Skip to content

Commit

Permalink
fix: ids key is optional
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed Jan 6, 2021
1 parent 7fc6706 commit 5d53a2d
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 4 deletions.
85 changes: 85 additions & 0 deletions libs/ngrx-entity-relationship/e2e/custom-keys-for-entities.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
ngrxEntityRelationshipReducer,
reduceGraph,
relatedEntitySelector,
rootEntitySelector,
stateKeys,
} from 'ngrx-entity-relationship';

describe('custom-keys-for-entities', () => {
interface Item {
id: string;
name: string;
parentId?: string;
parent?: Item;
}

const state: {
records: {
ids: Array<string>;
byId: Record<string, Item | undefined>;
};
} = {
records: {
ids: [],
byId: {},
},
};

const selectItemsState = (s: typeof state) => s.records;
const featureSelector = stateKeys(selectItemsState, 'byId');

const sItem = rootEntitySelector(featureSelector);
const sItemParent = relatedEntitySelector(featureSelector, 'parentId', 'parent');

const selector = sItem(sItemParent());

it('handles custom values correctly', () => {
const action = reduceGraph({
data: [
{
id: 'i1',
name: '1',
parentId: 'i2',
parent: {
id: 'i2',
name: '2',
},
},
],
selector,
});

const reducer = ngrxEntityRelationshipReducer<typeof state>(((s: typeof state) => s) as any);
const testingState = reducer(state, action);

// data has been reduced.
expect(testingState).toEqual({
records: {
ids: ['i1', 'i2'],
byId: {
i1: {
id: 'i1',
name: '1',
parentId: 'i2',
},
i2: {
id: 'i2',
name: '2',
},
},
},
});

// data has been reached.
expect(selector(testingState, 'i1')).toEqual({
id: 'i1',
name: '1',
parentId: 'i2',
parent: {
id: 'i2',
name: '2',
},
});
});
});
82 changes: 82 additions & 0 deletions libs/ngrx-entity-relationship/e2e/custom-keys-no-id.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {
ngrxEntityRelationshipReducer,
reduceGraph,
relatedEntitySelector,
rootEntitySelector,
stateKeys,
} from 'ngrx-entity-relationship';

describe('custom-keys-no-id', () => {
interface Item {
id: string;
name: string;
parentId?: string;
parent?: Item;
}

const state: {
records: {
byId: Record<string, Item | undefined>;
};
} = {
records: {
byId: {},
},
};

const selectItemsState = (s: typeof state) => s.records;
const featureSelector = stateKeys(selectItemsState, 'byId');

const sItem = rootEntitySelector(featureSelector);
const sItemParent = relatedEntitySelector(featureSelector, 'parentId', 'parent');

const selector = sItem(sItemParent());

it('handles custom values correctly', () => {
const action = reduceGraph({
data: [
{
id: 'i1',
name: '1',
parentId: 'i2',
parent: {
id: 'i2',
name: '2',
},
},
],
selector,
});

const reducer = ngrxEntityRelationshipReducer<typeof state>(((s: typeof state) => s) as any);
const testingState = reducer(state, action);

// data has been reduced.
expect(testingState).toEqual({
records: {
byId: {
i1: {
id: 'i1',
name: '1',
parentId: 'i2',
},
i2: {
id: 'i2',
name: '2',
},
},
},
});

// data has been reached.
expect(selector(testingState, 'i1')).toEqual({
id: 'i1',
name: '1',
parentId: 'i2',
parent: {
id: 'i2',
name: '2',
},
});
});
});
21 changes: 19 additions & 2 deletions libs/ngrx-entity-relationship/src/lib/stateKeys.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
import {ENTITY_STATE, ENTITY_STATE_CUSTOM, STORE_SELECTOR} from './types';

export function stateKeys<
SELECTOR extends STORE_SELECTOR<any, any>,
STORE extends SELECTOR extends STORE_SELECTOR<infer U, any> ? U : never,
SLICE extends SELECTOR extends STORE_SELECTOR<any, infer U> ? U : never,
E_KEY extends keyof SLICE,
ENTITY extends SLICE extends ENTITY_STATE_CUSTOM<E_KEY, 'ids', infer U> ? U : never
>(selector: SELECTOR, entitiesKey: E_KEY): STORE_SELECTOR<STORE, ENTITY_STATE<ENTITY>>;

export function stateKeys<
SELECTOR extends STORE_SELECTOR<any, any>,
STORE extends SELECTOR extends STORE_SELECTOR<infer U, any> ? U : never,
SLICE extends SELECTOR extends STORE_SELECTOR<any, infer U> ? U : never,
E_KEY extends keyof SLICE,
I_KEY extends keyof SLICE,
ENTITY extends SLICE extends ENTITY_STATE_CUSTOM<E_KEY, I_KEY, infer U> ? U : never
>(selector: SELECTOR, entitiesKey: E_KEY, idsKey: I_KEY): STORE_SELECTOR<STORE, ENTITY_STATE<ENTITY>>;

export function stateKeys<
SELECTOR extends STORE_SELECTOR<any, any>,
STORE extends SELECTOR extends STORE_SELECTOR<infer U, any> ? U : never,
SLICE extends SELECTOR extends STORE_SELECTOR<any, infer U> ? U : never,
E_KEY extends keyof SLICE,
I_KEY extends keyof SLICE,
ENTITY extends SLICE extends ENTITY_STATE_CUSTOM<E_KEY, I_KEY, infer U> ? U : never
>(selector: SELECTOR, entitiesKey: E_KEY, idsKey: I_KEY): STORE_SELECTOR<STORE, ENTITY_STATE<ENTITY>> {
>(selector: SELECTOR, entitiesKey: E_KEY, idsKey?: I_KEY): STORE_SELECTOR<STORE, ENTITY_STATE<ENTITY>> {
const callback: STORE_SELECTOR<STORE, ENTITY_STATE<ENTITY>> = (s: STORE): ENTITY_STATE<ENTITY> => {
const slice = selector(s);
return {
ids: slice[idsKey],
ids: idsKey ? slice[idsKey] : slice.ids,
entities: slice[entitiesKey],
};
};
Expand Down
4 changes: 2 additions & 2 deletions libs/ngrx-entity-relationship/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export type ENTITY_STATE_CUSTOM<EK extends keyof any, IK extends keyof any, ENTI
};
} &
{
[key in IK]: Array<ID_TYPES>;
[key in IK]?: Array<ID_TYPES>;
};

export interface ENTITY_STATE<E> {
ids: Array<ID_TYPES>;
ids?: Array<ID_TYPES>;
entities: {
[id in ID_TYPES]?: E;
};
Expand Down

0 comments on commit 5d53a2d

Please sign in to comment.