Permalink
Browse files

Add has-many support for BasicAdapter

  • Loading branch information...
tomhuda
tomhuda committed Mar 11, 2013
1 parent bc720dc commit 81e6fdeef02e909c90b88da93d94c5cab7625baf
@@ -1,5 +1,7 @@
var camelize = Ember.String.camelize,
+ capitalize = Ember.String.capitalize,
get = Ember.get,
+ map = Ember.ArrayPolyfills.map,
registeredTransforms;
var passthruTransform = {
@@ -125,6 +127,30 @@ function arrayProcessorFactory(store, type, array) {
};
}
+var HasManyProcessor = function(json, store, record, relationship) {
+ this.json = json;
+ this.store = store;
+ this.record = record;
+ this.type = record.constructor;
+ this.relationship = relationship;
+};
+
+HasManyProcessor.prototype = Ember.create(ArrayProcessor.prototype);
+
+HasManyProcessor.prototype.load = function() {
+ var store = this.store;
+ var ids = map.call(this.json, function(obj) { return obj.id; });
+
+ store.loadMany(this.relationship.type, this.json);
+ store.loadHasMany(this.record, this.relationship.key, ids);
+};
+
+function hasManyProcessorFactory(store, record, relationship) {
+ return function(json) {
+ return new HasManyProcessor(json, store, record, relationship);
+ };
+}
+
DS.BasicAdapter = DS.Adapter.extend({
find: function(store, type, id) {
var sync = type.sync;
@@ -142,6 +168,20 @@ DS.BasicAdapter = DS.Adapter.extend({
Ember.assert("The sync code on " + type + " does not implement query(), but you are trying to query " + type + ".", sync.query);
sync.query(query, arrayProcessorFactory(store, type, recordArray));
+ },
+
+ findHasMany: function(store, record, relationship, any) {
+ var name = capitalize(relationship.key),
+ sync = record.constructor.sync,
+ processor = hasManyProcessorFactory(store, record, relationship);
+
+ if (sync['find'+name]) {
+ sync['find' + name](record, processor);
+ } else if (sync.findHasMany) {
+ sync.findHasMany(record, relationship.key, processor);
+ } else {
+ Ember.assert("You are trying to use the BasicAdapter to find the " + relationship.key + " has-many relationship, but " + record.constructor + ".sync did not implement findHasMany or find" + name + ".", false);
+ }
}
});
@@ -17,7 +17,7 @@ var hasRelationship = function(type, options) {
}
ids = data[key];
- relationship = store.findMany(type, ids || [], this, meta);
+ relationship = store.findMany(type, ids, this, meta);
set(relationship, 'owner', this);
set(relationship, 'name', key);
@@ -676,7 +676,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
if (!Ember.isArray(ids)) {
var adapter = this.adapterForType(type);
if (adapter && adapter.findHasMany) { adapter.findHasMany(this, record, relationship, ids); }
- else { throw fmt("Adapter is either null or does not implement `findHasMany` method", this); }
+ else if (ids !== undefined) { throw fmt("Adapter is either null or does not implement `findHasMany` method", this); }
return this.createManyArray(type, Ember.A());
}
@@ -1602,7 +1602,10 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
// TODO (tomdale) this assumes that loadHasMany *always* means
// that the records for the provided IDs are loaded.
- if (relationship) { set(relationship, 'isLoaded', true); }
+ if (relationship) {
+ set(relationship, 'isLoaded', true);
+ relationship.trigger('didLoad');
+ }
},
/** @private
@@ -1,20 +1,30 @@
var get = Ember.get;
-var store, adapter, Person;
+var store, adapter, Person, PhoneNumber;
module("Basic Adapter", {
setup: function() {
adapter = DS.BasicAdapter.create();
store = DS.Store.create({
adapter: adapter
});
- var attr = DS.attr;
+ var attr = DS.attr, hasMany = DS.hasMany, belongsTo = DS.belongsTo;
Person = DS.Model.extend({
firstName: attr('string'),
lastName: attr('string'),
createdAt: attr('date')
});
+ PhoneNumber = DS.Model.extend({
+ areaCode: attr('number'),
+ number: attr('number'),
+ person: belongsTo(Person)
+ });
+
+ Person.reopen({
+ phoneNumbers: hasMany(PhoneNumber)
+ });
+
DS.registerTransforms('test', {
date: {
serialize: function(value) {
@@ -200,3 +210,56 @@ test("A query's processor supports munge across all elements in its Array", func
});
});
+test("A basic adapter receives a call to find<Relationship> for relationships", function() {
+ expect(3);
+
+ Person.sync = {
+ find: function(id, process) {
+ setTimeout(async(function() {
+ process({ id: 1, firstName: "Tom", lastName: "Dale" }).load();
+ }));
+ },
+
+ findPhoneNumbers: function(person, process) {
+ setTimeout(async(function() {
+ process([ { id: 1, areaCode: 703, number: 1234567 }, { id: 2, areaCode: 904, number: 9543256 } ]).load();
+ }));
+ }
+ };
+
+ Person.find(1).then(function(person) {
+ return person.get('phoneNumbers');
+ }).then(async(function(phoneNumbers) {
+ equal(phoneNumbers.get('length'), 2, "There are now two phone numbers");
+ equal(phoneNumbers.objectAt(0).get('number'), 1234567, "The first phone number was loaded in");
+ equal(phoneNumbers.objectAt(1).get('number'), 9543256, "The second phone number was loaded in");
+ }));
+});
+
+test("A basic adapter receives a call to find<Relationship> for relationships", function() {
+ expect(4);
+
+ Person.sync = {
+ find: function(id, process) {
+ setTimeout(async(function() {
+ process({ id: 1, firstName: "Tom", lastName: "Dale" }).load();
+ }));
+ },
+
+ findHasMany: function(person, relationship, process) {
+ equal(relationship, 'phoneNumbers');
+ setTimeout(async(function() {
+ process([ { id: 1, areaCode: 703, number: 1234567 }, { id: 2, areaCode: 904, number: 9543256 } ]).load();
+ }));
+ }
+ };
+
+ Person.find(1).then(function(person) {
+ return person.get('phoneNumbers');
+ }).then(async(function(phoneNumbers) {
+ equal(phoneNumbers.get('length'), 2, "There are now two phone numbers");
+ equal(phoneNumbers.objectAt(0).get('number'), 1234567, "The first phone number was loaded in");
+ equal(phoneNumbers.objectAt(1).get('number'), 9543256, "The second phone number was loaded in");
+ }));
+});
+

0 comments on commit 81e6fde

Please sign in to comment.