diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 519e10e5a0a..2b27a94c624 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -15,6 +15,7 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { //multiple possible typeKeys this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; this.linkPromise = null; + this.hasData = false; }; Relationship.prototype = { @@ -230,7 +231,11 @@ Relationship.prototype = { }, notifyRecordRelationshipAdded: Ember.K, - notifyRecordRelationshipRemoved: Ember.K + notifyRecordRelationshipRemoved: Ember.K, + + setHasData: function() { + this.hasData = true; + } }; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b7c9c4a1178..f31f802f64a 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -331,6 +331,10 @@ Store = Service.extend({ // Set the properties specified on the record. record.setProperties(properties); + record.eachRelationship(function(key, descriptor) { + record._relationships[key].setHasData(true); + }); + return record; }, @@ -2059,13 +2063,13 @@ function setupRelationships(store, record, data) { relationship.updateLink(data.links[key]); } - if (kind === 'belongsTo') { - if (value === undefined) { - return; + if (value !== undefined) { + if (kind === 'belongsTo') { + relationship.setCanonicalRecord(value); + } else if (kind === 'hasMany') { + relationship.updateRecordsFromAdapter(value); } - relationship.setCanonicalRecord(value); - } else if (kind === 'hasMany' && value) { - relationship.updateRecordsFromAdapter(value); + relationship.setHasData(true); } }); } diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 67fdf112a79..a906968a355 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -1,4 +1,4 @@ -var env, store, User, Message, Post, Contact, Comment, Book, Author, NewMessage; +var env, store, User, Message, Post, Contact, Comment, Book, Chapter, Author, NewMessage; var get = Ember.get; var run = Ember.run; @@ -47,11 +47,18 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Book = DS.Model.extend({ name: attr('string'), - author: belongsTo('author') + author: belongsTo('author'), + chapters: hasMany('chapters') + }); + + Chapter = DS.Model.extend({ + title: attr('string'), + belongsTo: belongsTo('book') }); Author = DS.Model.extend({ - name: attr('string') + name: attr('string'), + books: hasMany('books') }); env = setupStore({ @@ -60,6 +67,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { comment: Comment, message: Message, book: Book, + chapter: Chapter, author: Author }); @@ -580,3 +588,95 @@ test("Passing a model as type to belongsTo should not work", function () { }); }, /The first argument to DS.belongsTo must be a string/); }); + +test("belongsTo hasData async loaded", function () { + expect(1); + + Book.reopen({ + author: belongsTo('author', { async: true }) + }); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); + }; + + run(function() { + store.find('book', 1).then(function(book) { + var relationship = book._relationships['author']; + equal(relationship.hasData, true, 'relationship has data'); + }); + }); +}); + +test("belongsTo hasData sync loaded", function () { + expect(1); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); + }; + + run(function() { + store.find('book', 1).then(function(book) { + var relationship = book._relationships['author']; + equal(relationship.hasData, true, 'relationship has data'); + }); + }); +}); + +test("belongsTo hasData async not loaded", function () { + expect(1); + + Book.reopen({ + author: belongsTo('author', { async: true }) + }); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', links: { author: 'author' } }); + }; + + run(function() { + store.find('book', 1).then(function(book) { + var relationship = book._relationships['author']; + equal(relationship.hasData, false, 'relationship does not have data'); + }); + }); +}); + +test("belongsTo hasData sync not loaded", function () { + expect(1); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book' }); + }; + + run(function() { + store.find('book', 1).then(function(book) { + var relationship = book._relationships['author']; + equal(relationship.hasData, false, 'relationship does not have data'); + }); + }); +}); + +test("belongsTo hasData async created", function () { + expect(1); + + Book.reopen({ + author: belongsTo('author', { async: true }) + }); + + run(function() { + var book = store.createRecord('book', { name: 'The Greatest Book' }); + var relationship = book._relationships['author']; + equal(relationship.hasData, true, 'relationship has data'); + }); +}); + +test("belongsTo hasData sync created", function () { + expect(1); + + run(function() { + var book = store.createRecord('book', { name: 'The Greatest Book' }); + var relationship = book._relationships['author']; + equal(relationship.hasData, true, 'relationship has data'); + }); +}); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 74b6b63a263..d61eacb5823 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1,4 +1,4 @@ -var env, User, Contact, Email, Phone, Message, Post, Comment; +var env, store, User, Contact, Email, Phone, Message, Post, Comment; var Book, Chapter, Page; var get = Ember.get; var resolve = Ember.RSVP.resolve; @@ -80,6 +80,8 @@ module("integration/relationships/has_many - Has-Many Relationships", { chapter: Chapter, page: Page }); + + store = env.store; }, teardown: function() { @@ -1312,3 +1314,95 @@ test("adding and removing records from hasMany relationship #2666", function() { }); }); }); + +test("hasMany hasData async loaded", function () { + expect(1); + + Chapter.reopen({ + pages: hasMany('pages', { async: true }) + }); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); + }; + + run(function() { + store.find('chapter', 1).then(function(chapter) { + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, true, 'relationship has data'); + }); + }); +}); + +test("hasMany hasData sync loaded", function () { + expect(1); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); + }; + + run(function() { + store.find('chapter', 1).then(function(chapter) { + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, true, 'relationship has data'); + }); + }); +}); + +test("hasMany hasData async not loaded", function () { + expect(1); + + Chapter.reopen({ + pages: hasMany('pages', { async: true }) + }); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', links: { pages: 'pages' } }); + }; + + run(function() { + store.find('chapter', 1).then(function(chapter) { + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, false, 'relationship does not have data'); + }); + }); +}); + +test("hasMany hasData sync not loaded", function () { + expect(1); + + env.adapter.find = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins' }); + }; + + run(function() { + store.find('chapter', 1).then(function(chapter) { + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, false, 'relationship does not have data'); + }); + }); +}); + +test("hasMany hasData async created", function () { + expect(1); + + Chapter.reopen({ + pages: hasMany('pages', { async: true }) + }); + + run(function() { + var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, true, 'relationship has data'); + }); +}); + +test("hasMany hasData sync created", function () { + expect(1); + + run(function() { + var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + var relationship = chapter._relationships['pages']; + equal(relationship.hasData, true, 'relationship has data'); + }); +});