Immunid — Opinionated Data Storage
- Robust relational data handling
- Absolutely no view layer
- Modularize via CommonJS
- No reliance on jQuery for ajax
- No reliance on Underscore or lodash for functions
- Promises, not callbacks
- Emphasis on mixins
Installation
Immunid is distributed with npm and can be imported as CommonJS modules.
npm install immunid --save
Retrieving Data
All models must be created or retrieved through the store. The store is what
allows relational behavior, caching, and identity mapping. It is strictly
possible to create a new instance of a model directly, but it will not be able
to retrieve any associations.
var Post = Model.extend({
path: function() {
return '/posts';
}
});
var adapter = new Adapter({
headers: { 'Content-Type': 'application/json' },
host: '/api'
});
var store = new Store(adapter, {
'Post': Post
});
store.find('posts', 1).then(function(post) {
});
All data returned from the GET
request to /posts/1
will be parsed into the
appropriate location within the store and wrapped in a corresponding model
object. This allows the Post
to synchronously retrieve associated data. This
mechanism relies on embedded ids within the parent record:
post.get('comment_ids');
post.comments().all();
The path used for a particular model or relation can be customized within the
model itself. There is no basePath
or automatic id appending.
var Comment = Model.extend({
path: function(post) {
return '/post/' + post.id + '/comments';
}
});
Persisting Records
Records instantiated through the store expose some simple persistence methods.
model.save();
model.reload();
model.destroy();
Persisting models with associations does not create, update, or destroy any of
the associated models.
Adding and Removing Records without Persistence
Records can be added to or removed from the store without making a call to
#find
or #destroy
:
var store = new Store(adapter, {
'Post': Post
});
var post = store.add('posts', { id: 42, body: 'Lorem ipsum' });
store.remove(post);
Calling #add
with new attributes for a model that already exists updates the
existing model attributes instead of overwriting them:
store.add('posts', { id: 42, body: 'Lorem ipsum' });
store.add('posts', { id: 42, group: 'beta' });
var post = store.get('posts', 42);
post.get('body');
post.get('group');
During testing or in certain production situations you may want clear all, or
part of the store. For that, there is clear
:
store.clear('posts');
store.clear();
Clearing is only a local operation and doesn't make any external requests.
Relating Records
- There is no
belongsTo
relation. Only hasOne
or hasMany
currently. - Relation names are always singular.
var Project = Model.extend({
account: Relation.hasOne('account'),
missions: Relation.hasMany('mission'),
screeners: Relation.hasMany('screener'),
memberships: Relation.hasMany('membership')
});
project.account().get();
project.memberships().all();
Events
The store emits events under namespaces when model instances are changed.
Event names are always past tense to indicate the model is ready for use:
var adapter = new Adapter();
var Tag = Model.extend({});
var store = new Store(adapter, { Tag: Tag });
function handleChangeTag(tag) {
}
var myTag = store.get('tags', 42).then(function(tag) {
store.on('tags:changed', handleChangeTag);
});
myTag.set({ name: 'banana' });
myTag.unset('name');
myTag.clear();
store.off('tags:changed', handleChangeTag);
Set the event handler's this
value with the third argument to on
:
var context = { model: null };
store.on('model:changed', handleChange, context);
function handleChange(model) {
this.model = model;
}
There are a few ways to unsubscribe event handlers:
store.off('tags:changed', handleChange);
store.off('tags:changed', null, null);
store.off('tags', null, null);
The store also emits events when parsing a response from the server:
store.find('tags');
store.find('tags', 42);
var tag = store.build('tags', { name: 'apple' });
tag.save();
tag.reload();
tag.set({ name: 'banana' }).save();
tag.destroy();
The payload for fetched
, created
, reloaded
, and updated
events will be
an array of one or more models. The payload for destroyed
events will be a
single model.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
License
Released under the MIT license. See LICENSE for details.