persistence.js: An Asynchronous Javascript ORM for HTML5/Gears

The past week or two I have been developing an asynchronous object-relational mapper in Javascript, called persistence.js. Its main use-case, right now, is to simplify the database component of offline-capable web applications, like the mobile web applications that I’m working on. But with some tweaking it should also be usable in server-side applications, like node.js servers. It uses the SQLite database that is available in modern Webkit-based browsers (like Safari 4 and Google Chrome), or the Google Gears datastore that is available in any browser that runs the Google Gears browser extension (like Firefox). It also runs on iPhone (OS 3+) and Android browsers. In its current state it does not run on IE (although I haven’t tested it).

There is one other asynchronous Javascript ORM framework that I know of (Impel), but it has a dependency on MooTools, which would be yet another framework you need to pull into your web application. persistence.js has no dependency on any Javascript framework (other than a tiny Google Gears initialization script in case you want to use Gears).

persistence.js is an asynchronous framework, which means that operations that can take some time, are provided with a callback function that will be invoked when the operation has completed. This asynchronous nature makes persistence.js harder to use than synchronous frameworks like e.g. ActiveRecord.js, but the fact is that if you want to take advantage of the new HTML5 database capabilities, you have no other choice than to do it asynchronously. persistence.js tries to make it as easy for you as possible.

The code is fairly well documented (for my doing anyway), and the README explains how to use it and gives some code examples as well. To give you flavor, the following code opens a database connection, defines two entities (Task and Category), and synchronizes the definition with the database (creates the tables etc.):

persistence.connect('testdbnm', 'My test db', 5 * 1024 * 1024); var Task = persistence.define('Task', {     name: "TEXT",     description: "TEXT",     done: "BOOL" }); var Category = persistence.define('Category', {     name: "TEXT" }); Category.hasMany('tasks', Task, 'category'); persistence.schemaSync(null, function(tx) {   alert('Successfully synchronized the schema!'); });

Instances of the defined entities can then be created in a natural way, and subsequently marked to be persisted:

var task = new Task(); task.name = "My new task"; var category =     new Category({name: "My category"}); persistence.add(task); persistence.add(category);

One-to-many and many-to-many relationships can be used as collections:

category.tasks.add(task);

When modifications to objects have been made, these have to be flushed to the database:

persistence.flush(null, function() {   alert('All objects flushed!'); });

A nice feature of persistence.js is QueryCollections, which are virtual collections that can prefetch relations, can easily be filtered and sorted (and in the future paginated): 

Task.all().filter("done", '=', true)           .prefetch("category")          .order("name", false)           .list(null, function (results) {     results.forEach(function (t) {         console.log('[' + t.category.name + '] '                     + t.name);     }); });

In the future I intend to add synchronization support to it so that the local database can transparently be synchronized with a (view on) a remote database, which is a typical use case of applications like these.