Skip to content

Commit e1720b4

Browse files
fix(data): mergeQuerySet uses mergeStrategy (#2430)
Closes #2368
1 parent 0b41c71 commit e1720b4

File tree

2 files changed

+173
-1
lines changed

2 files changed

+173
-1
lines changed

modules/data/spec/reducers/entity-cache-reducer.spec.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
ChangeSet,
2929
ChangeSetOperation,
3030
Logger,
31+
MergeStrategy,
32+
ChangeType,
3133
} from '../..';
3234

3335
class Hero {
@@ -286,6 +288,121 @@ describe('EntityCacheReducer', () => {
286288
expect(heroCollection.ids).toEqual(expectedIds);
287289
expect(heroCollection.entities[42]).toEqual({ id: 42, name: 'Bobby' });
288290
});
291+
292+
it('should use default preserve changes merge strategy', () => {
293+
const {
294+
unchangedHero,
295+
unchangedHeroServerUpdated,
296+
updatedHero,
297+
locallyUpdatedHero,
298+
serverUpdatedHero,
299+
initialCache,
300+
} = createInitialCacheForMerges();
301+
const querySet: EntityCacheQuerySet = {
302+
Hero: [unchangedHeroServerUpdated, serverUpdatedHero],
303+
};
304+
const action = new MergeQuerySet(querySet);
305+
306+
const state = entityCacheReducer(initialCache, action);
307+
expect(state['Hero'].entities[unchangedHero.id]).toEqual(
308+
unchangedHeroServerUpdated,
309+
'Updates current value for unchanged entity'
310+
);
311+
expect(state['Hero'].entities[updatedHero.id]).toEqual(
312+
locallyUpdatedHero,
313+
'Preserves the current value for changed entity'
314+
);
315+
expect(
316+
state['Hero'].changeState[updatedHero.id]!.originalValue
317+
).toEqual(
318+
serverUpdatedHero,
319+
'Overwrites the originalValue with the merge entity'
320+
);
321+
});
322+
323+
it('should be able to use ignore changes merge strategy', () => {
324+
const {
325+
updatedHero,
326+
serverUpdatedHero,
327+
initialCache,
328+
} = createInitialCacheForMerges();
329+
const querySet: EntityCacheQuerySet = {
330+
Hero: [serverUpdatedHero],
331+
};
332+
const action = new MergeQuerySet(querySet, MergeStrategy.IgnoreChanges);
333+
334+
const state = entityCacheReducer(initialCache, action);
335+
expect(state['Hero'].entities[updatedHero.id]).toEqual(
336+
serverUpdatedHero,
337+
'Update the collection entity'
338+
);
339+
expect(
340+
state['Hero'].changeState[updatedHero.id]!.originalValue
341+
).toEqual(updatedHero, 'changeState is untouched');
342+
});
343+
344+
it('should be able to use preserve changes merge strategy', () => {
345+
const {
346+
unchangedHero,
347+
unchangedHeroServerUpdated,
348+
updatedHero,
349+
locallyUpdatedHero,
350+
serverUpdatedHero,
351+
initialCache,
352+
} = createInitialCacheForMerges();
353+
const querySet: EntityCacheQuerySet = {
354+
Hero: [unchangedHeroServerUpdated, serverUpdatedHero],
355+
};
356+
const action = new MergeQuerySet(
357+
querySet,
358+
MergeStrategy.PreserveChanges
359+
);
360+
361+
const state = entityCacheReducer(initialCache, action);
362+
expect(state['Hero'].entities[unchangedHero.id]).toEqual(
363+
unchangedHeroServerUpdated,
364+
'Updates current value for unchanged entity'
365+
);
366+
expect(state['Hero'].entities[updatedHero.id]).toEqual(
367+
locallyUpdatedHero,
368+
'Preserves the current value for changed entity'
369+
);
370+
expect(
371+
state['Hero'].changeState[updatedHero.id]!.originalValue
372+
).toEqual(
373+
serverUpdatedHero,
374+
'Overwrites the originalValue with the merge entity'
375+
);
376+
});
377+
378+
it('should be able to use overwrite changes merge strategy', () => {
379+
const {
380+
unchangedHero,
381+
unchangedHeroServerUpdated,
382+
updatedHero,
383+
serverUpdatedHero,
384+
initialCache,
385+
} = createInitialCacheForMerges();
386+
const querySet: EntityCacheQuerySet = {
387+
Hero: [unchangedHeroServerUpdated, serverUpdatedHero],
388+
};
389+
const action = new MergeQuerySet(
390+
querySet,
391+
MergeStrategy.OverwriteChanges
392+
);
393+
394+
const state = entityCacheReducer(initialCache, action);
395+
expect(state['Hero'].entities[unchangedHero.id]).toEqual(
396+
unchangedHeroServerUpdated,
397+
'Replace the current collection entity for unchanged entity'
398+
);
399+
expect(state['Hero'].changeState[unchangedHero.id]).toBeUndefined();
400+
expect(state['Hero'].entities[updatedHero.id]).toEqual(
401+
serverUpdatedHero,
402+
'Replace the current collection entity for changed entity'
403+
);
404+
expect(state['Hero'].changeState[updatedHero.id]).toBeUndefined();
405+
});
289406
});
290407

291408
describe('SET_ENTITY_CACHE', () => {
@@ -592,6 +709,61 @@ describe('EntityCacheReducer', () => {
592709
return cache;
593710
}
594711

712+
function createInitialCacheForMerges() {
713+
// general test data for testing mergeStrategy
714+
const unchangedHero = { id: 1, name: 'Unchanged', power: 'Hammer' };
715+
const unchangedHeroServerUpdated = {
716+
id: 1,
717+
name: 'UnchangedUpdated',
718+
power: 'Bish',
719+
};
720+
const deletedHero = { id: 2, name: 'Deleted', power: 'Bash' };
721+
const addedHero = { id: 3, name: 'Added', power: 'Tiny' };
722+
const updatedHero = { id: 4, name: 'Pre Updated', power: 'Tech' };
723+
const locallyUpdatedHero = {
724+
id: 4,
725+
name: 'Locally Updated',
726+
power: 'Suit',
727+
};
728+
const serverUpdatedHero = { id: 4, name: 'Server Updated', power: 'Nano' };
729+
const ids = [unchangedHero.id, addedHero.id, updatedHero.id];
730+
const initialCache = {
731+
Hero: {
732+
ids,
733+
entities: {
734+
[unchangedHero.id]: unchangedHero,
735+
[addedHero.id]: addedHero,
736+
[updatedHero.id]: locallyUpdatedHero,
737+
},
738+
entityName: 'Hero',
739+
filter: '',
740+
loaded: true,
741+
loading: false,
742+
changeState: {
743+
[deletedHero.id]: {
744+
changeType: ChangeType.Deleted,
745+
originalValue: deletedHero,
746+
},
747+
[updatedHero.id]: {
748+
changeType: ChangeType.Updated,
749+
originalValue: updatedHero,
750+
},
751+
[addedHero.id]: { changeType: ChangeType.Added },
752+
},
753+
},
754+
};
755+
return {
756+
unchangedHero,
757+
unchangedHeroServerUpdated,
758+
deletedHero,
759+
addedHero,
760+
updatedHero,
761+
locallyUpdatedHero,
762+
serverUpdatedHero,
763+
initialCache,
764+
};
765+
}
766+
595767
function createInitialSaveTestEntities() {
596768
const entities: { [entityName: string]: any[] } = {
597769
Fool: [

modules/data/src/reducers/entity-cache-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export class EntityCacheReducerFactory {
188188
let { mergeStrategy, querySet, tag } = action.payload;
189189
mergeStrategy =
190190
mergeStrategy === null ? MergeStrategy.PreserveChanges : mergeStrategy;
191-
const entityOp = EntityOp.UPSERT_MANY;
191+
const entityOp = EntityOp.QUERY_MANY_SUCCESS;
192192

193193
const entityNames = Object.keys(querySet);
194194
entityCache = entityNames.reduce((newCache, entityName) => {

0 commit comments

Comments
 (0)