From dc0928e3c80330ec70d3d65e8385404942242b61 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 29 Nov 2018 17:56:16 -0800 Subject: [PATCH] [BUGFIX beta] backport #5767 Make _recordData lazy --- addon/-private/system/model/internal-model.js | 21 ++++++- tests/integration/records/record-data-test.js | 59 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index af126b1117c..968ae91105e 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -92,7 +92,7 @@ export default class InternalModel { this.modelName = modelName; this.clientId = clientId; - this._recordData = store._createRecordData(modelName, id, clientId, this); + this.__recordData = null; // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; @@ -143,6 +143,17 @@ export default class InternalModel { return this._recordReference; } + get _recordData() { + if (this.__recordData === null) { + this._recordData = this.store._createRecordData(this.modelName, this.id, this.clientId, this); + } + return this.__recordData; + } + + set _recordData(newValue) { + this.__recordData = newValue; + } + get _recordArrays() { if (this.__recordArrays === null) { this.__recordArrays = new OrderedSet(); @@ -790,6 +801,10 @@ export default class InternalModel { hasChangedAttributes() { heimdall.increment(hasChangedAttributes); + if (this.isLoading() && !this.isReloading) { + // no need to instantiate _recordData in this case + return false; + } return this._recordData.hasChangedAttributes(); } @@ -802,6 +817,10 @@ export default class InternalModel { */ changedAttributes() { heimdall.increment(changedAttributes); + if (this.isLoading() && !this.isReloading) { + // no need to calculate changed attributes when calling `findRecord` + return {}; + } return this._recordData.changedAttributes(); } diff --git a/tests/integration/records/record-data-test.js b/tests/integration/records/record-data-test.js index a9b9c3f9765..2106494c4cc 100644 --- a/tests/integration/records/record-data-test.js +++ b/tests/integration/records/record-data-test.js @@ -5,6 +5,7 @@ import { run } from '@ember/runloop'; import { attr, belongsTo, hasMany } from '@ember-decorators/data'; import { assign } from '@ember/polyfills'; import { RecordData } from 'ember-data/-private'; +import { resolve } from 'rsvp'; class Person extends Model { @hasMany('pet', { inverse: null, async: false }) @@ -230,4 +231,62 @@ module('RecordData Compatibility', function(hooks) { assert.ok(false, 'expected `unloadRecord()` not to throw'); } }); + + test(`store.findRecord does not eagerly instantiate record data`, async function(assert) { + let recordDataInstances = 0; + class TestRecordData extends CustomRecordData { + constructor() { + super(...arguments); + ++recordDataInstances; + } + } + + store.createRecordDataFor = function(modelName, id, lid, storeWrapper) { + return new TestRecordData(modelName, id, lid, storeWrapper); + }; + this.owner.register( + 'adapter:pet', + class TestAdapter { + static create() { + return new TestAdapter(...arguments); + } + + findRecord() { + assert.equal( + recordDataInstances, + 0, + 'no instance created from findRecord before adapter promise resolves' + ); + + return resolve({ + data: { + id: '1', + type: 'pet', + attributes: { + name: 'Loki', + }, + }, + }); + } + } + ); + this.owner.register( + 'serializer:pet', + class TestSerializer { + static create() { + return new TestSerializer(...arguments); + } + + normalizeResponse(store, modelClass, payload) { + return payload; + } + } + ); + + assert.equal(recordDataInstances, 0, 'initially no instances'); + + await store.findRecord('pet', '1'); + + assert.equal(recordDataInstances, 1, 'record data created after promise fulfills'); + }); });