Skip to content

Commit

Permalink
feat(Entity): Enable creating entity selectors without composing a st…
Browse files Browse the repository at this point in the history
…ate selector (#490)
  • Loading branch information
MikeRyanDev authored and brandonroberts committed Oct 17, 2017
1 parent 8728bc1 commit aae4064
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 50 deletions.
109 changes: 78 additions & 31 deletions modules/entity/spec/state_selectors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,98 @@ import {
TheGreatGatsby,
} from './fixtures/book';

describe('Entity State', () => {
interface State {
books: EntityState<BookModel>;
}
describe('Entity State Selectors', () => {
describe('Composed Selectors', () => {
interface State {
books: EntityState<BookModel>;
}

let adapter: EntityAdapter<BookModel>;
let selectors: EntitySelectors<BookModel, State>;
let state: State;
let adapter: EntityAdapter<BookModel>;
let selectors: EntitySelectors<BookModel, State>;
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<BookModel>;

let adapter: EntityAdapter<BookModel>;
let selectors: EntitySelectors<BookModel, EntityState<BookModel>>;
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);
});
});
});
1 change: 1 addition & 0 deletions modules/entity/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export type EntitySelectors<T, V> =
export interface EntityAdapter<T> extends EntityStateAdapter<T> {
getInitialState(): EntityState<T>;
getInitialState<S extends object>(state: S): EntityState<T> & S;
getSelectors(): EntitySelectors<T, EntityState<T>>;
getSelectors<V>(
selectState: (state: V) => EntityState<T>
): EntitySelectors<T, V>;
Expand Down
51 changes: 32 additions & 19 deletions modules/entity/src/state_selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,40 @@ import { createSelector } from '@ngrx/store';
import { EntityState, EntitySelectors, Dictionary } from './models';

export function createSelectorsFactory<T>() {
return {
getSelectors<V>(
selectState: (state: V) => EntityState<T>
): EntitySelectors<T, V> {
const selectIds = (state: any) => state.ids;
const selectEntities = (state: EntityState<T>) => state.entities;
const selectAll = createSelector(
selectIds,
selectEntities,
(ids: T[], entities: Dictionary<T>): any =>
ids.map((id: any) => (entities as any)[id])
);
function getSelectors(): EntitySelectors<T, EntityState<T>>;
function getSelectors<V>(
selectState: (state: V) => EntityState<T>
): EntitySelectors<T, V>;
function getSelectors(
selectState?: (state: any) => EntityState<T>
): EntitySelectors<T, any> {
const selectIds = (state: any) => state.ids;
const selectEntities = (state: EntityState<T>) => state.entities;
const selectAll = createSelector(
selectIds,
selectEntities,
(ids: T[], entities: Dictionary<T>): 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 };
}

0 comments on commit aae4064

Please sign in to comment.