Skip to content

Commit e00c73d

Browse files
committed
fix: prevent rollbackRelationships from setting remoteState and localState to the same array reference
1 parent 91b4275 commit e00c73d

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
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

+55
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { settled } from '@ember/test-helpers';
2+
13
import { module, test } from 'qunit';
24

35
import { setupTest } from 'ember-qunit';
46

57
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
68
import type Store from '@ember-data/store';
9+
import { recordIdentifierFor } from '@ember-data/store';
710
import type { StableRecordIdentifier } from '@warp-drive/core-types';
811

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

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

0 commit comments

Comments
 (0)