Skip to content

Commit ed00731

Browse files
authored
fix: prevent rollbackRelationships from setting remoteState and localState to the same array reference (#9221)
* fix: prevent rollbackRelationships from setting remoteState and localState to the same array reference * fix lint
1 parent 0ea31da commit ed00731

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-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

+53
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ 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 { recordIdentifierFor } from '@ember-data/store';
78
import type { StableRecordIdentifier } from '@warp-drive/core-types';
89

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

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

0 commit comments

Comments
 (0)