From e9441a549d4f4a981a44735bf00b26196771edb0 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 3afc287f901..803d15793e9 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -2008,3 +2008,31 @@ test('1 sync : many async unload sync side', 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()) + ); +});