From 294186f281e0d4a056da58ab1c485f3ec66cd566 Mon Sep 17 00:00:00 2001 From: Andrey Fel Date: Tue, 6 Oct 2020 17:26:17 +0300 Subject: [PATCH] Pass lid from relationship data to get record data The issue appeared in the sideposting scenario: - model A has has many relationship to model B. - instance of model A and instance of model B are created on the client, - model A is saved along with model B sent in `include` section of payload; the linking is done through `lid` - server persisted both models and sent the response with server-generated `id` along with `lid` sent by the client. - when hasMany.updateData() was called while the response payload was pushed to the store it couldn't match the record which was already in the store with the record data contained in the relationship data because `lid` was omitted. Add a test which ensures that the hasMany() relationship has correct status in the sideposting with lid scenario. --- .../identifiers/lid-reflection-test.ts | 79 ++++++++++++++++++- .../-private/relationships/state/has-many.ts | 6 +- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/packages/-ember-data/tests/integration/identifiers/lid-reflection-test.ts b/packages/-ember-data/tests/integration/identifiers/lid-reflection-test.ts index 4d58ac081c7..d2268f56e6c 100644 --- a/packages/-ember-data/tests/integration/identifiers/lid-reflection-test.ts +++ b/packages/-ember-data/tests/integration/identifiers/lid-reflection-test.ts @@ -1,11 +1,11 @@ import { module, test } from 'qunit'; -import { defer } from 'rsvp'; +import { defer, resolve } from 'rsvp'; import { setupTest } from 'ember-qunit'; import Adapter from '@ember-data/adapter'; import { RECORD_DATA_STATE } from '@ember-data/canary-features'; -import Model, { attr } from '@ember-data/model'; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; import Serializer from '@ember-data/serializer'; import Store, { recordIdentifierFor } from '@ember-data/store'; @@ -145,4 +145,79 @@ module('Integration | Identifiers - lid reflection', function(hooks) { assert.strictEqual(record.name, '@runspired', 'After we finish we use the most recent clean name'); }); + + test('hasMany() has correct state after .save() on a newly created record with sideposted child record when lid is provided in the response payload', async function(assert) { + class Ingredient extends Model { + @attr name; + @belongsTo('cake') cake; + } + + class Cake extends Model { + @attr name; + @hasMany('ingredient', { async: false }) ingredients; + } + + this.owner.register('model:ingredient', Ingredient); + this.owner.register('model:cake', Cake); + + class TestSerializer extends Serializer { + normalizeResponse(_, __, payload) { + return payload; + } + } + class TestAdapter extends Adapter { + createRecord(store, ModelClass, snapshot) { + return resolve({ + data: { + type: 'cake', + id: '1', + attributes: { + name: 'Cheesecake', + }, + relationships: { + ingredients: { + data: [ + { + type: 'ingredient', + id: '2', + lid: cheeseIdentifier.lid, + }, + ], + }, + }, + }, + included: [ + { + type: 'ingredient', + id: '2', + lid: cheeseIdentifier.lid, + attributes: { + name: 'Cheese', + }, + relationships: { + cake: { + data: { + type: 'cake', + id: '1', + }, + }, + }, + }, + ], + }); + } + } + this.owner.register('serializer:application', TestSerializer); + this.owner.register('adapter:application', TestAdapter); + + const cheese = store.createRecord('ingredient', { name: 'Cheese' }); + const cake = store.createRecord('cake', { name: 'Cheesecake', ingredients: [cheese] }); + + const cheeseIdentifier = recordIdentifierFor(cheese); + + await cake.save(); + + assert.deepEqual(cake.hasMany('ingredients').ids(), ['2']); + assert.equal(cake.ingredients.objectAt(0).name, 'Cheese'); + }); }); diff --git a/packages/record-data/addon/-private/relationships/state/has-many.ts b/packages/record-data/addon/-private/relationships/state/has-many.ts index 5620ea3c4f6..3ef4ff9279c 100755 --- a/packages/record-data/addon/-private/relationships/state/has-many.ts +++ b/packages/record-data/addon/-private/relationships/state/has-many.ts @@ -215,7 +215,11 @@ export default class ManyRelationship extends Relationship { } else { recordDatas = new Array(data.length); for (let i = 0; i < data.length; i++) { - recordDatas[i] = this.recordData.storeWrapper.recordDataFor(data[i].type, data[i].id) as RelationshipRecordData; + recordDatas[i] = this.recordData.storeWrapper.recordDataFor( + data[i].type, + data[i].id, + data[i].lid + ) as RelationshipRecordData; } } this.updateRecordDatasFromAdapter(recordDatas);