diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index a85df168cab..86af77eb11f 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -225,7 +225,13 @@ export default class BelongsToRelationship extends Relationship { }); } - getData() { + /* + While the `shouldForceReload` flag will also be true when `isForcedReload` is true, + `isForcedReload` is only `true` for an initial `getData` call during a forced reload. + Other calls must conform to the typical expectations, for instance, sync relationships + expect that their data is already loaded. + */ + getData(isForcedReload = false) { //TODO(Igor) flushCanonical here once our syncing is not stupid let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; @@ -264,7 +270,7 @@ export default class BelongsToRelationship extends Relationship { "' with id " + this.internalModel.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.belongsTo({ async: true })`)', - record === null || !record.get('isEmpty') + record === null || !record.get('isEmpty') || isForcedReload ); return record; } diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index 7a164d92958..c6b8449cb06 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -344,7 +344,7 @@ export default class ManyRelationship extends Relationship { }); } - getData() { + getData(isForcedReload = false) { //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; @@ -379,7 +379,7 @@ export default class ManyRelationship extends Relationship { }' with id ${ this.internalModel.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.allInverseRecordsAreLoaded + this.allInverseRecordsAreLoaded || isForcedReload ); return manyArray; diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index 77e26f374a6..2448ff392e9 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -554,7 +554,7 @@ export default class Relationship { this.setHasFailedLoadAttempt(false); this.setShouldForceReload(true); - this.getData(); + this.getData(true); return this._promiseProxy; } diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index afa9c6c8e86..f3b9c5cccb0 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -27,7 +27,7 @@ class TestAdapter extends JSONAPIAdapter { this._payloads = arr; } - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; } diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js index dc40dc717f6..29ad420597a 100644 --- a/tests/acceptance/relationships/has-many-test.js +++ b/tests/acceptance/relationships/has-many-test.js @@ -31,7 +31,7 @@ class TestAdapter extends JSONAPIAdapter { this._payloads = arr; } - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; } diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 51477ae2a9c..a063a7838c3 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -133,7 +133,7 @@ module('Store.createRecord() coverage', function(hooks) { this.owner.register( 'adapter:application', JSONAPIAdapter.extend({ - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; }, findRecord() { diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index e764cd4cb56..29318234f97 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,121 +1,103 @@ import { resolve, reject } from 'rsvp'; -import { run } from '@ember/runloop'; import { get } from '@ember/object'; -import setupStore from 'dummy/tests/helpers/store'; - +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; +import Store from 'ember-data/store'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; + +module('integration/reload - Reloading Records', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + class Person extends Model { + @attr + updatedAt; + @attr + name; + @attr + firstName; + @attr + lastName; + } -import DS from 'ember-data'; + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, jsonApiPayload) { + return jsonApiPayload; + }, + }) + ); + store = owner.lookup('service:store'); + }); -var attr = DS.attr; -var Person, env; + test("When a single record is requested, the adapter's find method should be called unless it's loaded.", async function(assert) { + let count = 0; + let reloadOptions = { + adapterOptions: { + makeSnazzy: true, + }, + }; -module('integration/reload - Reloading Records', { - beforeEach() { - Person = DS.Model.extend({ - updatedAt: attr('string'), - name: attr('string'), - firstName: attr('string'), - lastName: attr('string'), - }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, - env = setupStore({ person: Person }); - }, + findRecord(store, type, id, snapshot) { + if (count === 0) { + count++; + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); + } else if (count === 1) { + assert.equal( + snapshot.adapterOptions, + reloadOptions.adapterOptions, + 'We passed adapterOptions via reload' + ); + count++; + return resolve({ + data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } }, + }); + } else { + assert.ok(false, 'Should not get here'); + } + }, + }) + ); - afterEach() { - run(env.container, 'destroy'); - }, -}); + let person = await store.findRecord('person', '1'); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { - var count = 0; - - env.adapter.findRecord = function(store, type, id, snapshot) { - if (count === 0) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); - } else if (count === 1) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); - } else { - assert.ok(false, 'Should not get here'); - } - }; - - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); - assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); - var promise = person.reload(); - assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); - return promise; - }) - .then(function(person) { - assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); - assert.equal( - get(person, 'name'), - 'Braaaahm Dale', - 'The person is now updated with the right name' - ); - }); - }); -}); + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); + assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { - let count = 0; - let reloadOptions = { - adapterOptions: { - makeSnazzy: true, - }, - }; - - env.adapter.findRecord = function(store, type, id, snapshot) { - if (count === 0) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); - } else if (count === 1) { - assert.equal( - snapshot.adapterOptions, - reloadOptions.adapterOptions, - 'We passed adapterOptions via reload' - ); - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); - } else { - assert.ok(false, 'Should not get here'); - } - }; + let promise = person.reload(reloadOptions); - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); - assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); + assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); - let promise = person.reload(reloadOptions); + await promise; - assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); + assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); + assert.equal( + get(person, 'name'), + 'Braaaahm Dale', + 'The person is now updated with the right name' + ); - return promise; - }) - .then(function(person) { - assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); - assert.equal( - get(person, 'name'), - 'Braaaahm Dale', - 'The person is now updated with the right name' - ); - }); + // ensure we won't call adapter.findRecord again + await store.findRecord('person', '1'); }); -}); -test('When a record is reloaded and fails, it can try again', function(assert) { - var tom; - run(function() { - env.store.push({ + test('When a record is reloaded and fails, it can try again', async function(assert) { + let tom = store.push({ data: { type: 'person', id: '1', @@ -124,134 +106,607 @@ test('When a record is reloaded and fails, it can try again', function(assert) { }, }, }); - tom = env.store.peekRecord('person', 1); + let count = 0; + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return true; + }, + + findRecord() { + assert.equal(tom.get('isReloading'), true, 'Tom is reloading'); + if (count++ === 0) { + return reject(); + } else { + return resolve({ + data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } }, + }); + } + }, + }) + ); + + await tom.reload().catch(() => { + assert.ok(true, 'we throw an error'); + }); + + assert.equal(tom.get('isError'), true, 'Tom is now errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + + let person = await tom.reload(); + + assert.equal(person, tom, 'The resolved value is the record'); + assert.equal(tom.get('isError'), false, 'Tom is no longer errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + assert.equal(tom.get('name'), 'Thomas Dale', 'the updates apply'); }); - var count = 0; - env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(tom.get('isReloading'), true, 'Tom is reloading'); - if (count++ === 0) { - return reject(); - } else { - return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }); + test('When a record is loaded a second time, isLoaded stays true', async function(assert) { + assert.expect(3); + function getTomDale() { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + }, + }; } - }; - - run(function() { - tom - .reload() - .then(null, function() { - assert.equal(tom.get('isError'), true, 'Tom is now errored'); - assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); - return tom.reload(); + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return true; + }, + + findRecord(store, type, id, snapshot) { + assert.ok(true, 'We should call findRecord'); + return resolve(getTomDale()); + }, }) - .then(function(person) { - assert.equal(person, tom, 'The resolved value is the record'); - assert.equal(tom.get('isError'), false, 'Tom is no longer errored'); - assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); - assert.equal(tom.get('name'), 'Thomas Dale', 'the updates apply'); - }); + ); + + function isLoadedDidChange() { + // This observer should never fire + assert.ok(false, 'We should not trigger the isLoaded observer'); + // but if it does we should still have the same isLoaded state + assert.equal(get(this, 'isLoaded'), true, 'The person is still loaded after change'); + } + + store.push(getTomDale()); + + let person = await store.findRecord('person', '1'); + + person.addObserver('isLoaded', isLoadedDidChange); + assert.equal(get(person, 'isLoaded'), true, 'The person is loaded'); + + // Reload the record + store.push(getTomDale()); + + assert.equal(get(person, 'isLoaded'), true, 'The person is still loaded after load'); + + person.removeObserver('isLoaded', isLoadedDidChange); }); -}); -test('When a record is loaded a second time, isLoaded stays true', function(assert) { - let record = { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale', - }, - }, - }; - env.adapter.findRecord = function(store, type, id, snapshot) { - return record; - }; - run(function() { - env.store.push(record); + test('When a record is reloaded, its async hasMany relationships still work', async function(assert) { + class Person extends Model { + @attr + name; + @hasMany('tag', { async: true, inverse: null }) + tags; + } + class Tag extends Model { + @attr + name; + } + + this.owner.unregister('model:person'); + this.owner.register('model:person', Person); + this.owner.register('model:tag', Tag); + + let tagsById = { 1: 'hipster', 2: 'hair' }; + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + + findRecord(store, type, id, snapshot) { + switch (type.modelName) { + case 'person': + return resolve({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Tom' }, + relationships: { + tags: { + data: [{ id: '1', type: 'tag' }, { id: '2', type: 'tag' }], + }, + }, + }, + }); + case 'tag': + return resolve({ data: { id: id, type: 'tag', attributes: { name: tagsById[id] } } }); + } + }, + }) + ); + + let tom; + let person = await store.findRecord('person', '1'); + + tom = person; + assert.equal(person.get('name'), 'Tom', 'precond'); + + let tags = await person.get('tags'); + + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + + person = await tom.reload(); + assert.equal(person.get('name'), 'Tom', 'precond'); + + tags = await person.get('tags'); + + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], 'The tags are still there'); }); - run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'isLoaded'), true, 'The person is loaded'); - person.addObserver('isLoaded', isLoadedDidChange); + module('Reloading via relationship reference and { type, id }', function() { + test('When a sync belongsTo relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownerRef = shen.belongsTo('owner'); + let owner = shen.get('owner'); + let ownerViaRef = await ownerRef.reload(); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync belongsTo relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + }, + }, + }, + }); + + let ownerRef = shen.belongsTo('owner'); + let ownerViaRef = await ownerRef.reload(); + let owner = shen.get('owner'); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync hasMany relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownersRef = shen.hasMany('owners'); + let owners = shen.get('owners'); + let ownersViaRef = await ownersRef.reload(); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); - // Reload the record - env.store.push(record); + test('When a sync hasMany relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); - assert.equal(get(person, 'isLoaded'), true, 'The person is still loaded after load'); + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + }); - person.removeObserver('isLoaded', isLoadedDidChange); + let ownersRef = shen.hasMany('owners'); + let ownersViaRef = await ownersRef.reload(); + let owners = shen.get('owners'); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); }); }); - function isLoadedDidChange() { - // This shouldn't be hit - assert.equal(get(this, 'isLoaded'), true, 'The person is still loaded after change'); - } -}); + module('Reloading via relationship reference and links', function() { + test('When a sync belongsTo relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findBelongsTo() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); -test('When a record is reloaded, its async hasMany relationships still work', function(assert) { - env.registry.register( - 'model:person', - DS.Model.extend({ - name: DS.attr(), - tags: DS.hasMany('tag', { async: true }), - }) - ); - - env.registry.register( - 'model:tag', - DS.Model.extend({ - name: DS.attr(), - }) - ); - - var tags = { 1: 'hipster', 2: 'hair' }; - - env.adapter.findRecord = function(store, type, id, snapshot) { - switch (type.modelName) { - case 'person': - return resolve({ - data: { - id: 1, + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + links: { + related: './owner', + }, + }, + }, + }, + included: [ + { type: 'person', - attributes: { name: 'Tom' }, - relationships: { - tags: { - data: [{ id: 1, type: 'tag' }, { id: 2, type: 'tag' }], + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownerRef = shen.belongsTo('owner'); + let owner = shen.get('owner'); + let ownerViaRef = await ownerRef.reload(); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync belongsTo relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findBelongsTo() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + links: { + related: './owner', }, }, }, - }); - case 'tag': - return resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); - } - }; + }, + }); - var tom; + let ownerRef = shen.belongsTo('owner'); + let ownerViaRef = await ownerRef.reload(); + let owner = shen.get('owner'); - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - tom = person; - assert.equal(person.get('name'), 'Tom', 'precond'); + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); - return person.get('tags'); - }) - .then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + test('When a sync hasMany relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findHasMany() { + assert.ok('We called findRecord'); + return resolve({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + }, + }) + ); - return tom.reload(); - }) - .then(function(person) { - assert.equal(person.get('name'), 'Tom', 'precond'); + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + links: { + related: './owners', + }, + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); - return person.get('tags'); - }) - .then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], 'The tags are still there'); + let ownersRef = shen.hasMany('owners'); + let owners = shen.get('owners'); + let ownersViaRef = await ownersRef.reload(); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); + + test('When a sync hasMany relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findHasMany() { + assert.ok('We called findRecord'); + return resolve({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + links: { + related: './owners', + }, + }, + }, + }, }); + + let ownersRef = shen.hasMany('owners'); + let ownersViaRef = await ownersRef.reload(); + let owners = shen.get('owners'); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); }); });