Skip to content

Commit

Permalink
Add meta for hasMany relationships
Browse files Browse the repository at this point in the history
Rebased #2878 and added a test from #2996
Added metadata support behind a feature flag, for hasMany relationships.
For now, until we refactor the internals, the store internally pushes hasMany
metadata around in the `meta` key next to `links` and `data`.
This might lead to overriding meta attribtues with meta relationships,
but will be solved by the upcoming change of the internals to JSONAPI format
  • Loading branch information
igorT committed Jun 9, 2015
1 parent 905a8c4 commit 1647c65
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 30 deletions.
22 changes: 13 additions & 9 deletions packages/ember-data/lib/system/relationships/state/has-many.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { PromiseManyArray } from "ember-data/system/promise-proxies";
import Relationship from "ember-data/system/relationships/state/relationship";
import OrderedSet from "ember-data/system/ordered-set";
import ManyArray from "ember-data/system/many-array";
import cloneNull from "ember-data/system/clone-null";

var map = Ember.EnumerableUtils.map;

Expand All @@ -29,6 +28,12 @@ ManyRelationship.prototype.destroy = function() {
this.manyArray.destroy();
};

ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta;
ManyRelationship.prototype.updateMeta = function(meta) {
this._super$updateMeta(meta);
this.manyArray.set('meta', meta);
};

ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord;
ManyRelationship.prototype.addCanonicalRecord = function(record, idx) {
if (this.canonicalMembers.has(record)) {
Expand Down Expand Up @@ -145,15 +150,14 @@ ManyRelationship.prototype.computeChanges = function(records) {
};

ManyRelationship.prototype.fetchLink = function() {
var self = this;
return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records) {
var meta = self.store.metadataFor(self.relationshipMeta.type);
self.manyArray.set('meta', cloneNull(meta));

self.store._backburner.join(function() {
self.updateRecordsFromAdapter(records);
return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => {
if (records.hasOwnProperty('meta')) {
this.updateMeta(records.meta);
}
this.store._backburner.join(() => {
this.updateRecordsFromAdapter(records);
});
return self.manyArray;
return this.manyArray;
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function Relationship(store, record, inverseKey, relationshipMeta) {
//multiple possible modelNames
this.inverseKeyForImplicit = this.record.constructor.modelName + this.key;
this.linkPromise = null;
this.meta = null;
this.hasData = false;
}

Expand All @@ -23,6 +24,10 @@ Relationship.prototype = {

destroy: Ember.K,

updateMeta: function(meta) {
this.meta = meta;
},

clear: function() {
var members = this.members.list;
var member;
Expand Down
5 changes: 5 additions & 0 deletions packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2148,6 +2148,11 @@ function setupRelationships(store, record, data) {
relationship.updateLink(data.links[key]);
}

if (data.meta && data.meta.hasOwnProperty(key)) {
relationship = record._relationships.get(key);
relationship.updateMeta(data.meta[key]);
}

if (value !== undefined) {
if (kind === 'belongsTo') {
relationship = record._relationships.get(key);
Expand Down
6 changes: 5 additions & 1 deletion packages/ember-data/lib/system/store/finders.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ export function _findHasMany(adapter, store, internalModel, link, relationship)
var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany');
//TODO Use a non record creating push
var records = pushPayload(store, payload);
return map(records, function(record) { return record._internalModel; });
var recordArray = map(records, function(record) { return record._internalModel; });
if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && serializer.get('isNewSerializerAPI')) {
recordArray.meta = payload.meta;
}
return recordArray;
});
}, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type);
}
Expand Down
107 changes: 87 additions & 20 deletions packages/ember-data/tests/integration/relationships/has-many-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1443,33 +1443,100 @@ test("Model's belongsTo relationship should be created during 'get' method", fun
user = env.store.createRecord('user');
user.get('messages');
ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships");
});
});

test("metadata is accessible", function() {
expect(1);
if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) {

env.adapter.findHasMany = function() {
return resolve({
meta: {
foo: 'bar'
},
chapters: [
{ id: '2' },
{ id: '3' }
]
test("metadata is accessible when pushed as a meta property for a relationship", function() {
expect(1);
var book;
env.adapter.findHasMany = function() {
return resolve({});
};

run(function() {
book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', meta: { chapters: 'the lefkada sea' }, links: { chapters: '/chapters' } });
});
};

var book;
run(function() {
equal(book._internalModel._relationships.get('chapters').meta, 'the lefkada sea', 'meta is there');
});
});

run(function() {
book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } });
test("metadata is accessible when return from a fetchLink", function() {
expect(1);
env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true }));

env.adapter.findHasMany = function() {
return resolve({
meta: {
foo: 'bar'
},
chapters: [
{ id: '2' },
{ id: '3' }
]
});
};

var book;

run(function() {
book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } });
});

run(function() {
book.get('chapters').then(function(chapters) {
var meta = chapters.get('meta');
equal(get(meta, 'foo'), 'bar', 'metadata is available');
});
});
});

run(function() {
book.get('chapters').then(function(chapters) {
var meta = chapters.get('meta');
equal(get(meta, 'foo'), 'bar', 'metadata is available');
test("metadata should be reset between requests", function() {
var counter = 0;
env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true }));

env.adapter.findHasMany = function() {
var data = {
meta: {
foo: 'bar'
},
chapters: [
{ id: '2' },
{ id: '3' }
]
};

ok(true, 'findHasMany should be called twice');

if (counter === 1) {
delete data.meta;
}

counter++;

return resolve(data);
};

var book1, book2;

run(function() {
book1 = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: 'chapters' } });
book2 = env.store.push('book', { id: 2, title: 'Another book title', links: { chapters: 'chapters' } });
});

run(function() {
book1.get('chapters').then(function(chapters) {
var meta = chapters.get('meta');
equal(get(meta, 'foo'), 'bar', 'metadata should available');

book2.get('chapters').then(function(chapters) {
var meta = chapters.get('meta');
equal(meta, undefined, 'metadata should not be available');
});
});
});
});
});
}

0 comments on commit 1647c65

Please sign in to comment.