Entity relationship magic for AngularJS and PouchDB.
Well it's simple, you just:
- Create a local PouchDB database
- Define your model (collections + relationships) using Sneaker's simple API.
SneakerJS will then:
- Load the collections in memory and bi-directionally map the relationships for super fast querying.
- Generate intelligently named functions to work with your collections and relationships.
What this means is:
-
You can write concise, readable code using your domain language.
-
You can query collections and relationships directly in your views (no need for services or controllers) and it will all be lightening fast.
-
Changes will be automatically saved to your local database (and optionally synchronized with a remote CouchDB) and will update your views without you having to call $digest() or $apply() and this will be lightening fast too.
-
You have just saved yourself a lot of boilerplate code to achieve the same result.
To understand the full awesomness, and how much typing this saves you, it is best to study a small example.
Consider a blog platform with posts, comments, and tags. All you need to do is:
- Create the PouchDB
- Define our collections (posts, comments, and tags) and fields
- Define the relationships between the collections
- Save your model as db on $rootScope (optional, just for convenience)
var app = angular.module('app', ['SneakerJS']);
app.run(function(SneakerModel, $rootScope) {
var database = new PouchDB('my_local_database');
var db = new SneakerModel(database);
db.collection('post', ['title', 'datetime', 'text']);
db.collection('comment', ['datetime', 'text']);
db.collection('tag', ['name']);
db.oneToMany('post', 'comment');
db.manyToMany('post', 'tag');
db.dataReady().then(function() {
$rootScope.db = db;
});
});
You can then write template code using the intelligently generated functions:
<div ng-app="app">
<div ng-repeat="post in db.allPosts()">
<h3>{{post.title}}</h3>
This post has {{db.getPostComments(post).length}} comments.<br/>
<h5>Tags:</h5>
<span ng-repeat="tag in db.getPostTags(post)">{{tag.name}}</span>
</div>
</div>
A few notes:
- The functions allPosts(), getPostComments() and getPostTags() were all generated by SneakerJS according to the names of your collections (but you can override these).
- Query functions return actual objects and arrays, not promises (otherwise this code would not be possible).
- These queries are super fast, as each parent-child relationship is cached bi-directionally in memory (in deeply nested cases this can be over 100x faster than map-reduce!)
- Did you notice we didn't even need a controller or service for this page?
- SneakerJS will also generate newPost(), addPostTag(), removePostTag() etc... (note: functions which modify data return promises)
- Because it's PouchDB, you can synchronise your local db with a remote CouchDB with a single line of code.
- Passing a mock PouchDB object to route calls to your API instead of the local database is trivial.
- You can specify a prototype object for a collection (every item will get instantiated to it) allowing for powerful behaviour.
- If you do
SneakerModel.call(this, database)
inside a service instead of inapp.run()
then the generated functions will be attached to that service, which some might prefer. - You can override the generated functions (e.g. you might want newPost() to do some additional stuff)
- You can define various relationships like one-to-many, many-to-many (without having to create an intermediate collection) and also singleton objects instead of collections (e.g. for user settings)
- You can have multiple relationships between the same two collections using different qualifiers, e.g. setPostUserAsAuthor() and setPostUserAsReviewer().
Here is a simple Plunkr. There is also a demo project included.
npm install sneakerjs --save
Yes, there is a complete [User Guide](User Guide.md)!
Please report any issues in the issue tracker.
Tests are written in Jasmine, run with Karma, and code coverage checked with Istanbul.
npm test
Tests currently use karma-nicer-reporter.