From 2ff2107e246b3cb56dcdad09b99794d9599e349f Mon Sep 17 00:00:00 2001 From: tchak Date: Thu, 20 Oct 2016 01:29:15 +0300 Subject: [PATCH] make DS.ManyArray lazy --- addon/-private/system/many-array.js | 8 +- addon/-private/system/references/has-many.js | 16 ++-- .../system/relationships/state/has-many.js | 82 +++++++++++-------- .../integration/adapter/rest-adapter-test.js | 12 ++- tests/integration/record-array-test.js | 13 ++- tests/integration/references/has-many-test.js | 10 ++- .../relationships/has-many-test.js | 3 +- .../inverse-relationships-test.js | 24 ++---- .../relationships/many-to-many-test.js | 22 +++-- .../relationships/one-to-many-test.js | 31 +++++-- tests/integration/store-test.js | 4 +- tests/unit/many-array-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 29 ++++++- 13 files changed, 163 insertions(+), 95 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 56827f6c783..d3724a34f35 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -56,6 +56,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init() { this._super(...arguments); this.currentState = Ember.A([]); + this.flushCanonical(); }, record: null, @@ -74,19 +75,18 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, flushCanonical() { - //TODO make this smarter, currently its plenty stupid - var toSet = this.canonicalState.filter((internalModel) => !internalModel.isDeleted()); + let toSet = this.canonicalState; //a hack for not removing new records //TODO remove once we have proper diffing - var newRecords = this.currentState.filter( + let newRecords = this.currentState.filter( // only add new records which are not yet in the canonical state of this // relationship (a new record can be in the canonical state if it has // been 'acknowleged' to be in the relationship via a store.push) (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); toSet = toSet.concat(newRecords); - var oldLength = this.length; + let oldLength = this.length; this.arrayContentWillChange(0, this.length, toSet.length); // It’s possible the parent side of the relationship may have been unloaded by this point if (_objectIsAlive(this)) { diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 8efc18fd6d1..4235e93673e 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -8,7 +8,10 @@ import { import isEnabled from 'ember-data/-private/features'; -const get = Ember.get; +const { + RSVP: { resolve }, + get +} = Ember; var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { this._super$constructor(store, parentInternalModel); @@ -45,11 +48,11 @@ HasManyReference.prototype.ids = function() { }; HasManyReference.prototype.meta = function() { - return this.hasManyRelationship.manyArray.meta; + return this.hasManyRelationship.meta; }; HasManyReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((payload) => { + return resolve(objectOrPromise).then((payload) => { var array = payload; if (isEnabled("ds-overhaul-references")) { @@ -102,7 +105,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { this.hasManyRelationship.computeChanges(internalModels); - return this.hasManyRelationship.manyArray; + return this.hasManyRelationship.getManyArray(); }); }; @@ -122,7 +125,7 @@ HasManyReference.prototype._isLoaded = function() { HasManyReference.prototype.value = function() { if (this._isLoaded()) { - return this.hasManyRelationship.manyArray; + return this.hasManyRelationship.getManyArray(); } return null; @@ -133,8 +136,7 @@ HasManyReference.prototype.load = function() { return this.hasManyRelationship.getRecords(); } - var manyArray = this.hasManyRelationship.manyArray; - return Ember.RSVP.resolve(manyArray); + return resolve(this.hasManyRelationship.getManyArray()); }; HasManyReference.prototype.reload = function() { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index bae53b3bc8d..9aa3286abf0 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -10,29 +10,40 @@ export default function ManyRelationship(store, record, inverseKey, relationship this._super$constructor(store, record, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; - this.manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: record - }); this.isPolymorphic = relationshipMeta.options.polymorphic; - this.manyArray.isPolymorphic = this.isPolymorphic; } ManyRelationship.prototype = Object.create(Relationship.prototype); +ManyRelationship.prototype.getManyArray = function() { + if (!this._manyArray) { + this._manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.record, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; +}; + ManyRelationship.prototype.constructor = ManyRelationship; ManyRelationship.prototype._super$constructor = Relationship; ManyRelationship.prototype.destroy = function() { - this.manyArray.destroy(); + if (this._manyArray) { + this._manyArray.destroy(); + } }; ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta; ManyRelationship.prototype.updateMeta = function(meta) { this._super$updateMeta(meta); - this.manyArray.set('meta', meta); + if (this._manyArray) { + this._manyArray.set('meta', meta); + } }; ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; @@ -54,7 +65,8 @@ ManyRelationship.prototype.addRecord = function(record, idx) { return; } this._super$addRecord(record, idx); - this.manyArray.internalAddRecords([record], idx); + // make lazy later + this.getManyArray().internalAddRecords([record], idx); }; ManyRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; @@ -74,7 +86,9 @@ ManyRelationship.prototype.removeCanonicalRecordFromOwn = function(record, idx) ManyRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; ManyRelationship.prototype.flushCanonical = function() { - this.manyArray.flushCanonical(); + if (this._manyArray) { + this._manyArray.flushCanonical(); + } this._super$flushCanonical(); }; @@ -84,11 +98,12 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { return; } this._super$removeRecordFromOwn(record, idx); + let manyArray = this.getManyArray(); if (idx !== undefined) { //TODO(Igor) not used currently, fix - this.manyArray.currentState.removeAt(idx); + manyArray.currentState.removeAt(idx); } else { - this.manyArray.internalRemoveRecords([record]); + manyArray.internalRemoveRecords([record]); } }; @@ -99,14 +114,15 @@ ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) }; ManyRelationship.prototype.reload = function() { - var manyArrayLoadedState = this.manyArray.get('isLoaded'); + let manyArray = this.getManyArray(); + let manyArrayLoadedState = manyArray.get('isLoaded'); if (this._loadingPromise) { if (this._loadingPromise.get('isPending')) { return this._loadingPromise; } if (this._loadingPromise.get('isRejected')) { - this.manyArray.set('isLoaded', manyArrayLoadedState); + manyArray.set('isLoaded', manyArrayLoadedState); } } @@ -114,8 +130,8 @@ ManyRelationship.prototype.reload = function() { this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); return this._loadingPromise; } else { - this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(this.manyArray.toArray()).then(() => { - return this.manyArray; + this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(manyArray.toArray()).then(() => { + return manyArray; }), 'Reload with ids'); return this._loadingPromise; } @@ -158,27 +174,28 @@ ManyRelationship.prototype.fetchLink = function() { } this.store._backburner.join(() => { this.updateRecordsFromAdapter(records); - this.manyArray.set('isLoaded', true); + this.getManyArray().set('isLoaded', true); }); - return this.manyArray; + return this.getManyArray(); }); }; ManyRelationship.prototype.findRecords = function() { - let manyArray = this.manyArray.toArray(); - let internalModels = new Array(manyArray.length); + let manyArray = this.getManyArray() + let array = manyArray.toArray(); + let internalModels = new Array(array.length); - for (let i = 0; i < manyArray.length; i++) { - internalModels[i] = manyArray[i]._internalModel; + for (let i = 0; i < array.length; i++) { + internalModels[i] = array[i]._internalModel; } //TODO CLEANUP return this.store.findMany(internalModels).then(() => { - if (!this.manyArray.get('isDestroyed')) { + if (!manyArray.get('isDestroyed')) { //Goes away after the manyArray refactor - this.manyArray.set('isLoaded', true); + manyArray.set('isLoaded', true); } - return this.manyArray; + return manyArray; }); }; ManyRelationship.prototype.notifyHasManyChanged = function() { @@ -187,6 +204,7 @@ ManyRelationship.prototype.notifyHasManyChanged = function() { ManyRelationship.prototype.getRecords = function() { //TODO(Igor) sync server here, once our syncing is not stupid + let manyArray = this.getManyArray(); if (this.isAsync) { var promise; if (this.link) { @@ -199,18 +217,18 @@ ManyRelationship.prototype.getRecords = function() { promise = this.findRecords(); } this._loadingPromise = PromiseManyArray.create({ - content: this.manyArray, + content: manyArray, promise: promise }); return this._loadingPromise; } else { - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? - if (!this.manyArray.get('isDestroyed')) { - this.manyArray.set('isLoaded', true); + if (!manyArray.get('isDestroyed')) { + manyArray.set('isLoaded', true); } - return this.manyArray; + return manyArray; } }; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 26510668bf0..0f0167ec8f7 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -291,9 +291,12 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { run(function() { comment = store.createRecord('comment', { name: "The Parley Letter" }); }); - post.get('comments').pushObject(comment); - assert.equal(comment.get('post'), post, "the post has been set correctly"); + run(function() { + post.get('comments').pushObject(comment); + + assert.equal(comment.get('post'), post, "the post has been set correctly"); + }); run(function() { comment.save().then(assert.wait(function(comment) { @@ -482,7 +485,10 @@ test("createRecord - a record on the many side of a hasMany relationship should }); var post = store.peekRecord('post', 1); - var commentCount = post.get('comments.length'); + var commentCount = run(function() { + return post.get('comments.length'); + }); + assert.equal(commentCount, 1, "the post starts life with a comment"); run(function() { diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index d0c0b5f9e10..1bf129bbf37 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -264,11 +264,14 @@ test('a loaded record is not removed from a record array when it is deleted even }); scumbag = store.peekRecord('person', 1); tag = store.peekRecord('tag', 1); + scumbag.deleteRecord(); }); - assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); - assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); + run(function() { + assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); + assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); + }); }); test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", function(assert) { @@ -320,8 +323,10 @@ test("a loaded record is not removed from both the record array and from the bel tool = store.peekRecord('tool', 1); }); - assert.equal(tag.get('people.length'), 1, 'record is in the record array'); - assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); + run(function() { + assert.equal(tag.get('people.length'), 1, 'record is in the record array'); + assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); + }); run(() => scumbag.deleteRecord()); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 32fee3c8af6..2ddd2d049ea 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -530,10 +530,12 @@ test("value() returns the referenced records when all records are loaded", funct env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); }); - var personsReference = family.hasMany('persons'); - var records = personsReference.value(); - assert.equal(get(records, 'length'), 2); - assert.equal(records.isEvery('isLoaded'), true); + run(function() { + var personsReference = family.hasMany('persons'); + var records = personsReference.value(); + assert.equal(get(records, 'length'), 2); + assert.equal(records.isEvery('isLoaded'), true); + }); }); test("load() fetches the referenced records", function(assert) { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 2300815875a..5509add44a9 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1678,8 +1678,9 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); post = env.store.peekRecord('post', 1); + + assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); }); - assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); run(function() { env.store.push({ diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 96d0be84b55..3d26be599b2 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -120,13 +120,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); - }); - assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); - assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); - assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); + assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); + assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); - run(function() { comment.set('post', post); }); @@ -355,13 +353,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse run(function() { user = store.createRecord('user'); post = store.createRecord('post'); - }); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function() { post.set('user', user); }); @@ -402,13 +398,11 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); - }); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function() { comment.set('message', post); }); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 99ca92d786e..f133d1bea4e 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -180,7 +180,7 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { +test("Fetching a hasMany where a record was removed reflects on the other hasMany side - sync", function(assert) { var account, user; run(function() { account = store.push({ @@ -225,8 +225,10 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); - assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); + run(function() { + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); + }); }); /* @@ -297,7 +299,9 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function( stanley.get('accounts').pushObject(account); }); - assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + run(function() { + assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + }); }); test("Removing a record from a hasMany reflects on the other hasMany side - async", function(assert) { @@ -374,12 +378,12 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync }); }); - assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); run(function() { + assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); account.get('users').removeObject(user); + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); - assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); /* @@ -465,9 +469,9 @@ test("Deleting a record that has a hasMany relationship removes it from the othe run(function() { account.deleteRecord(); account.rollbackAttributes(); + assert.equal(account.get('users.length'), 1, 'Users are still there'); + assert.equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); - assert.equal(account.get('users.length'), 1, 'Users are still there'); - assert.equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function(assert) { diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 2af63fe7f96..6225205f555 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -189,7 +189,9 @@ test("Relationship is available from the hasMany side even if only loaded from t } }); }); - assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + run(function() { + assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + }); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { @@ -300,7 +302,10 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } }); }); - assert.equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); + + run(function() { + assert.equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); + }); }); test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function(assert) { @@ -398,7 +403,10 @@ test("Fetching a belongsTo that is not defined does not remove the record from a } }); }); - assert.equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); + + run(function() { + assert.equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); + }); }); test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function(assert) { @@ -542,7 +550,10 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT } }); }); - assert.equal(account.get('user'), null, 'User was removed correctly'); + + run(function() { + assert.equal(account.get('user'), null, 'User was removed correctly'); + }); }); test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function(assert) { @@ -657,7 +668,9 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t }); }); - assert.equal(account.get('user'), user, 'User was not removed'); + run(function() { + assert.equal(account.get('user'), user, 'User was not removed'); + }); }); /* @@ -1249,9 +1262,9 @@ test("Rollbacking attributes of a deleted record works correctly when the hasMan run(function() { account.deleteRecord(); account.rollbackAttributes(); + assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); + assert.equal(account.get('user'), user, 'Account still has the user'); }); - assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); - assert.equal(account.get('user'), user, 'Account still has the user'); }); test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function(assert) { @@ -1331,9 +1344,9 @@ test("Rollbacking attributes of a deleted record works correctly when the belong run(function() { user.deleteRecord(); user.rollbackAttributes(); + assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); + assert.equal(account.get('user'), user, 'Account has the user again'); }); - assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); - assert.equal(account.get('user'), user, 'Account has the user again'); }); /* diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index ec1a03c47eb..176de164571 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -155,7 +155,9 @@ test("destroying the store correctly cleans everything up", function(assert) { var personWillDestroy = tap(person, 'willDestroy'); var carWillDestroy = tap(car, 'willDestroy'); - var carsWillDestroy = tap(car.get('person.cars'), 'willDestroy'); + var carsWillDestroy = run(function() { + return tap(car.get('person.cars'), 'willDestroy'); + }); env.adapter.query = function() { return [{ diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 49dc753537a..cd2fd323cf5 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -94,6 +94,7 @@ test("manyArray trigger arrayContentChange functions with the correct values", f var willChangeAddAmt; var originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; var originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; + DS.ManyArray.reopen({ arrayContentWillChange(startIdx, removeAmt, addAmt) { willChangeStartIdx = startIdx; @@ -138,7 +139,7 @@ test("manyArray trigger arrayContentChange functions with the correct values", f }] }); - store.peekRecord('post', 3); + store.peekRecord('post', 3).get('tags'); store.push({ data: { @@ -158,7 +159,6 @@ test("manyArray trigger arrayContentChange functions with the correct values", f } }); - store.peekRecord('post', 3); }); DS.ManyArray.reopen({ arrayContentWillChange: originalArrayContentWillChange, diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index d57ab8e6cce..db8d92ebb34 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -721,18 +721,16 @@ test("it is possible to add an item to a relationship, remove it, then add it ag var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - var person, tag1, tag2, tag3; + var person, tag1, tag2, tag3, tags; run(function() { person = store.createRecord('person'); tag1 = store.createRecord('tag'); tag2 = store.createRecord('tag'); tag3 = store.createRecord('tag'); - }); - var tags = get(person, 'tags'); + tags = get(person, 'tags'); - run(function() { tags.pushObjects([tag1, tag2, tag3]); tags.removeObject(tag2); }); @@ -771,6 +769,29 @@ test("DS.hasMany is async by default", function(assert) { }); }); +test("DS.ManyArray is lazy", function(assert) { + let Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + + let Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let tag = run(function() { + return env.store.createRecord('tag'); + }); + let hasManyRelationship = tag.hasMany('people').hasManyRelationship; + assert.ok(!hasManyRelationship._manyArray); + run(function() { + tag.get('people'); + }); + assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); +}); + testInDebug("throws assertion if of not set with an array", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({