Skip to content

Commit 46d6f2f

Browse files
brandonrobertsMikeRyanDev
authored andcommitted
feat(Entity): Add support for string or number type for ID (#441)
1 parent b80aa6e commit 46d6f2f

File tree

6 files changed

+107
-34
lines changed

6 files changed

+107
-34
lines changed

modules/entity/src/entity_state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EntityState } from './models';
1+
import { EntityState, EntityStateStr, EntityStateNum } from './models';
22

33
export function getInitialEntityState<V>(): EntityState<V> {
44
return {

modules/entity/src/models.ts

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,57 @@
1-
export type Comparer<T> = {
1+
export type ComparerStr<T> = {
2+
(a: T, b: T): string;
3+
};
4+
5+
export type ComparerNum<T> = {
26
(a: T, b: T): number;
37
};
48

5-
export type IdSelector<T> = {
9+
export type Comparer<T> = ComparerNum<T> | ComparerStr<T>;
10+
11+
export type IdSelectorStr<T> = {
612
(model: T): string;
713
};
814

9-
export type Dictionary<T> = {
15+
export type IdSelectorNum<T> = {
16+
(model: T): number;
17+
};
18+
19+
export type IdSelector<T> = IdSelectorStr<T> | IdSelectorNum<T>;
20+
21+
export type DictionaryStr<T> = {
1022
[id: string]: T;
1123
};
1224

13-
export type Update<T> = {
25+
export type DictionaryNum<T> = {
26+
[id: number]: T;
27+
};
28+
29+
export type Dictionary<T> = DictionaryStr<T> | DictionaryNum<T>;
30+
31+
export type UpdateStr<T> = {
1432
id: string;
1533
changes: Partial<T>;
1634
};
1735

18-
export interface EntityState<T> {
36+
export type UpdateNum<T> = {
37+
id: number;
38+
changes: Partial<T>;
39+
};
40+
41+
export type Update<T> = UpdateStr<T> | UpdateNum<T>;
42+
43+
export interface EntityStateStr<T> {
1944
ids: string[];
2045
entities: Dictionary<T>;
2146
}
2247

48+
export interface EntityStateNum<T> {
49+
ids: number[];
50+
entities: Dictionary<T>;
51+
}
52+
53+
export type EntityState<T> = EntityStateStr<T> | EntityStateNum<T>;
54+
2355
export interface EntityDefinition<T> {
2456
selectId: IdSelector<T>;
2557
sortComparer: false | Comparer<T>;
@@ -31,20 +63,35 @@ export interface EntityStateAdapter<T> {
3163
addAll<S extends EntityState<T>>(entities: T[], state: S): S;
3264

3365
removeOne<S extends EntityState<T>>(key: string, state: S): S;
66+
removeOne<S extends EntityState<T>>(key: number, state: S): S;
67+
3468
removeMany<S extends EntityState<T>>(keys: string[], state: S): S;
69+
removeMany<S extends EntityState<T>>(keys: number[], state: S): S;
70+
3571
removeAll<S extends EntityState<T>>(state: S): S;
3672

3773
updateOne<S extends EntityState<T>>(update: Update<T>, state: S): S;
3874
updateMany<S extends EntityState<T>>(updates: Update<T>[], state: S): S;
3975
}
4076

41-
export type EntitySelectors<T, V> = {
42-
selectIds: (state: V) => string[];
77+
export type EntitySelectorsBase<T, V> = {
4378
selectEntities: (state: V) => Dictionary<T>;
4479
selectAll: (state: V) => T[];
4580
selectTotal: (state: V) => number;
4681
};
4782

83+
export interface EntitySelectorsStr<T, V> extends EntitySelectorsBase<T, V> {
84+
selectIds: (state: V) => string[];
85+
}
86+
87+
export interface EntitySelectorsNum<T, V> extends EntitySelectorsBase<T, V> {
88+
selectIds: (state: V) => number[];
89+
}
90+
91+
export type EntitySelectors<T, V> =
92+
| EntitySelectorsNum<T, V>
93+
| EntitySelectorsStr<T, V>;
94+
4895
export interface EntityAdapter<T> extends EntityStateAdapter<T> {
4996
getInitialState(): EntityState<T>;
5097
getInitialState<S extends object>(state: S): EntityState<T> & S;

modules/entity/src/sorted_state_adapter.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,30 @@ import { createUnsortedStateAdapter } from './unsorted_state_adapter';
1212
export function createSortedStateAdapter<T>(
1313
selectId: IdSelector<T>,
1414
sort: Comparer<T>
15-
): EntityStateAdapter<T> {
15+
): EntityStateAdapter<T>;
16+
export function createSortedStateAdapter<T>(selectId: any, sort: any): any {
1617
type R = EntityState<T>;
1718

1819
const { removeOne, removeMany, removeAll } = createUnsortedStateAdapter(
1920
selectId
2021
);
2122

22-
function addOneMutably(entity: T, state: R): boolean {
23+
function addOneMutably(entity: T, state: R): boolean;
24+
function addOneMutably(entity: any, state: any): boolean {
2325
return addManyMutably([entity], state);
2426
}
2527

26-
function addManyMutably(newModels: T[], state: R): boolean {
28+
function addManyMutably(newModels: T[], state: R): boolean;
29+
function addManyMutably(newModels: any[], state: any): boolean {
2730
const models = newModels.filter(
2831
model => !(selectId(model) in state.entities)
2932
);
3033

3134
return merge(models, state);
3235
}
3336

34-
function addAllMutably(models: T[], state: R): boolean {
37+
function addAllMutably(models: T[], state: R): boolean;
38+
function addAllMutably(models: any[], state: any): boolean {
3539
state.entities = {};
3640
state.ids = [];
3741

@@ -40,11 +44,13 @@ export function createSortedStateAdapter<T>(
4044
return true;
4145
}
4246

43-
function updateOneMutably(update: Update<T>, state: R): boolean {
47+
function updateOneMutably(update: Update<T>, state: R): boolean;
48+
function updateOneMutably(update: any, state: any): boolean {
4449
return updateManyMutably([update], state);
4550
}
4651

47-
function takeUpdatedModel(models: T[], update: Update<T>, state: R): void {
52+
function takeUpdatedModel(models: T[], update: Update<T>, state: R): void;
53+
function takeUpdatedModel(models: any[], update: any, state: any): void {
4854
if (!(update.id in state.entities)) {
4955
return;
5056
}
@@ -57,26 +63,28 @@ export function createSortedStateAdapter<T>(
5763
models.push(updated);
5864
}
5965

60-
function updateManyMutably(updates: Update<T>[], state: R): boolean {
66+
function updateManyMutably(updates: Update<T>[], state: R): boolean;
67+
function updateManyMutably(updates: any[], state: any): boolean {
6168
const models: T[] = [];
6269

6370
updates.forEach(update => takeUpdatedModel(models, update, state));
6471

6572
if (models.length) {
66-
state.ids = state.ids.filter(id => id in state.entities);
73+
state.ids = state.ids.filter((id: any) => id in state.entities);
6774
}
6875

6976
return merge(models, state);
7077
}
7178

72-
function merge(models: T[], state: R): boolean {
79+
function merge(models: T[], state: R): boolean;
80+
function merge(models: any[], state: any): boolean {
7381
if (models.length === 0) {
7482
return false;
7583
}
7684

7785
models.sort(sort);
7886

79-
const ids: string[] = [];
87+
const ids: any[] = [];
8088

8189
let i = 0;
8290
let j = 0;

modules/entity/src/state_adapter.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import { EntityState, EntityStateAdapter } from './models';
22

33
export function createStateOperator<V, R>(
44
mutator: (arg: R, state: EntityState<V>) => boolean
5-
) {
6-
return function operation<S extends EntityState<V>>(arg: R, state: S): S {
5+
): EntityState<V>;
6+
export function createStateOperator<V, R>(
7+
mutator: (arg: any, state: any) => boolean
8+
): any {
9+
return function operation<S extends EntityState<V>>(arg: R, state: any): S {
710
const clonedEntityState: EntityState<V> = {
811
ids: [...state.ids],
912
entities: { ...state.entities },

modules/entity/src/state_selectors.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { createSelector } from '@ngrx/store';
2-
import { EntityState, EntitySelectors } from './models';
2+
import { EntityState, EntitySelectors, Dictionary } from './models';
33

44
export function createSelectorsFactory<T>() {
55
return {
66
getSelectors<V>(
77
selectState: (state: V) => EntityState<T>
88
): EntitySelectors<T, V> {
9-
const selectIds = (state: EntityState<T>) => state.ids;
9+
const selectIds = (state: any) => state.ids;
1010
const selectEntities = (state: EntityState<T>) => state.entities;
1111
const selectAll = createSelector(
1212
selectIds,
1313
selectEntities,
14-
(ids, entities) => ids.map(id => entities[id])
14+
(ids: T[], entities: Dictionary<T>): any =>
15+
ids.map((id: any) => (entities as any)[id])
1516
);
1617

1718
const selectTotal = createSelector(selectIds, ids => ids.length);

modules/entity/src/unsorted_state_adapter.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { createStateOperator } from './state_adapter';
33

44
export function createUnsortedStateAdapter<T>(
55
selectId: IdSelector<T>
6-
): EntityStateAdapter<T> {
6+
): EntityStateAdapter<T>;
7+
export function createUnsortedStateAdapter<T>(selectId: IdSelector<T>): any {
78
type R = EntityState<T>;
89

9-
function addOneMutably(entity: T, state: R): boolean {
10+
function addOneMutably(entity: T, state: R): boolean;
11+
function addOneMutably(entity: any, state: any): boolean {
1012
const key = selectId(entity);
1113

1214
if (key in state.entities) {
@@ -19,7 +21,8 @@ export function createUnsortedStateAdapter<T>(
1921
return true;
2022
}
2123

22-
function addManyMutably(entities: T[], state: R): boolean {
24+
function addManyMutably(entities: T[], state: R): boolean;
25+
function addManyMutably(entities: any[], state: any): boolean {
2326
let didMutate = false;
2427

2528
for (let index in entities) {
@@ -29,7 +32,8 @@ export function createUnsortedStateAdapter<T>(
2932
return didMutate;
3033
}
3134

32-
function addAllMutably(entities: T[], state: R): boolean {
35+
function addAllMutably(entities: T[], state: R): boolean;
36+
function addAllMutably(entities: any[], state: any): boolean {
3337
state.ids = [];
3438
state.entities = {};
3539

@@ -38,24 +42,27 @@ export function createUnsortedStateAdapter<T>(
3842
return true;
3943
}
4044

41-
function removeOneMutably(key: string, state: R): boolean {
45+
function removeOneMutably(key: T, state: R): boolean;
46+
function removeOneMutably(key: any, state: any): boolean {
4247
return removeManyMutably([key], state);
4348
}
4449

45-
function removeManyMutably(keys: string[], state: R): boolean {
50+
function removeManyMutably(keys: T[], state: R): boolean;
51+
function removeManyMutably(keys: any[], state: any): boolean {
4652
const didMutate =
4753
keys
4854
.filter(key => key in state.entities)
4955
.map(key => delete state.entities[key]).length > 0;
5056

5157
if (didMutate) {
52-
state.ids = state.ids.filter(id => id in state.entities);
58+
state.ids = state.ids.filter((id: any) => id in state.entities);
5359
}
5460

5561
return didMutate;
5662
}
5763

58-
function removeAll<S extends R>(state: S): S {
64+
function removeAll<S extends R>(state: S): S;
65+
function removeAll<S extends R>(state: any): S {
5966
return Object.assign({}, state, {
6067
ids: [],
6168
entities: {},
@@ -66,6 +73,11 @@ export function createUnsortedStateAdapter<T>(
6673
keys: { [id: string]: string },
6774
update: Update<T>,
6875
state: R
76+
): void;
77+
function takeNewKey(
78+
keys: { [id: string]: any },
79+
update: Update<T>,
80+
state: any
6981
): void {
7082
const original = state.entities[update.id];
7183
const updated: T = Object.assign({}, original, update.changes);
@@ -79,11 +91,13 @@ export function createUnsortedStateAdapter<T>(
7991
state.entities[newKey] = updated;
8092
}
8193

82-
function updateOneMutably(update: Update<T>, state: R): boolean {
94+
function updateOneMutably(update: Update<T>, state: R): boolean;
95+
function updateOneMutably(update: any, state: any): boolean {
8396
return updateManyMutably([update], state);
8497
}
8598

86-
function updateManyMutably(updates: Update<T>[], state: R): boolean {
99+
function updateManyMutably(updates: Update<T>[], state: R): boolean;
100+
function updateManyMutably(updates: any[], state: any): boolean {
87101
const newKeys: { [id: string]: string } = {};
88102

89103
const didMutate =
@@ -92,7 +106,7 @@ export function createUnsortedStateAdapter<T>(
92106
.map(update => takeNewKey(newKeys, update, state)).length > 0;
93107

94108
if (didMutate) {
95-
state.ids = state.ids.map(id => newKeys[id] || id);
109+
state.ids = state.ids.map((id: any) => newKeys[id] || id);
96110
}
97111

98112
return didMutate;

0 commit comments

Comments
 (0)