Migrating to v3

Migration path to JSData 3.0.0

🚧

Attention

While JSData v3 tried to stay API-compatible with v2, it is a completely new codebase. This migration guide may be incomplete. If you think anything in this guide is incorrect or missing, please add it (via the Suggest Edits button) or open an issue.

See the CHANGELOG for a detailed list of changes.

When upgrading to JSData 3.0 be aware of the following:

JSData requires the presence of a Promise constructor in the global environment. In the browser, window.Promise must be available. In Node.js, global.Promise must be available. Here is a handy library for polyfilling: https://github.com/jakearchibald/es6-promise. Please check caniuse.com for browser Promise compatibility. Please check node.green for Node.js Promise compatibility.

JSData also requires full ES5 support from the runtime. Here is a handy library for polyfilling: https://github.com/afarkas/html5shiv. Please check kangax.github.io for browser ES5 compatibility. All supported versions of Node.js have full ES5 compatibility.

JSData has been completely re-architected for better flexibility and to allow you to compose and customize according to your needs.

Breaking changes

  • JSData.DS has been split into a number of different components with more focused responsibilities, so you can flexibly construct your app's data layer.
    • Added DataStore, SimpleStore, Container, Mapper, Record, Schema, and several others.
    • The Record class is for individual in-memory records that correspond to say, a row in your database.
    • The Mapper class encapsulates the ORM's CRUD logic. An instance of Mapper corresponds to say, a table in your database.
    • The Container class provides a convenient way to define and manage Mapper instances. Use this instead of managing Mapper instances manually.
    • The DataStore and SimpleStore classes extend Container, and implement an in-memory Identity Map for caching Record instances.
    • The Schema class helps implement validation and change detection.
    • Each class is "just a function", so you can extend them using ES5-style inheritance or ES6 class syntax (they also have a Backbone-style extend method that you can use).
  • The official v3 recommendation is that DataStore be used in the browser and Container be used in Node.js (DataStore adds a bunch of functionality that's generally not used on the server).
  • Use of Object.observe (and observe-js) has been dropped. Change detection has been re-implemented Backbone-style. Active change detection requires that you define a schema and set track to true. Passive change detection via Record#hasChanges, Record#changes, and Record#previous works without having to explicitly enable it.
  • All "reap" and expiration functionality has been removed. However, the increased flexibility of v3 allows you to easily add your own cache-busting expiration schemes.

Backwards compatible changes

  • Added support secondary indexes (via Mindex) on the in-memory collections that hold record instances. Allows for really fast querying on in-memory records.
  • Other classes that were added (not mentioned above) are Component, Settable, Collection, LinkedCollection and Query. You likely won't use them directly unless you're composing custom components or implementing plugins and derivative libraries.

Summary of usage differences

🚧

Attention

There may be differences not covered here. Consult the v3 API Reference Docs for detailed API reference of the new JSData components.

Create a store in the browser:

BeforeAfter
const store = new DS();const store = new DataStore();

Create a store in Node.js (while you can use DataStore on the server, you're better off using Container):

BeforeAfter
const store = new DS();const store = new Container();

Define a Model or Resource:

BeforeAfter
store.defineResource({ name: 'foo', // options go here });store.defineMapper('foo', { // options go here });

Use custom class for records:

BeforeAfter
function CustomRecord () {} store.defineResource({ name: 'foo', useClass: CustomRecord });const CustomRecord = Record.extend(); store.defineMapper('foo', { recordClass: CustomRecord });

or

class CustomRecord extends Record {} store.defineMapper('foo', { recordClass: CustomRecord });

Computed properties:

BeforeAfter
store.defineResource({ name: 'user', computed: { fullName: ['first', 'last', function (first, last) { return first + ' ' + last; }] } });See example - Open in Plnkr

Record saves/creates itself:

BeforeAfter
const userRecord = store.createInstance('user', { name: 'John' }); userRecord.DSCreate().then(...);const userRecord = store.createRecord('user', { name: 'John' }); userRecord.save().then(...);

Record saves/updates itself:

BeforeAfter
record.DSUpdate({ key: 'value' }).then(...);record.set({ key: 'value' }).save().then(...);

or

record.key = value; record.save().then(...);

Record destroys itself:

BeforeAfter
record.DSDestroy().then(...);record.destroy().then(...);

HTTP actions:

store.defineResource({ name: 'user', actions: { count: { method: 'POST' } } });See example - Open in Plnkr

Change detection:

BeforeAfter
In Angular, you might do:

$scope.$watch(() => DS.lastModified('lesson', 1234), () => { $scope.lesson = DS.get('lesson', 1234); });

In React, you might list for the DS.change event to trigger component re-renders.
See Tracking changes.

Validation:

Relations: