Skip to content

Commit aae4064

Browse files
MikeRyanDevbrandonroberts
authored andcommitted
feat(Entity): Enable creating entity selectors without composing a state selector (#490)
1 parent 8728bc1 commit aae4064

File tree

3 files changed

+111
-50
lines changed

3 files changed

+111
-50
lines changed

modules/entity/spec/state_selectors.spec.ts

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,98 @@ import {
77
TheGreatGatsby,
88
} from './fixtures/book';
99

10-
describe('Entity State', () => {
11-
interface State {
12-
books: EntityState<BookModel>;
13-
}
10+
describe('Entity State Selectors', () => {
11+
describe('Composed Selectors', () => {
12+
interface State {
13+
books: EntityState<BookModel>;
14+
}
1415

15-
let adapter: EntityAdapter<BookModel>;
16-
let selectors: EntitySelectors<BookModel, State>;
17-
let state: State;
16+
let adapter: EntityAdapter<BookModel>;
17+
let selectors: EntitySelectors<BookModel, State>;
18+
let state: State;
1819

19-
beforeEach(() => {
20-
adapter = createEntityAdapter({
21-
selectId: (book: BookModel) => book.id,
20+
beforeEach(() => {
21+
adapter = createEntityAdapter({
22+
selectId: (book: BookModel) => book.id,
23+
});
24+
25+
state = {
26+
books: adapter.addAll(
27+
[AClockworkOrange, AnimalFarm, TheGreatGatsby],
28+
adapter.getInitialState()
29+
),
30+
};
31+
32+
selectors = adapter.getSelectors((state: State) => state.books);
33+
});
34+
35+
it('should create a selector for selecting the ids', () => {
36+
const ids = selectors.selectIds(state);
37+
38+
expect(ids).toEqual(state.books.ids);
39+
});
40+
41+
it('should create a selector for selecting the entities', () => {
42+
const entities = selectors.selectEntities(state);
43+
44+
expect(entities).toEqual(state.books.entities);
45+
});
46+
47+
it('should create a selector for selecting the list of models', () => {
48+
const models = selectors.selectAll(state);
49+
50+
expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]);
2251
});
2352

24-
state = {
25-
books: adapter.addAll(
53+
it('should create a selector for selecting the count of models', () => {
54+
const total = selectors.selectTotal(state);
55+
56+
expect(total).toEqual(3);
57+
});
58+
});
59+
60+
describe('Uncomposed Selectors', () => {
61+
type State = EntityState<BookModel>;
62+
63+
let adapter: EntityAdapter<BookModel>;
64+
let selectors: EntitySelectors<BookModel, EntityState<BookModel>>;
65+
let state: State;
66+
67+
beforeEach(() => {
68+
adapter = createEntityAdapter({
69+
selectId: (book: BookModel) => book.id,
70+
});
71+
72+
state = adapter.addAll(
2673
[AClockworkOrange, AnimalFarm, TheGreatGatsby],
2774
adapter.getInitialState()
28-
),
29-
};
75+
);
3076

31-
selectors = adapter.getSelectors((state: State) => state.books);
32-
});
77+
selectors = adapter.getSelectors();
78+
});
3379

34-
it('should create a selector for selecting the ids', () => {
35-
const ids = selectors.selectIds(state);
80+
it('should create a selector for selecting the ids', () => {
81+
const ids = selectors.selectIds(state);
3682

37-
expect(ids).toEqual(state.books.ids);
38-
});
83+
expect(ids).toEqual(state.ids);
84+
});
3985

40-
it('should create a selector for selecting the entities', () => {
41-
const entities = selectors.selectEntities(state);
86+
it('should create a selector for selecting the entities', () => {
87+
const entities = selectors.selectEntities(state);
4288

43-
expect(entities).toEqual(state.books.entities);
44-
});
89+
expect(entities).toEqual(state.entities);
90+
});
4591

46-
it('should create a selector for selecting the list of models', () => {
47-
const models = selectors.selectAll(state);
92+
it('should create a selector for selecting the list of models', () => {
93+
const models = selectors.selectAll(state);
4894

49-
expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]);
50-
});
95+
expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]);
96+
});
5197

52-
it('should create a selector for selecting the count of models', () => {
53-
const total = selectors.selectTotal(state);
98+
it('should create a selector for selecting the count of models', () => {
99+
const total = selectors.selectTotal(state);
54100

55-
expect(total).toEqual(3);
101+
expect(total).toEqual(3);
102+
});
56103
});
57104
});

modules/entity/src/models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export type EntitySelectors<T, V> =
8686
export interface EntityAdapter<T> extends EntityStateAdapter<T> {
8787
getInitialState(): EntityState<T>;
8888
getInitialState<S extends object>(state: S): EntityState<T> & S;
89+
getSelectors(): EntitySelectors<T, EntityState<T>>;
8990
getSelectors<V>(
9091
selectState: (state: V) => EntityState<T>
9192
): EntitySelectors<T, V>;

modules/entity/src/state_selectors.ts

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,40 @@ import { createSelector } from '@ngrx/store';
22
import { EntityState, EntitySelectors, Dictionary } from './models';
33

44
export function createSelectorsFactory<T>() {
5-
return {
6-
getSelectors<V>(
7-
selectState: (state: V) => EntityState<T>
8-
): EntitySelectors<T, V> {
9-
const selectIds = (state: any) => state.ids;
10-
const selectEntities = (state: EntityState<T>) => state.entities;
11-
const selectAll = createSelector(
12-
selectIds,
13-
selectEntities,
14-
(ids: T[], entities: Dictionary<T>): any =>
15-
ids.map((id: any) => (entities as any)[id])
16-
);
5+
function getSelectors(): EntitySelectors<T, EntityState<T>>;
6+
function getSelectors<V>(
7+
selectState: (state: V) => EntityState<T>
8+
): EntitySelectors<T, V>;
9+
function getSelectors(
10+
selectState?: (state: any) => EntityState<T>
11+
): EntitySelectors<T, any> {
12+
const selectIds = (state: any) => state.ids;
13+
const selectEntities = (state: EntityState<T>) => state.entities;
14+
const selectAll = createSelector(
15+
selectIds,
16+
selectEntities,
17+
(ids: T[], entities: Dictionary<T>): any =>
18+
ids.map((id: any) => (entities as any)[id])
19+
);
1720

18-
const selectTotal = createSelector(selectIds, ids => ids.length);
21+
const selectTotal = createSelector(selectIds, ids => ids.length);
1922

23+
if (!selectState) {
2024
return {
21-
selectIds: createSelector(selectState, selectIds),
22-
selectEntities: createSelector(selectState, selectEntities),
23-
selectAll: createSelector(selectState, selectAll),
24-
selectTotal: createSelector(selectState, selectTotal),
25+
selectIds,
26+
selectEntities,
27+
selectAll,
28+
selectTotal,
2529
};
26-
},
27-
};
30+
}
31+
32+
return {
33+
selectIds: createSelector(selectState, selectIds),
34+
selectEntities: createSelector(selectState, selectEntities),
35+
selectAll: createSelector(selectState, selectAll),
36+
selectTotal: createSelector(selectState, selectTotal),
37+
};
38+
}
39+
40+
return { getSelectors };
2841
}

0 commit comments

Comments
 (0)