Skip to content

Commit

Permalink
feat(signals): replace idKey with selectId when defining custom e…
Browse files Browse the repository at this point in the history
…ntity ID

Closes #4217, #4392
  • Loading branch information
markostanimirovic committed Jun 15, 2024
1 parent afb6c25 commit 5159c52
Show file tree
Hide file tree
Showing 22 changed files with 164 additions and 134 deletions.
4 changes: 4 additions & 0 deletions modules/signals/entities/spec/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { SelectEntityId } from '../src';
import { Todo } from './mocks';

export const selectTodoId: SelectEntityId<Todo> = (todo) => todo._id;
35 changes: 18 additions & 17 deletions modules/signals/entities/spec/updaters/add-entities.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { addEntities, withEntities } from '../../src';
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
import { selectTodoId as selectId } from '../helpers';

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

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

patchState(store, addEntities([todo2, todo3], { idKey: '_id' }));
patchState(store, addEntities([todo2, todo3], { selectId }));

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

patchState(
store,
addEntities([todo1], { idKey: '_id' }),
addEntities([] as Todo[], { idKey: '_id' })
addEntities([todo1], { selectId }),
addEntities([] as Todo[], { selectId })
);

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

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

patchState(
store,
addEntities([todo1], { idKey: '_id' }),
addEntities([todo2, todo1], { idKey: '_id' }),
addEntities([] as Todo[], { idKey: '_id' })
addEntities([todo1], { selectId }),
addEntities([todo2, todo1], { selectId }),
addEntities([] as Todo[], { selectId })
);

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

patchState(
store,
addEntities([] as Todo[], { idKey: '_id' }),
addEntities([todo2, { ...todo2, text: 'NgRx' }, todo1], { idKey: '_id' })
addEntities([] as Todo[], { selectId }),
addEntities([todo2, { ...todo2, text: 'NgRx' }, todo1], { selectId })
);

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

patchState(store, addEntities([todo1, todo3, todo2], { idKey: '_id' }));
patchState(store, addEntities([todo1, todo3, todo2], { selectId }));

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

it('adds entities with the specified idKey to the specified collection if they do not exist', () => {
it('adds entities with a custom id to the specified collection if they do not exist', () => {
const Store = signalStore(
withEntities({
entity: type<Todo>(),
Expand All @@ -184,7 +185,7 @@ describe('addEntities', () => {
store,
addEntities([todo3, todo2], {
collection: 'todo',
idKey: '_id',
selectId,
})
);

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

patchState(
store,
addEntities([todo1], { collection: 'todo', idKey: '_id' }),
addEntities([] as Todo[], { collection: 'todo', idKey: '_id' })
addEntities([todo1], { collection: 'todo', selectId }),
addEntities([] as Todo[], { collection: 'todo', selectId })
);

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

it('does not add entities with the specified idKey to the specified collection if they already exist', () => {
it('does not add entities with a custom id to the specified collection if they already exist', () => {
const todoMeta = {
entity: type<Todo>(),
collection: 'todo',
idKey: '_id',
selectId,
} as const;

const Store = signalStore(withEntities(todoMeta));
Expand Down
31 changes: 16 additions & 15 deletions modules/signals/entities/spec/updaters/add-entity.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { addEntity, withEntities } from '../../src';
import { Todo, todo1, todo2, User, user1, user2 } from '../mocks';
import { selectTodoId as selectId } from '../helpers';

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

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

patchState(store, addEntity(todo1, { idKey: '_id' }));
patchState(store, addEntity(todo1, { selectId }));

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

patchState(store, addEntity(todo2, { idKey: '_id' }));
patchState(store, addEntity(todo2, { selectId }));

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

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

patchState(
store,
addEntity(todo1, { idKey: '_id' }),
addEntity(todo2, { idKey: '_id' })
addEntity(todo1, { selectId }),
addEntity(todo2, { selectId })
);

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

patchState(
store,
addEntity(todo1, { idKey: '_id' }),
addEntity({ ...todo1, text: 'NgRx' }, { idKey: '_id' }),
addEntity(todo2, { idKey: '_id' }),
addEntity(todo1, { idKey: '_id' })
addEntity(todo1, { selectId }),
addEntity({ ...todo1, text: 'NgRx' }, { selectId }),
addEntity(todo2, { selectId }),
addEntity(todo1, { selectId })
);

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

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

patchState(store, addEntity(todo1, { collection: 'todo', idKey: '_id' }));
patchState(store, addEntity(todo1, { collection: 'todo', selectId }));

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

patchState(store, addEntity(todo2, { collection: 'todo', idKey: '_id' }));
patchState(store, addEntity(todo2, { collection: 'todo', selectId }));

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

it('does not add entity with the specified idKey to the specified collection if it already exists', () => {
it('does not add entity with a custom id to the specified collection if it already exists', () => {
const todoMeta = {
entity: type<Todo>(),
collection: 'todo',
idKey: '_id',
selectId,
} as const;

const Store = signalStore(withEntities(todoMeta));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { removeAllEntities, setAllEntities, withEntities } from '../../src';
import { Todo, todo1, todo2, User, user1, user2 } from '../mocks';
import { selectTodoId } from '../helpers';

describe('removeAllEntities', () => {
it('removes all entities', () => {
Expand All @@ -27,7 +28,7 @@ describe('removeAllEntities', () => {
store,
setAllEntities([todo1, todo2], {
collection: 'todo',
idKey: '_id',
selectId: selectTodoId,
})
);
patchState(store, removeAllEntities({ collection: 'todo' }));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { addEntities, removeEntities, withEntities } from '../../src';
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
import { selectTodoId } from '../helpers';

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

patchState(
store,
addEntities([todo1, todo2, todo3], { idKey: '_id' }),
addEntities([todo1, todo2, todo3], { selectId: selectTodoId }),
removeEntities((todo) => todo.completed)
);

Expand Down Expand Up @@ -99,7 +100,7 @@ describe('removeEntities', () => {
const todoMeta = {
entity: type<Todo>(),
collection: 'todo',
idKey: '_id',
selectId: selectTodoId,
} as const;

const Store = signalStore(withEntities(todoMeta));
Expand Down
5 changes: 3 additions & 2 deletions modules/signals/entities/spec/updaters/remove-entity.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { addEntities, removeEntity, withEntities } from '../../src';
import { Todo, todo1, todo2, todo3, User, user1, user2 } from '../mocks';
import { selectTodoId } from '../helpers';

describe('removeEntity', () => {
it('removes entity', () => {
Expand All @@ -18,7 +19,7 @@ describe('removeEntity', () => {
const Store = signalStore(withEntities<Todo>());
const store = new Store();

patchState(store, addEntities([todo2, todo3], { idKey: '_id' }));
patchState(store, addEntities([todo2, todo3], { selectId: selectTodoId }));

const entityMap = store.entityMap();
const ids = store.ids();
Expand All @@ -39,7 +40,7 @@ describe('removeEntity', () => {
const todoMeta = {
entity: type<Todo>(),
collection: 'todo',
idKey: '_id',
selectId: selectTodoId,
} as const;

const Store = signalStore(withEntities(todoMeta));
Expand Down
13 changes: 7 additions & 6 deletions modules/signals/entities/spec/updaters/set-all-entities.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import { setAllEntities, withEntities } from '../../src';
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';
import { selectTodoId as selectId } from '../helpers';

describe('setAllEntities', () => {
it('replaces entity collection with provided entities', () => {
Expand Down Expand Up @@ -57,34 +58,34 @@ describe('setAllEntities', () => {
expect(store.userEntities()).toEqual([]);
});

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

patchState(store, setAllEntities([todo2, todo3], { idKey: '_id' }));
patchState(store, setAllEntities([todo2, todo3], { selectId }));

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

patchState(store, setAllEntities([todo3, todo2, todo1], { idKey: '_id' }));
patchState(store, setAllEntities([todo3, todo2, todo1], { selectId }));

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

patchState(store, setAllEntities([] as Todo[], { idKey: '_id' }));
patchState(store, setAllEntities([] as Todo[], { selectId }));

expect(store.entityMap()).toEqual({});
expect(store.ids()).toEqual([]);
expect(store.entities()).toEqual([]);
});

it('replaces specified entity collection with provided entities with the specified idKey', () => {
it('replaces specified entity collection with provided entities with a custom id', () => {
const todoMeta = {
entity: type<Todo>(),
collection: 'todo',
idKey: '_id',
selectId,
} as const;

const Store = signalStore(withEntities(todoMeta));
Expand Down
Loading

0 comments on commit 5159c52

Please sign in to comment.