Skip to content

Commit

Permalink
feat(Store): createSelector with only a props selector
Browse files Browse the repository at this point in the history
  • Loading branch information
timdeschryver authored and brandonroberts committed Jul 27, 2018
1 parent 53832a1 commit 35a4848
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
32 changes: 32 additions & 0 deletions modules/store/spec/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,38 @@ describe('ngRx Integration spec', () => {
});

it('should use props to get a todo', () => {
const getTodosById = createSelector(
(state: TodoAppSchema, id: number) => {
return state.todos.find(p => p.id === id);
}
);

let testCase = 1;
const todo$ = store.pipe(select(getTodosById, 2));
todo$.subscribe(todo => {
if (testCase === 1) {
expect(todo).toEqual(undefined);
} else if (testCase === 2) {
expect(todo).toEqual({
id: 2,
text: 'second todo',
completed: false,
});
} else if (testCase === 3) {
expect(todo).toEqual({ id: 2, text: 'second todo', completed: true });
}
testCase++;
});

store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } });
store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } });
store.dispatch({
type: COMPLETE_TODO,
payload: { id: 2 },
});
});

it('should use the selector and props to get a todo', () => {
const getTodosState = createFeatureSelector<TodoAppSchema, Todo[]>(
'todos'
);
Expand Down
45 changes: 45 additions & 0 deletions modules/store/spec/selector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,51 @@ describe('Selectors', () => {
});
});

describe('createSelector with only a props selector', () => {
it('should deliver the state and the props to the projection function', () => {
const projectFn = jasmine.createSpy('projectionFn');
const state = { counter: {} };
const props = { value: 47 };
const selector = createSelector(projectFn)(state, props);
expect(projectFn).toHaveBeenCalledWith(state, props);
});

it('should be possible to use a projector fn', () => {
const projectFn = jasmine.createSpy('projectionFn');
const selector = createSelector(projectFn);
selector.projector('foo', 'bar');
expect(projectFn).toHaveBeenCalledWith('foo', 'bar');
});

it('should call the projector function when the state changes', () => {
const projectFn = jasmine.createSpy('projectionFn');
const selector = createSelector(projectFn);

const firstState = { first: 'state' };
const secondState = { second: 'state' };
const props = { foo: 'props' };
selector(firstState, props);
selector(firstState, props);
selector(secondState, props);
expect(projectFn).toHaveBeenCalledTimes(2);
});

it('should allow you to release memoized arguments', () => {
const state = { first: 'state' };
const props = { first: 'props' };
const projectFn = jasmine.createSpy('projectionFn');
const selector = createSelector(projectFn);

selector(state, props);
selector(state, props);
selector.release();
selector(state, props);
selector(state, props);

expect(projectFn).toHaveBeenCalledTimes(2);
});
});

describe('createSelector with arrays', () => {
it('should deliver the value of selectors to the projection function', () => {
const projectFn = jasmine.createSpy('projectionFn');
Expand Down
10 changes: 10 additions & 0 deletions modules/store/src/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ export function createSelector<
) => Result
): MemoizedSelectorWithProps<State, Props, Result>;

export function createSelector<State, Props, Result>(
projector: SelectorWithProps<State, Props, Result>
): MemoizedSelectorWithProps<State, Props, Result>;

export function createSelector(
...input: any[]
): Selector<any, any> | SelectorWithProps<any, any, any> {
Expand Down Expand Up @@ -501,6 +505,12 @@ export function createSelectorFactory(
});

const memoizedState = defaultMemoize(function(state: any, props: any) {
// createSelector works directly on state
// e.g. createSelector((state, props) => ...)
if (selectors.length === 0) {
return projector.apply(null, [state, props]);
}

return options.stateFn.apply(null, [
state,
selectors,
Expand Down

0 comments on commit 35a4848

Please sign in to comment.