From aae4064f8562b0c97ab34c077608e86d6fe5cbc0 Mon Sep 17 00:00:00 2001 From: Mike Ryan Date: Mon, 16 Oct 2017 21:16:31 -0500 Subject: [PATCH] feat(Entity): Enable creating entity selectors without composing a state selector (#490) --- modules/entity/spec/state_selectors.spec.ts | 109 ++++++++++++++------ modules/entity/src/models.ts | 1 + modules/entity/src/state_selectors.ts | 51 +++++---- 3 files changed, 111 insertions(+), 50 deletions(-) diff --git a/modules/entity/spec/state_selectors.spec.ts b/modules/entity/spec/state_selectors.spec.ts index 0e0a9cb55b..7a2c47db41 100644 --- a/modules/entity/spec/state_selectors.spec.ts +++ b/modules/entity/spec/state_selectors.spec.ts @@ -7,51 +7,98 @@ import { TheGreatGatsby, } from './fixtures/book'; -describe('Entity State', () => { - interface State { - books: EntityState; - } +describe('Entity State Selectors', () => { + describe('Composed Selectors', () => { + interface State { + books: EntityState; + } - let adapter: EntityAdapter; - let selectors: EntitySelectors; - let state: State; + let adapter: EntityAdapter; + let selectors: EntitySelectors; + let state: State; - beforeEach(() => { - adapter = createEntityAdapter({ - selectId: (book: BookModel) => book.id, + beforeEach(() => { + adapter = createEntityAdapter({ + selectId: (book: BookModel) => book.id, + }); + + state = { + books: adapter.addAll( + [AClockworkOrange, AnimalFarm, TheGreatGatsby], + adapter.getInitialState() + ), + }; + + selectors = adapter.getSelectors((state: State) => state.books); + }); + + it('should create a selector for selecting the ids', () => { + const ids = selectors.selectIds(state); + + expect(ids).toEqual(state.books.ids); + }); + + it('should create a selector for selecting the entities', () => { + const entities = selectors.selectEntities(state); + + expect(entities).toEqual(state.books.entities); + }); + + it('should create a selector for selecting the list of models', () => { + const models = selectors.selectAll(state); + + expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]); }); - state = { - books: adapter.addAll( + it('should create a selector for selecting the count of models', () => { + const total = selectors.selectTotal(state); + + expect(total).toEqual(3); + }); + }); + + describe('Uncomposed Selectors', () => { + type State = EntityState; + + let adapter: EntityAdapter; + let selectors: EntitySelectors>; + let state: State; + + beforeEach(() => { + adapter = createEntityAdapter({ + selectId: (book: BookModel) => book.id, + }); + + state = adapter.addAll( [AClockworkOrange, AnimalFarm, TheGreatGatsby], adapter.getInitialState() - ), - }; + ); - selectors = adapter.getSelectors((state: State) => state.books); - }); + selectors = adapter.getSelectors(); + }); - it('should create a selector for selecting the ids', () => { - const ids = selectors.selectIds(state); + it('should create a selector for selecting the ids', () => { + const ids = selectors.selectIds(state); - expect(ids).toEqual(state.books.ids); - }); + expect(ids).toEqual(state.ids); + }); - it('should create a selector for selecting the entities', () => { - const entities = selectors.selectEntities(state); + it('should create a selector for selecting the entities', () => { + const entities = selectors.selectEntities(state); - expect(entities).toEqual(state.books.entities); - }); + expect(entities).toEqual(state.entities); + }); - it('should create a selector for selecting the list of models', () => { - const models = selectors.selectAll(state); + it('should create a selector for selecting the list of models', () => { + const models = selectors.selectAll(state); - expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]); - }); + expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby]); + }); - it('should create a selector for selecting the count of models', () => { - const total = selectors.selectTotal(state); + it('should create a selector for selecting the count of models', () => { + const total = selectors.selectTotal(state); - expect(total).toEqual(3); + expect(total).toEqual(3); + }); }); }); diff --git a/modules/entity/src/models.ts b/modules/entity/src/models.ts index d1ba0692b9..7e8802261d 100644 --- a/modules/entity/src/models.ts +++ b/modules/entity/src/models.ts @@ -86,6 +86,7 @@ export type EntitySelectors = export interface EntityAdapter extends EntityStateAdapter { getInitialState(): EntityState; getInitialState(state: S): EntityState & S; + getSelectors(): EntitySelectors>; getSelectors( selectState: (state: V) => EntityState ): EntitySelectors; diff --git a/modules/entity/src/state_selectors.ts b/modules/entity/src/state_selectors.ts index 8d8f1affdc..b34a4fd8a0 100644 --- a/modules/entity/src/state_selectors.ts +++ b/modules/entity/src/state_selectors.ts @@ -2,27 +2,40 @@ import { createSelector } from '@ngrx/store'; import { EntityState, EntitySelectors, Dictionary } from './models'; export function createSelectorsFactory() { - return { - getSelectors( - selectState: (state: V) => EntityState - ): EntitySelectors { - const selectIds = (state: any) => state.ids; - const selectEntities = (state: EntityState) => state.entities; - const selectAll = createSelector( - selectIds, - selectEntities, - (ids: T[], entities: Dictionary): any => - ids.map((id: any) => (entities as any)[id]) - ); + function getSelectors(): EntitySelectors>; + function getSelectors( + selectState: (state: V) => EntityState + ): EntitySelectors; + function getSelectors( + selectState?: (state: any) => EntityState + ): EntitySelectors { + const selectIds = (state: any) => state.ids; + const selectEntities = (state: EntityState) => state.entities; + const selectAll = createSelector( + selectIds, + selectEntities, + (ids: T[], entities: Dictionary): any => + ids.map((id: any) => (entities as any)[id]) + ); - const selectTotal = createSelector(selectIds, ids => ids.length); + const selectTotal = createSelector(selectIds, ids => ids.length); + if (!selectState) { return { - selectIds: createSelector(selectState, selectIds), - selectEntities: createSelector(selectState, selectEntities), - selectAll: createSelector(selectState, selectAll), - selectTotal: createSelector(selectState, selectTotal), + selectIds, + selectEntities, + selectAll, + selectTotal, }; - }, - }; + } + + return { + selectIds: createSelector(selectState, selectIds), + selectEntities: createSelector(selectState, selectEntities), + selectAll: createSelector(selectState, selectAll), + selectTotal: createSelector(selectState, selectTotal), + }; + } + + return { getSelectors }; }