Skip to content

Commit

Permalink
feat: Add a hoodie DS.Store and DS.Adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
courajs committed May 31, 2016
1 parent dcd0c2c commit d5a9718
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 0 deletions.
73 changes: 73 additions & 0 deletions addon/adapters/hoodie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import DS from 'ember-data';
import Ember from 'ember';

const {
inject: { service }
} = Ember;

export default DS.Adapter.extend({
hoodie: service(),

init() {
this._super(...arguments);
this._queue = Ember.RSVP.resolve();
},

findRecord(store, type, id) {
return this._next(() => {
return this._storeForType(type).find(id);
});
},

createRecord(store, type, snapshot) {
var props = this.serialize(snapshot);
return this._next(() => {
return this._storeForType(type).add(props);
});
},

updateRecord(store, type, snapshot) {
var props = this.serialize(snapshot);
return this._next(() => {
return this._storeForType(type).update(snapshot.id, props);
});
},

// because hoodie/pouchdb uses UUIDs, we don't actually need
// a scoped store for the delete.
// Also, scoped remove is a little buggy
// https://github.com/hoodiehq/hoodie-store-client/issues/104
deleteRecord(store, type, snapshot) {
return this._next(() => {
return this.get('hoodie.store').remove(snapshot.id);
});
},

findAll(store, type) {
return this._next(() => {
return this._storeForType(type).findAll();
});
},

query() {
throw new Error('not implemented');
},

_storeForType(type) {
return this.get('hoodie.store')(type.modelName);
},

// This is used to synchronize and single-file hoodie operations.
// It helps in situations like:
// When creating a record. If you find that record with findAll before
// the create promise resolves, you end up two records in the store for
// the same hoodie model. They have the same type, id, and attributes,
// there are just two of them in the store
//
// This shouldn't be too bad of a workaround, as these operations are actually very quick.
// They're not doing server round trips, they're only talking to an in-memory
// pouchdb store.
_next(f) {
return this._queue = this._queue.catch(function(){}).then(f);
}
});
42 changes: 42 additions & 0 deletions addon/services/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import DS from 'ember-data';
import Ember from 'ember';

const {
get,
inject: { service }
} = Ember;

export default DS.Store.extend({
hoodie: service(),
adapter: 'hoodie',

init() {
this._super(...arguments);

let update = (obj) => {
let data = this.normalize('card', obj);
// HACK: ugh... these change events were coming through
// before the promise was resolving in the adapter. This
// means the record was still in flight when we attempted
// this push. Somehow we were ending up with two records
// in the store with the same id. I think this is an ED
// bug, but this works around it for now.
Ember.run.next(this, function(){
Ember.run.next(this, function(){
this.push(data);
});
});
};

let remove = (obj) => {
let record = this.peekRecord('card', obj.id);
if (!get(record, 'isDeleted')) {
record.unloadRecord();
}
};

this.get('hoodie.store').on('add', update);
this.get('hoodie.store').on('update', update);
this.get('hoodie.store').on('remove', remove);
}
});
3 changes: 3 additions & 0 deletions app/adapters/hoodie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import HoodieAdapter from 'ember-hoodie/adapters/hoodie';

export default HoodieAdapter;

0 comments on commit d5a9718

Please sign in to comment.