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.

 

Got something to say?
  1. cactuspants says:

    A simliar API was announced as part of one of the sessions in last year's Google I/O

    API: http://code.google.com/p/webstorageportabilityl
    Session: http://code.google.com/events/io/2009/sessions/

  2. Zef Hemel says:

    I'm aware of WSPL, of what I have seen from the API, it's only a thin abstraction layer on top of the different query interfaces, not really an ORM.

  3. plasticcard01 says:

    pvc cards pains to depict the poor treatment: PS Printing Down Collection Frequently Asked Questions (1) The over exposed Approach: to reduce exposure or to select the best exposure time (with Printing Down gray ladder feet,pvc cards section to achieve the best exposure time). (2) In most cases,pvc cards development time is too long, DEVELOPER DEVELOPER concentration or pvc cards is too high will lead to graphic part of a small amount of light-sensitive layer was dissolved, resulting in loss of 2% of small outlets.pvc cards PS version of the thickness of the photo sensitive layer is only about 1.5μm, by weight, a maximum of approximately 2.5g/m2 (version thickness 0.28mm). pvc cards

  4. Karel says:

    Hi Zef,

    This is a great effort! I was reviewing your code, to see if it is already robust enough to use. It looked pretty sound, but a detail caught my attention: Although conflicts will be rare, don't you think using a random number for an Entity-id is strictly spoken unsafe? (As in createUUID() ).

  5. Zef Hemel says:

    Yes, strictly taken it's unsafe. Although odds of collision are extremely rare, sadly it's not really possible to generate truly globally unique ids from Javascript.

  6. Ege says:

    Can’t you use timestamps?

  7. zeeshanr says:

    Thanks for wonderfull wrapper; How can I mark any field as primary key; I got id as primary key by default, but what if I want int_my_primary_field to be my primary key.

  8. Zef Hemel says:

    No, currently you can not define what field to use as primary key. It has to be ‘id’.

  9. Juzer Ali says:

    I agree, timestamps can be thought of being fairly unique. Also, to be safer we can use combination of a random number and a timestamp like: var key = new Date().getTime()+Math.random();

Trackbacks for this post

  1. InVisible Blog » links for 2010-02-06
  2. Full-Text Search in persistence.js « I am Zef
  3. The Past, Present & Future of Local Storage for Web Applications | ItPak.net
  4. Integra un ORM con Javascript y WebSQL | aNieto2K
  5. Changing the World, One Paper at a Time « I am Zef
  6. An HTML5 Web Storage Round-Up - WebsitesMadeRight.com
  7. HTML5 Web Storage Tutorials and Resources - WebsitesMadeRight.com
  8. Which JavaScript ORM to use?

Comments are closed now.