JayData is a unified data access layer for JavaScript developers.
JayData provides a common coding experience over a number of different data APIs like WebSQL, IndexedDB or OData. With a single API to master you can spare a lot of time and code on local and online data management. On the other hand JayData lets you to connect data to some popular UI libraries like KnockoutJS, Handlebars or Kendo UI. More then just the client side: with JayData and NodeJS you can even create your own data service solely using JavaScript coding skills.
How to start with offline databases
JayData is available as a download or can be used from our CDN. In order for all features to be present you’ll need jQuery and JayData included in your HTML5 App or web page.
1 2 3 |
<span class="kwrd"><</span><span class="html">script</span> <span class="attr">src</span><span class="kwrd">="http://code.jquery.com/jquery-1.8.2.min.js"</span><span class="kwrd">></</span><span class="html">script</span><span class="kwrd">></span> </code><code class="language-javascript"> <span class="kwrd"><</span><span class="html">script</span> <span class="attr">src</span><span class="kwrd">="http://include.jaydata.org/jaydata.js"</span><span class="kwrd">></</span><span class="html">script</span><span class="kwrd">></span> |
Create your first model type ( = table)
Before you could save or get it back, first you have to define the structure of your data. This definition, otherwise called the model, is created with the $data.define method, that takes a model name and a model definition and returns a JavaScript type ( = constructor).
1 2 3 4 5 6 7 |
<span class="kwrd">var</span> Task = <strong>$data.define</strong>(<span class="str">"Task"</span>, { Todo: String, Completed: Boolean, </code><code class="language-javascript"> Priority: Number, </code><code class="language-javascript"> DueDate: Date }); |
Save a new task item
In JayData every model definition has a default store configured, based on the device capabilities this will be WebSQL, IndexedDB or localStore. To utilize this store is a simple thing: use the Task type as a façade to store items of that type.
1 2 3 4 5 6 7 |
Task.<strong>save</strong>({ Todo: <span class="str">"Include script resources"</span>, Completed: <span class="kwrd">false</span>, Priority: 1, </code><code class="language-javascript"> DueDate: new Date() }); |
That’s all to it. Here is the combined code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<span class="kwrd"><</span><span class="html">html</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">head</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">script</span> <span class="attr">src</span><span class="kwrd">="http://code.jquery.com/jquery-1.8.2.min.js"</span><span class="kwrd">></</span><span class="html">script</span><span class="kwrd">></span> <script src=<span class="str">"http://include.jaydata.org/jaydata.js"</span>></script> </head> <body> <script> <span class="kwrd">var</span> Task = $data.define(<span class="str">"Task"</span>, { Todo: String, Completed: Boolean, Priority: Number, DueDate: Date }); Task.save({ Todo: <span class="str">"Include script resources"</span>, Completed: <span class="kwrd">false</span>, Priority: 1, DueDate: <span class="kwrd">new</span> Date() }); <span class="kwrd"></</span><span class="html">script</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">body</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">html</span><span class="kwrd">></span> |
Place it in an HTML page an load with the browser. Since Google Chrome has the easiest way to check databases I suggest using that. Press F12 and on the Resources tab you’ll see what happened in the background.
JayData has created the necessary store (it defaults to WebSQL where available) and persisted our object. Had our environment only support IndexedDB we would have had an objectStore created for us. Read on to see how to force IndexedDB (or eventually OData) to be the default store.
Get all items from the store
Now that we have stored it, it is time to get our data back – we can close our browser (or app), and the next time we reopen it our data will be there waiting for us. The simplest way to get all stored items of a given model class is type.readAll().
1 2 3 4 5 |
<strong>Task.readAll().</strong>then(<span class="kwrd">function</span>(taskArray) { taskArray.forEach(<span class="kwrd">function</span>(task) { $(<span class="str">'#output'</span>).append(JSON.stringify(task) + <span class="str">"<br />"</span>) }); }); |
Beware: it is all the way async!
Storing and reading data in HTML5 are async operations by their nature. Such methods that encapsulate async functionality will return a promise in JayData (either jQuery.Deferred or Q depending on the module you use). You have to call then() and fail() on these promises so that you can get the async result or to wait for it to finish before your code proceeds. Read more on working with promises here.
To have the readAll() operation happen after the save() operation finished you can chain them in a then() chain.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Task.save({ Todo: <span class="str">"Include script resources"</span>, Completed: <span class="kwrd">false</span>, Priority: 1, DueDate: <span class="kwrd">new</span> Date() }) </code><code class="language-javascript"> .then(<span class="kwrd">function</span>(newTask) { Task.readAll() </code><code class="language-javascript"> .then(<span class="kwrd">function</span>(taskArray) { taskArray.forEach(<span class="kwrd">function</span>(task) { $(<span class="str">'#output'</span>).append(JSON.stringify(task) + <span class="str">"<br />"</span>) }); }); }); |
Review this jsFiddle to see how it executes. http://jsfiddle.net/JayData/UBR6e/
You might have noticed that even if you haven’t specified an Id field one is present any way. This is because JayData needs a unique identifier for every entity and if you don’t specify a key field JayData automatically appends one for you. You can override this behavior by manually defining a key field. Refer to Defining types in JayData to see how.
Retrieving specific items, query
To get an item back based on it unique key field use the type.read() method.
1 2 3 |
Task.<strong>read</strong>(1).then(<span class="kwrd">function</span> (task) { </code><code class="language-javascript"> //work with task here }); |
To retrieve items based on a criteria you can use the query() method. This accepts two parameters: a query predicate and an optional param object to support parametric queries. The query predicate is a simple filter statement expressed as a JavaScript bool expression or function.
The query for expired unfinished tasks looks like as follows.
1 2 3 4 |
Task.query(<span class="str">"it.Completed == false && it.DueDate < now"</span>, { now: <span class="kwrd">new</span> Date() }) .then(<span class="kwrd">function</span> () { console.dir(arguments); }); |
As an alternative you can write a full JavaScript function. Use the this keyword to reference the parameter object.
1 2 3 4 |
<span class="kwrd">var</span> thisArg = { date: <span class="kwrd">new</span> Date() }; Task.query(<span class="kwrd">function</span> (it) { </code><code class="language-javascript"> <span class="kwrd">return</span> it.Completed == <span class="kwrd">false</span> && it.DueDate < <span class="kwrd">this</span>.date }, thisArg).then(...) |
Albeit the assumption is trivial, yet filter predicates are NOT executed by the client on an in-memory object array. Predicates are translated to SQL statements or IndexedDB cursor operations or OData network calls to return just the correct number of items. You can handle several hundred thousand records on a phone this way.
Removing items
1 2 3 4 |
Task.read(1).then(<span class="kwrd">function</span> (task) { task.remove(); }); |
To be continued