Skip to content

Commit a02ea9f

Browse files
feat(entity): new setMany adapter (#3026) (#3029)
Closes #3026
1 parent 15bc0df commit a02ea9f

File tree

6 files changed

+87
-1
lines changed

6 files changed

+87
-1
lines changed

modules/entity/spec/sorted_state_adapter.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ describe('Sorted State Adapter', () => {
6969
});
7070
});
7171

72+
it('should let you set many entities in the state', () => {
73+
const firstChange = { title: 'First Change' };
74+
const withMany = adapter.setAll([TheGreatGatsby], state);
75+
76+
const withUpserts = adapter.setMany(
77+
[{ ...TheGreatGatsby, ...firstChange }, AClockworkOrange],
78+
withMany
79+
);
80+
81+
expect(withUpserts).toEqual({
82+
ids: [AClockworkOrange.id, TheGreatGatsby.id],
83+
entities: {
84+
[TheGreatGatsby.id]: {
85+
...TheGreatGatsby,
86+
...firstChange,
87+
},
88+
[AClockworkOrange.id]: AClockworkOrange,
89+
},
90+
});
91+
});
92+
7293
it('should remove existing and add new ones on setAll', () => {
7394
const withOneEntity = adapter.addOne(TheGreatGatsby, state);
7495

modules/entity/spec/unsorted_state_adapter.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ describe('Unsorted State Adapter', () => {
6868
});
6969
});
7070

71+
it('should let you set many entities in the state', () => {
72+
const firstChange = { title: 'First Change' };
73+
const withMany = adapter.setAll([TheGreatGatsby], state);
74+
75+
const withUpserts = adapter.setMany(
76+
[{ ...TheGreatGatsby, ...firstChange }, AClockworkOrange],
77+
withMany
78+
);
79+
80+
expect(withUpserts).toEqual({
81+
ids: [TheGreatGatsby.id, AClockworkOrange.id],
82+
entities: {
83+
[TheGreatGatsby.id]: {
84+
...TheGreatGatsby,
85+
...firstChange,
86+
},
87+
[AClockworkOrange.id]: AClockworkOrange,
88+
},
89+
});
90+
});
91+
7192
it('should remove existing and add new ones on setAll', () => {
7293
const withOneEntity = adapter.addOne(TheGreatGatsby, state);
7394

modules/entity/src/models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export interface EntityStateAdapter<T> {
5757

5858
setAll<S extends EntityState<T>>(entities: T[], state: S): S;
5959
setOne<S extends EntityState<T>>(entity: T, state: S): S;
60+
setMany<S extends EntityState<T>>(entities: T[], state: S): S;
6061

6162
removeOne<S extends EntityState<T>>(key: string, state: S): S;
6263
removeOne<S extends EntityState<T>>(key: number, state: S): S;

modules/entity/src/sorted_state_adapter.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
6464
}
6565
}
6666

67+
function setManyMutably(entities: T[], state: R): DidMutate;
68+
function setManyMutably(entities: any[], state: any): DidMutate {
69+
const didMutateSetOne = entities.map((entity) =>
70+
setOneMutably(entity, state)
71+
);
72+
73+
switch (true) {
74+
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.Both):
75+
return DidMutate.Both;
76+
case didMutateSetOne.some(
77+
(didMutate) => didMutate === DidMutate.EntitiesOnly
78+
):
79+
return DidMutate.EntitiesOnly;
80+
default:
81+
return DidMutate.None;
82+
}
83+
}
84+
6785
function updateOneMutably(update: Update<T>, state: R): DidMutate;
6886
function updateOneMutably(update: any, state: any): DidMutate {
6987
return updateManyMutably([update], state);
@@ -233,6 +251,7 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
233251
upsertOne: createStateOperator(upsertOneMutably),
234252
setAll: createStateOperator(setAllMutably),
235253
setOne: createStateOperator(setOneMutably),
254+
setMany: createStateOperator(setManyMutably),
236255
addMany: createStateOperator(addManyMutably),
237256
updateMany: createStateOperator(updateManyMutably),
238257
upsertMany: createStateOperator(upsertManyMutably),

modules/entity/src/unsorted_state_adapter.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,24 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
6767
return DidMutate.Both;
6868
}
6969

70+
function setManyMutably(entities: T[], state: R): DidMutate;
71+
function setManyMutably(entities: any[], state: any): DidMutate {
72+
const didMutateSetOne = entities.map((entity) =>
73+
setOneMutably(entity, state)
74+
);
75+
76+
switch (true) {
77+
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.Both):
78+
return DidMutate.Both;
79+
case didMutateSetOne.some(
80+
(didMutate) => didMutate === DidMutate.EntitiesOnly
81+
):
82+
return DidMutate.EntitiesOnly;
83+
default:
84+
return DidMutate.None;
85+
}
86+
}
87+
7088
function removeOneMutably(key: T, state: R): DidMutate;
7189
function removeOneMutably(key: any, state: any): DidMutate {
7290
return removeManyMutably([key], state);
@@ -232,6 +250,7 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
232250
addMany: createStateOperator(addManyMutably),
233251
setAll: createStateOperator(setAllMutably),
234252
setOne: createStateOperator(setOneMutably),
253+
setMany: createStateOperator(setManyMutably),
235254
updateOne: createStateOperator(updateOneMutably),
236255
updateMany: createStateOperator(updateManyMutably),
237256
upsertOne: createStateOperator(upsertOneMutably),

projects/ngrx.io/content/guide/entity/adapter.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ state if no changes were made.
8787
- `addMany`: Add multiple entities to the collection.
8888
- `setAll`: Replace current collection with provided collection.
8989
- `setOne`: Add or Replace one entity in the collection.
90+
- `setMany`: Add or Replace multiple entities in the collection.
9091
- `removeOne`: Remove one entity from the collection.
9192
- `removeMany`: Remove multiple entities from the collection, by id or by predicate.
9293
- `removeAll`: Clear entity collection.
@@ -113,6 +114,7 @@ import { Update, EntityMap, EntityMapOne, Predicate } from '@ngrx/entity';
113114
import { User } from '../models/user.model';
114115

115116
export const loadUsers = createAction('[User/API] Load Users', props<{ users: User[] }>());
117+
export const setUsers = createAction('[User/API] Set Users', props<{ users: User[] }>());
116118
export const addUser = createAction('[User/API] Add User', props<{ user: User }>());
117119
export const setUser = createAction('[User/API] Set User', props<{ user: User }>());
118120
export const upsertUser = createAction('[User/API] Upsert User', props<{ user: User }>());
@@ -188,6 +190,9 @@ const userReducer = createReducer(
188190
on(UserActions.loadUsers, (state, { users }) => {
189191
return adapter.setAll(users, state);
190192
}),
193+
on(UserActions.setUsers, (state, { users }) => {
194+
return adapter.setMany(users, state);
195+
}),
191196
on(UserActions.clearUsers, state => {
192197
return adapter.removeAll({ ...state, selectedUserId: null });
193198
})
@@ -242,7 +247,7 @@ type Update<T> = UpdateStr<T> | UpdateNum<T>;
242247

243248
Secondly, `upsertOne` and `upsertMany` will perform an insert or update. If a partial entity is provided this will perform an update.
244249

245-
To prevent partial updates either explicitly set all the fields, setting non-used fields with value `undefined`, or use the `setOne` or `setAll` adapter methods.
250+
To prevent partial updates either explicitly set all the fields, setting non-used fields with value `undefined`, or use the `setOne`, `setAll` or `setMany` adapter methods.
246251

247252
### Entity Selectors
248253

0 commit comments

Comments
 (0)