From 74444443980ffb9e9fd94bb70762c3791b9b93ad Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 13 Mar 2018 15:16:27 -0700 Subject: [PATCH] [bugfix beta] Fetch cancels unload When fetching records, cancel internal model destruction if it is scheduled, ie if the model is dematerializing because it was unloaded. It is not possible to construct snapshots for dematerializing internal models. Prior to this commit, this could happen when fetching a record in the same runloop that it was unloaded. A straightfoward way of getting into this state was via ``` store.findRecord('book', 1).then(b => b.unloadRecord) ``` when the model is already cached in the store. Under these conditions, the fetch is scheduled, then the promise fulfills with the cached record and is unloaded and *then* the scheduled fetch is flushed. [fix #5343] --- addon/-private/system/store.js | 12 ++++++++++ tests/integration/records/unload-test.js | 28 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1e04de2be9b..87822122ef5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -855,6 +855,18 @@ Store = Service.extend({ seeking[internalModel.id] = pendingItem; } + for (let i = 0; i < totalItems; i++) { + let internalModel = internalModels[i]; + // We may have unloaded the record after scheduling this fetch, in which + // case we must cancel the destory. This is because we require a record + // to build a snapshot. This is not fundamental: this cancelation code + // can be removed when snapshots can be created for internal models that + // have no records. + if (internalModel.hasScheduledDestroy()) { + internalModels[i].cancelDestroy(); + } + } + function _fetchRecord(recordResolverPair) { let recordFetch = store._fetchRecord( recordResolverPair.internalModel, diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 34e98b168cc..f7cdb8494a4 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -2089,3 +2089,31 @@ test('unload invalidates link promises', function(assert) { }) ); }); + +test('fetching records cancels unloading', function(assert) { + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + + return { + data: { + id: 1, + type: 'person' + } + } + }; + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person' + } + }) + ); + + return run(() => + env.store.findRecord('person', 1, { backgroundReload: true }) + .then(person => person.unloadRecord()) + ); +});