Skip to content

Commit 640322d

Browse files
authored
fix: prevent rollbackRelationships from setting remoteState and localState to the same array reference (#9222)
1 parent 36a5a15 commit 640322d

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

packages/graph/src/-private/-diff.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ export function rollbackRelationship(
398398
op: 'replaceRelatedRecords',
399399
record: identifier,
400400
field,
401-
value: relationship.remoteState,
401+
value: relationship.remoteState.slice(),
402402
},
403403
false
404404
);

tests/main/tests/integration/relationships/rollback-test.ts

+54-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { setupTest } from 'ember-qunit';
44

55
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
66
import type Store from '@ember-data/store';
7-
import { StableRecordIdentifier } from '@ember-data/types/q/identifier';
7+
import { recordIdentifierFor } from '@ember-data/store';
8+
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
89

910
class App extends Model {
1011
@attr declare name: string;
@@ -394,6 +395,58 @@ module('Integration | Relationships | Rollback', function (hooks) {
394395
assert.arrayStrictEquals(changed, [], 'belongsTo has rolled back');
395396
assert.strictEqual(config.app, store.peekRecord('app', '1') as App, 'belongsTo has rolled back');
396397
});
398+
399+
test('relationship rollback can be repeated', function (assert) {
400+
class Message extends Model {
401+
@attr declare msg: string;
402+
}
403+
class Job extends Model {
404+
@attr declare name: string;
405+
@hasMany('message', { async: false, inverse: null }) declare messages: Message[];
406+
}
407+
408+
this.owner.register('model:job', Job);
409+
this.owner.register('model:message', Message);
410+
const store = this.owner.lookup('service:store') as Store;
411+
412+
const job = store.push({
413+
data: {
414+
id: '1',
415+
type: 'job',
416+
attributes: {
417+
name: 'First Job',
418+
},
419+
},
420+
}) as Job;
421+
422+
const msg1 = store.push({
423+
data: {
424+
id: '1',
425+
type: 'message',
426+
attributes: {
427+
msg: 'First Message',
428+
},
429+
},
430+
}) as Message;
431+
assert.strictEqual(job.messages.length, 0, 'job has 0 messages');
432+
const jobIdentifier = recordIdentifierFor(job);
433+
434+
// add message, assert state, rollback, assert state is clean
435+
job.messages.push(msg1);
436+
assert.strictEqual(job.messages.length, 1, 'job has 1 message');
437+
438+
const rollbackResult = store.cache.rollbackRelationships(jobIdentifier);
439+
assert.strictEqual(rollbackResult.length, 1, '1 rollbackRelations');
440+
assert.strictEqual(job.messages.length, 0, 'job has no message');
441+
442+
// repeat the scenario to add a message and rollback
443+
job.messages.push(msg1);
444+
assert.strictEqual(job.messages.length, 1, 'job has 1 message');
445+
446+
const rollbackResult2 = store.cache.rollbackRelationships(jobIdentifier);
447+
assert.strictEqual(rollbackResult2.length, 1, '1 rollbackRelations');
448+
assert.strictEqual(job.messages.length, 0, 'job has no message');
449+
});
397450
});
398451

399452
module('<cache>.changedRelationships', function () {

0 commit comments

Comments
 (0)