Skip to content

Commit 4e4c50f

Browse files
timdeschryverbrandonroberts
authored andcommitted
feat(entity): add support for predicate to updateMany (#907)
1 parent a9bc070 commit 4e4c50f

File tree

7 files changed

+122
-5
lines changed

7 files changed

+122
-5
lines changed

modules/entity/spec/sorted_state_adapter.spec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ describe('Sorted State Adapter', () => {
280280
});
281281
});
282282

283-
it('should let you update many entities in the state', () => {
283+
it('should let you update many entities by id in the state', () => {
284284
const firstChange = { title: 'Zack' };
285285
const secondChange = { title: 'Aaron' };
286286
const withMany = adapter.addAll([TheGreatGatsby, AClockworkOrange], state);
@@ -308,6 +308,41 @@ describe('Sorted State Adapter', () => {
308308
});
309309
});
310310

311+
it('should let you map over entities in the state', () => {
312+
const firstChange = { ...TheGreatGatsby, title: 'First change' };
313+
const secondChange = { ...AClockworkOrange, title: 'Second change' };
314+
315+
const withMany = adapter.addAll(
316+
[TheGreatGatsby, AClockworkOrange, AnimalFarm],
317+
state
318+
);
319+
320+
const withUpdates = adapter.map(
321+
book =>
322+
book.title === TheGreatGatsby.title
323+
? firstChange
324+
: book.title === AClockworkOrange.title
325+
? secondChange
326+
: book,
327+
withMany
328+
);
329+
330+
expect(withUpdates).toEqual({
331+
ids: [AnimalFarm.id, TheGreatGatsby.id, AClockworkOrange.id],
332+
entities: {
333+
[AnimalFarm.id]: AnimalFarm,
334+
[TheGreatGatsby.id]: {
335+
...TheGreatGatsby,
336+
...firstChange,
337+
},
338+
[AClockworkOrange.id]: {
339+
...AClockworkOrange,
340+
...secondChange,
341+
},
342+
},
343+
});
344+
});
345+
311346
it('should let you add one entity to the state with upsert()', () => {
312347
const withOneEntity = adapter.upsertOne(TheGreatGatsby, state);
313348
expect(withOneEntity).toEqual({

modules/entity/spec/unsorted_state_adapter.spec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ describe('Unsorted State Adapter', () => {
220220
});
221221
});
222222

223-
it('should let you update many entities in the state', () => {
223+
it('should let you update many entities by id in the state', () => {
224224
const firstChange = { title: 'First Change' };
225225
const secondChange = { title: 'Second Change' };
226226
const withMany = adapter.addAll([TheGreatGatsby, AClockworkOrange], state);
@@ -248,6 +248,41 @@ describe('Unsorted State Adapter', () => {
248248
});
249249
});
250250

251+
it('should let you map over entities in the state', () => {
252+
const firstChange = { ...TheGreatGatsby, title: 'First change' };
253+
const secondChange = { ...AClockworkOrange, title: 'Second change' };
254+
255+
const withMany = adapter.addAll(
256+
[TheGreatGatsby, AClockworkOrange, AnimalFarm],
257+
state
258+
);
259+
260+
const withUpdates = adapter.map(
261+
book =>
262+
book.title === TheGreatGatsby.title
263+
? firstChange
264+
: book.title === AClockworkOrange.title
265+
? secondChange
266+
: book,
267+
withMany
268+
);
269+
270+
expect(withUpdates).toEqual({
271+
ids: [TheGreatGatsby.id, AClockworkOrange.id, AnimalFarm.id],
272+
entities: {
273+
[TheGreatGatsby.id]: {
274+
...TheGreatGatsby,
275+
...firstChange,
276+
},
277+
[AClockworkOrange.id]: {
278+
...AClockworkOrange,
279+
...secondChange,
280+
},
281+
[AnimalFarm.id]: AnimalFarm,
282+
},
283+
});
284+
});
285+
251286
it('should let you add one entity to the state with upsert()', () => {
252287
const withOneEntity = adapter.upsertOne(TheGreatGatsby, state);
253288
expect(withOneEntity).toEqual({

modules/entity/src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
export { createEntityAdapter } from './create_adapter';
2-
export { Dictionary, EntityState, EntityAdapter, Update } from './models';
2+
export {
3+
Dictionary,
4+
EntityState,
5+
EntityAdapter,
6+
Update,
7+
EntityMap,
8+
Predicate,
9+
} from './models';

modules/entity/src/models.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export type Update<T> = UpdateStr<T> | UpdateNum<T>;
3030

3131
export type Predicate<T> = (entity: T) => boolean;
3232

33+
export type EntityMap<T> = (entity: T) => T;
34+
3335
export interface EntityState<T> {
3436
ids: string[] | number[];
3537
entities: Dictionary<T>;
@@ -59,6 +61,8 @@ export interface EntityStateAdapter<T> {
5961

6062
upsertOne<S extends EntityState<T>>(entity: T, state: S): S;
6163
upsertMany<S extends EntityState<T>>(entities: T[], state: S): S;
64+
65+
map<S extends EntityState<T>>(map: EntityMap<T>, state: S): S;
6266
}
6367

6468
export interface EntitySelectors<T, V> {

modules/entity/src/sorted_state_adapter.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import {
22
EntityState,
33
IdSelector,
44
Comparer,
5-
Dictionary,
65
EntityStateAdapter,
76
Update,
7+
EntityMap,
88
} from './models';
99
import { createStateOperator, DidMutate } from './state_adapter';
1010
import { createUnsortedStateAdapter } from './unsorted_state_adapter';
@@ -107,6 +107,22 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
107107
}
108108
}
109109

110+
function mapMutably(map: EntityMap<T>, state: R): DidMutate;
111+
function mapMutably(updatesOrMap: any, state: any): DidMutate {
112+
const updates: Update<T>[] = state.ids.reduce(
113+
(changes: any[], id: string | number) => {
114+
const change = updatesOrMap(state.entities[id]);
115+
if (change !== state.entities[id]) {
116+
changes.push({ id, changes: change });
117+
}
118+
return changes;
119+
},
120+
[]
121+
);
122+
123+
return updateManyMutably(updates, state);
124+
}
125+
110126
function upsertOneMutably(entity: T, state: R): DidMutate;
111127
function upsertOneMutably(entity: any, state: any): DidMutate {
112128
return upsertManyMutably([entity], state);
@@ -187,5 +203,6 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
187203
addMany: createStateOperator(addManyMutably),
188204
updateMany: createStateOperator(updateManyMutably),
189205
upsertMany: createStateOperator(upsertManyMutably),
206+
map: createStateOperator(mapMutably),
190207
};
191208
}

modules/entity/src/state_adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EntityState, EntityStateAdapter } from './models';
1+
import { EntityState } from './models';
22

33
export enum DidMutate {
44
EntitiesOnly,

modules/entity/src/unsorted_state_adapter.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
IdSelector,
55
Update,
66
Predicate,
7+
EntityMap,
78
} from './models';
89
import { createStateOperator, DidMutate } from './state_adapter';
910
import { selectIdValue } from './utils';
@@ -138,6 +139,23 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
138139
return DidMutate.None;
139140
}
140141

142+
function mapMutably(map: EntityMap<T>, state: R): DidMutate;
143+
function mapMutably(map: any, state: any): DidMutate {
144+
const changes: Update<T>[] = state.ids.reduce(
145+
(changes: any[], id: string | number) => {
146+
const change = map(state.entities[id]);
147+
if (change !== state.entities[id]) {
148+
changes.push({ id, changes: change });
149+
}
150+
return changes;
151+
},
152+
[]
153+
);
154+
const updates = changes.filter(({ id }) => id in state.entities);
155+
156+
return updateManyMutably(updates, state);
157+
}
158+
141159
function upsertOneMutably(entity: T, state: R): DidMutate;
142160
function upsertOneMutably(entity: any, state: any): DidMutate {
143161
return upsertManyMutably([entity], state);
@@ -183,5 +201,6 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
183201
upsertMany: createStateOperator(upsertManyMutably),
184202
removeOne: createStateOperator(removeOneMutably),
185203
removeMany: createStateOperator(removeManyMutably),
204+
map: createStateOperator(mapMutably),
186205
};
187206
}

0 commit comments

Comments
 (0)