Skip to content

Commit 67a5a93

Browse files
feat(signals): replace idKey with selectId when defining custom entity ID (#4396)
Closes #4217, #4392 Co-authored-by: Tim Deschryver <[email protected]>
1 parent 05f0940 commit 67a5a93

22 files changed

+164
-134
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { SelectEntityId } from '../src';
2+
import { Todo } from './mocks';
3+
4+
export const selectTodoId: SelectEntityId<Todo> = (todo) => todo._id;

modules/signals/entities/spec/updaters/add-entities.spec.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { addEntities, withEntities } from '../../src';
33
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
4+
import { selectTodoId as selectId } from '../helpers';
45

56
describe('addEntities', () => {
67
it('adds entities if they do not exist', () => {
@@ -115,36 +116,36 @@ describe('addEntities', () => {
115116
expect(store.userEntities()).toEqual([user1, user3, user2]);
116117
});
117118

118-
it('adds entities with the specified idKey if they do not exist', () => {
119+
it('adds entities with a custom id if they do not exist', () => {
119120
const Store = signalStore(withEntities<Todo>());
120121
const store = new Store();
121122

122-
patchState(store, addEntities([todo2, todo3], { idKey: '_id' }));
123+
patchState(store, addEntities([todo2, todo3], { selectId }));
123124

124125
expect(store.entityMap()).toEqual({ y: todo2, z: todo3 });
125126
expect(store.ids()).toEqual(['y', 'z']);
126127
expect(store.entities()).toEqual([todo2, todo3]);
127128

128129
patchState(
129130
store,
130-
addEntities([todo1], { idKey: '_id' }),
131-
addEntities([] as Todo[], { idKey: '_id' })
131+
addEntities([todo1], { selectId }),
132+
addEntities([] as Todo[], { selectId })
132133
);
133134

134135
expect(store.entityMap()).toEqual({ y: todo2, z: todo3, x: todo1 });
135136
expect(store.ids()).toEqual(['y', 'z', 'x']);
136137
expect(store.entities()).toEqual([todo2, todo3, todo1]);
137138
});
138139

139-
it('does not add entities with the specified idKey if they already exist', () => {
140+
it('does not add entities with a custom id if they already exist', () => {
140141
const Store = signalStore(withEntities<Todo>());
141142
const store = new Store();
142143

143144
patchState(
144145
store,
145-
addEntities([todo1], { idKey: '_id' }),
146-
addEntities([todo2, todo1], { idKey: '_id' }),
147-
addEntities([] as Todo[], { idKey: '_id' })
146+
addEntities([todo1], { selectId }),
147+
addEntities([todo2, todo1], { selectId }),
148+
addEntities([] as Todo[], { selectId })
148149
);
149150

150151
const entityMap = store.entityMap();
@@ -153,8 +154,8 @@ describe('addEntities', () => {
153154

154155
patchState(
155156
store,
156-
addEntities([] as Todo[], { idKey: '_id' }),
157-
addEntities([todo2, { ...todo2, text: 'NgRx' }, todo1], { idKey: '_id' })
157+
addEntities([] as Todo[], { selectId }),
158+
addEntities([todo2, { ...todo2, text: 'NgRx' }, todo1], { selectId })
158159
);
159160

160161
expect(store.entityMap()).toBe(entityMap);
@@ -164,14 +165,14 @@ describe('addEntities', () => {
164165
expect(store.ids()).toEqual(['x', 'y']);
165166
expect(store.entities()).toEqual([todo1, todo2]);
166167

167-
patchState(store, addEntities([todo1, todo3, todo2], { idKey: '_id' }));
168+
patchState(store, addEntities([todo1, todo3, todo2], { selectId }));
168169

169170
expect(store.entityMap()).toEqual({ x: todo1, y: todo2, z: todo3 });
170171
expect(store.ids()).toEqual(['x', 'y', 'z']);
171172
expect(store.entities()).toEqual([todo1, todo2, todo3]);
172173
});
173174

174-
it('adds entities with the specified idKey to the specified collection if they do not exist', () => {
175+
it('adds entities with a custom id to the specified collection if they do not exist', () => {
175176
const Store = signalStore(
176177
withEntities({
177178
entity: type<Todo>(),
@@ -184,7 +185,7 @@ describe('addEntities', () => {
184185
store,
185186
addEntities([todo3, todo2], {
186187
collection: 'todo',
187-
idKey: '_id',
188+
selectId,
188189
})
189190
);
190191

@@ -194,20 +195,20 @@ describe('addEntities', () => {
194195

195196
patchState(
196197
store,
197-
addEntities([todo1], { collection: 'todo', idKey: '_id' }),
198-
addEntities([] as Todo[], { collection: 'todo', idKey: '_id' })
198+
addEntities([todo1], { collection: 'todo', selectId }),
199+
addEntities([] as Todo[], { collection: 'todo', selectId })
199200
);
200201

201202
expect(store.todoEntityMap()).toEqual({ z: todo3, y: todo2, x: todo1 });
202203
expect(store.todoIds()).toEqual(['z', 'y', 'x']);
203204
expect(store.todoEntities()).toEqual([todo3, todo2, todo1]);
204205
});
205206

206-
it('does not add entities with the specified idKey to the specified collection if they already exist', () => {
207+
it('does not add entities with a custom id to the specified collection if they already exist', () => {
207208
const todoMeta = {
208209
entity: type<Todo>(),
209210
collection: 'todo',
210-
idKey: '_id',
211+
selectId,
211212
} as const;
212213

213214
const Store = signalStore(withEntities(todoMeta));

modules/signals/entities/spec/updaters/add-entity.spec.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { addEntity, withEntities } from '../../src';
33
import { Todo, todo1, todo2, User, user1, user2 } from '../mocks';
4+
import { selectTodoId as selectId } from '../helpers';
45

56
describe('addEntity', () => {
67
it('adds entity if it does not exist', () => {
@@ -96,31 +97,31 @@ describe('addEntity', () => {
9697
expect(store.userEntities()).toEqual([user1]);
9798
});
9899

99-
it('adds entity with the specified idKey if it does not exist', () => {
100+
it('adds entity with a custom id if it does not exist', () => {
100101
const Store = signalStore(withEntities<Todo>());
101102
const store = new Store();
102103

103-
patchState(store, addEntity(todo1, { idKey: '_id' }));
104+
patchState(store, addEntity(todo1, { selectId }));
104105

105106
expect(store.entityMap()).toEqual({ x: todo1 });
106107
expect(store.ids()).toEqual(['x']);
107108
expect(store.entities()).toEqual([todo1]);
108109

109-
patchState(store, addEntity(todo2, { idKey: '_id' }));
110+
patchState(store, addEntity(todo2, { selectId }));
110111

111112
expect(store.entityMap()).toEqual({ x: todo1, y: todo2 });
112113
expect(store.ids()).toEqual(['x', 'y']);
113114
expect(store.entities()).toEqual([todo1, todo2]);
114115
});
115116

116-
it('does not add entity with the specified idKey if it already exists', () => {
117+
it('does not add entity with a custom id if it already exists', () => {
117118
const Store = signalStore(withEntities<Todo>());
118119
const store = new Store();
119120

120121
patchState(
121122
store,
122-
addEntity(todo1, { idKey: '_id' }),
123-
addEntity(todo2, { idKey: '_id' })
123+
addEntity(todo1, { selectId }),
124+
addEntity(todo2, { selectId })
124125
);
125126

126127
const entityMap = store.entityMap();
@@ -129,10 +130,10 @@ describe('addEntity', () => {
129130

130131
patchState(
131132
store,
132-
addEntity(todo1, { idKey: '_id' }),
133-
addEntity({ ...todo1, text: 'NgRx' }, { idKey: '_id' }),
134-
addEntity(todo2, { idKey: '_id' }),
135-
addEntity(todo1, { idKey: '_id' })
133+
addEntity(todo1, { selectId }),
134+
addEntity({ ...todo1, text: 'NgRx' }, { selectId }),
135+
addEntity(todo2, { selectId }),
136+
addEntity(todo1, { selectId })
136137
);
137138

138139
expect(store.entityMap()).toBe(entityMap);
@@ -143,7 +144,7 @@ describe('addEntity', () => {
143144
expect(store.entities()).toEqual([todo1, todo2]);
144145
});
145146

146-
it('adds entity with the specified idKey to the specified collection if it does not exist', () => {
147+
it('adds entity with a custom id to the specified collection if it does not exist', () => {
147148
const Store = signalStore(
148149
withEntities({
149150
entity: type<Todo>(),
@@ -152,24 +153,24 @@ describe('addEntity', () => {
152153
);
153154
const store = new Store();
154155

155-
patchState(store, addEntity(todo1, { collection: 'todo', idKey: '_id' }));
156+
patchState(store, addEntity(todo1, { collection: 'todo', selectId }));
156157

157158
expect(store.todoEntityMap()).toEqual({ x: todo1 });
158159
expect(store.todoIds()).toEqual(['x']);
159160
expect(store.todoEntities()).toEqual([todo1]);
160161

161-
patchState(store, addEntity(todo2, { collection: 'todo', idKey: '_id' }));
162+
patchState(store, addEntity(todo2, { collection: 'todo', selectId }));
162163

163164
expect(store.todoEntityMap()).toEqual({ x: todo1, y: todo2 });
164165
expect(store.todoIds()).toEqual(['x', 'y']);
165166
expect(store.todoEntities()).toEqual([todo1, todo2]);
166167
});
167168

168-
it('does not add entity with the specified idKey to the specified collection if it already exists', () => {
169+
it('does not add entity with a custom id to the specified collection if it already exists', () => {
169170
const todoMeta = {
170171
entity: type<Todo>(),
171172
collection: 'todo',
172-
idKey: '_id',
173+
selectId,
173174
} as const;
174175

175176
const Store = signalStore(withEntities(todoMeta));

modules/signals/entities/spec/updaters/remove-all-entities.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { removeAllEntities, setAllEntities, withEntities } from '../../src';
33
import { Todo, todo1, todo2, User, user1, user2 } from '../mocks';
4+
import { selectTodoId } from '../helpers';
45

56
describe('removeAllEntities', () => {
67
it('removes all entities', () => {
@@ -27,7 +28,7 @@ describe('removeAllEntities', () => {
2728
store,
2829
setAllEntities([todo1, todo2], {
2930
collection: 'todo',
30-
idKey: '_id',
31+
selectId: selectTodoId,
3132
})
3233
);
3334
patchState(store, removeAllEntities({ collection: 'todo' }));

modules/signals/entities/spec/updaters/remove-entities.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { addEntities, removeEntities, withEntities } from '../../src';
33
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
4+
import { selectTodoId } from '../helpers';
45

56
describe('removeEntities', () => {
67
it('removes entities by ids', () => {
@@ -24,7 +25,7 @@ describe('removeEntities', () => {
2425

2526
patchState(
2627
store,
27-
addEntities([todo1, todo2, todo3], { idKey: '_id' }),
28+
addEntities([todo1, todo2, todo3], { selectId: selectTodoId }),
2829
removeEntities((todo) => todo.completed)
2930
);
3031

@@ -99,7 +100,7 @@ describe('removeEntities', () => {
99100
const todoMeta = {
100101
entity: type<Todo>(),
101102
collection: 'todo',
102-
idKey: '_id',
103+
selectId: selectTodoId,
103104
} as const;
104105

105106
const Store = signalStore(withEntities(todoMeta));

modules/signals/entities/spec/updaters/remove-entity.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { addEntities, removeEntity, withEntities } from '../../src';
33
import { Todo, todo1, todo2, todo3, User, user1, user2 } from '../mocks';
4+
import { selectTodoId } from '../helpers';
45

56
describe('removeEntity', () => {
67
it('removes entity', () => {
@@ -18,7 +19,7 @@ describe('removeEntity', () => {
1819
const Store = signalStore(withEntities<Todo>());
1920
const store = new Store();
2021

21-
patchState(store, addEntities([todo2, todo3], { idKey: '_id' }));
22+
patchState(store, addEntities([todo2, todo3], { selectId: selectTodoId }));
2223

2324
const entityMap = store.entityMap();
2425
const ids = store.ids();
@@ -39,7 +40,7 @@ describe('removeEntity', () => {
3940
const todoMeta = {
4041
entity: type<Todo>(),
4142
collection: 'todo',
42-
idKey: '_id',
43+
selectId: selectTodoId,
4344
} as const;
4445

4546
const Store = signalStore(withEntities(todoMeta));

modules/signals/entities/spec/updaters/set-all-entities.spec.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { patchState, signalStore, type } from '@ngrx/signals';
22
import { setAllEntities, withEntities } from '../../src';
33
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
4+
import { selectTodoId as selectId } from '../helpers';
45

56
describe('setAllEntities', () => {
67
it('replaces entity collection with provided entities', () => {
@@ -57,34 +58,34 @@ describe('setAllEntities', () => {
5758
expect(store.userEntities()).toEqual([]);
5859
});
5960

60-
it('replaces entity collection with provided entities with the specified idKey', () => {
61+
it('replaces entity collection with provided entities with a custom id', () => {
6162
const Store = signalStore(withEntities<Todo>());
6263
const store = new Store();
6364

64-
patchState(store, setAllEntities([todo2, todo3], { idKey: '_id' }));
65+
patchState(store, setAllEntities([todo2, todo3], { selectId }));
6566

6667
expect(store.entityMap()).toEqual({ y: todo2, z: todo3 });
6768
expect(store.ids()).toEqual(['y', 'z']);
6869
expect(store.entities()).toEqual([todo2, todo3]);
6970

70-
patchState(store, setAllEntities([todo3, todo2, todo1], { idKey: '_id' }));
71+
patchState(store, setAllEntities([todo3, todo2, todo1], { selectId }));
7172

7273
expect(store.entityMap()).toEqual({ z: todo3, y: todo2, x: todo1 });
7374
expect(store.ids()).toEqual(['z', 'y', 'x']);
7475
expect(store.entities()).toEqual([todo3, todo2, todo1]);
7576

76-
patchState(store, setAllEntities([] as Todo[], { idKey: '_id' }));
77+
patchState(store, setAllEntities([] as Todo[], { selectId }));
7778

7879
expect(store.entityMap()).toEqual({});
7980
expect(store.ids()).toEqual([]);
8081
expect(store.entities()).toEqual([]);
8182
});
8283

83-
it('replaces specified entity collection with provided entities with the specified idKey', () => {
84+
it('replaces specified entity collection with provided entities with a custom id', () => {
8485
const todoMeta = {
8586
entity: type<Todo>(),
8687
collection: 'todo',
87-
idKey: '_id',
88+
selectId,
8889
} as const;
8990

9091
const Store = signalStore(withEntities(todoMeta));

0 commit comments

Comments
 (0)