Skip to content

Commit

Permalink
feat(entity): log a warning message when selectId returns undefined i…
Browse files Browse the repository at this point in the history
…n dev mode (#1169)

Closes #1133
  • Loading branch information
timdeschryver authored and brandonroberts committed Jul 16, 2018
1 parent 28e2cc9 commit 8f05f1f
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
57 changes: 57 additions & 0 deletions modules/entity/spec/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as ngCore from '@angular/core';
import { selectIdValue } from '../src/utils';
import { BookModel, AClockworkOrange } from './fixtures/book';

describe('Entity utils', () => {
describe(`selectIdValue()`, () => {
it('should not warn when key does exist', () => {
const spy = spyOn(console, 'warn');

const key = selectIdValue(AClockworkOrange, book => book.id);

expect(spy).not.toHaveBeenCalled();
});

it('should warn when key does not exist in dev mode', () => {
const spy = spyOn(console, 'warn');

const key = selectIdValue(AClockworkOrange, (book: any) => book.foo);

expect(spy).toHaveBeenCalled();
});

it('should warn when key is undefined in dev mode', () => {
const spy = spyOn(console, 'warn');

const undefinedAClockworkOrange = { ...AClockworkOrange, id: undefined };
const key = selectIdValue(
undefinedAClockworkOrange,
(book: any) => book.id
);

expect(spy).toHaveBeenCalled();
});

it('should not warn when key does not exist in prod mode', () => {
spyOn(ngCore, 'isDevMode').and.returnValue(false);
const spy = spyOn(console, 'warn');

const key = selectIdValue(AClockworkOrange, (book: any) => book.foo);

expect(spy).not.toHaveBeenCalled();
});

it('should not warn when key is undefined in prod mode', () => {
spyOn(ngCore, 'isDevMode').and.returnValue(false);
const spy = spyOn(console, 'warn');

const undefinedAClockworkOrange = { ...AClockworkOrange, id: undefined };
const key = selectIdValue(
undefinedAClockworkOrange,
(book: any) => book.id
);

expect(spy).not.toHaveBeenCalled();
});
});
});
9 changes: 5 additions & 4 deletions modules/entity/src/sorted_state_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from './models';
import { createStateOperator, DidMutate } from './state_adapter';
import { createUnsortedStateAdapter } from './unsorted_state_adapter';
import { selectIdValue } from './utils';

export function createSortedStateAdapter<T>(
selectId: IdSelector<T>,
Expand All @@ -28,7 +29,7 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
function addManyMutably(newModels: T[], state: R): DidMutate;
function addManyMutably(newModels: any[], state: any): DidMutate {
const models = newModels.filter(
model => !(selectId(model) in state.entities)
model => !(selectIdValue(model, selectId) in state.entities)
);

if (models.length === 0) {
Expand Down Expand Up @@ -62,7 +63,7 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {

const original = state.entities[update.id];
const updated = Object.assign({}, original, update.changes);
const newKey = selectId(updated);
const newKey = selectIdValue(updated, selectId);

delete state.entities[update.id];

Expand Down Expand Up @@ -117,7 +118,7 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
const updated: any[] = [];

for (const entity of entities) {
const id = selectId(entity);
const id = selectIdValue(entity, selectId);
if (id in state.entities) {
updated.push({ id, changes: entity });
} else {
Expand Down Expand Up @@ -151,7 +152,7 @@ export function createSortedStateAdapter<T>(selectId: any, sort: any): any {

while (i < models.length && j < state.ids.length) {
const model = models[i];
const modelId = selectId(model);
const modelId = selectIdValue(model, selectId);
const entityId = state.ids[j];
const entity = state.entities[entityId];

Expand Down
7 changes: 4 additions & 3 deletions modules/entity/src/unsorted_state_adapter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EntityState, EntityStateAdapter, IdSelector, Update } from './models';
import { createStateOperator, DidMutate } from './state_adapter';
import { selectIdValue } from './utils';

export function createUnsortedStateAdapter<T>(
selectId: IdSelector<T>
Expand All @@ -9,7 +10,7 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {

function addOneMutably(entity: T, state: R): DidMutate;
function addOneMutably(entity: any, state: any): DidMutate {
const key = selectId(entity);
const key = selectIdValue(entity, selectId);

if (key in state.entities) {
return DidMutate.None;
Expand Down Expand Up @@ -81,7 +82,7 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
): boolean {
const original = state.entities[update.id];
const updated: T = Object.assign({}, original, update.changes);
const newKey = selectId(updated);
const newKey = selectIdValue(updated, selectId);
const hasNewKey = newKey !== update.id;

if (hasNewKey) {
Expand Down Expand Up @@ -133,7 +134,7 @@ export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
const updated: any[] = [];

for (const entity of entities) {
const id = selectId(entity);
const id = selectIdValue(entity, selectId);
if (id in state.entities) {
updated.push({ id, changes: entity });
} else {
Expand Down
19 changes: 19 additions & 0 deletions modules/entity/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { isDevMode } from '@angular/core';
import { IdSelector } from './models';

export function selectIdValue<T>(entity: T, selectId: IdSelector<T>) {
const key = selectId(entity);

if (isDevMode() && key === undefined) {
console.warn(
'@ngrx/entity: The entity passed to the `selectId` implementation returned undefined.',
'You should probably provide your own `selectId` implementation.',
'The entity that was passed:',
entity,
'The `selectId` implementation:',
selectId.toString()
);
}

return key;
}

0 comments on commit 8f05f1f

Please sign in to comment.