- commit
- 059dd3b
- parent
- 098b864
- author
- Eric Bower
- date
- 2023-12-01 22:16:34 +0000 UTC
refactor(store): `slice.table` `empty` is now optional (#28)
2 files changed,
+73,
-25
+16,
-0
1@@ -112,3 +112,19 @@ it(tests, "gets all rows", async () => {
2 });
3 asserts.assertEquals(store.getState()[NAME], data);
4 });
5+
6+it(tests, "optional empty", async () => {
7+ const tbl = createTable<TUser>({ name: "table" });
8+ const store = configureStore({
9+ initialState,
10+ });
11+
12+ await store.run(function* () {
13+ yield* updateStore(tbl.set({ [first.id]: first }));
14+ });
15+ asserts.assertEquals(tbl.selectTable(store.getState()), {
16+ [first.id]: first,
17+ });
18+ const result = tbl.selectById(store.getState(), { id: 1 });
19+ asserts.assertEquals(result, first);
20+});
+57,
-25
1@@ -35,27 +35,14 @@ function mustSelectEntity<Entity extends AnyState = AnyState>(
2 };
3 }
4
5-interface TableSelectors<
6- Entity extends AnyState = AnyState,
7- S extends AnyState = AnyState,
8-> {
9- findById: (d: Record<IdProp, Entity>, { id }: PropId) => Entity;
10- findByIds: (d: Record<IdProp, Entity>, { ids }: PropIds) => Entity[];
11- tableAsList: (d: Record<IdProp, Entity>) => Entity[];
12- selectTable: (s: S) => Record<IdProp, Entity>;
13- selectTableAsList: (state: S) => Entity[];
14- selectById: (s: S, p: PropId) => Entity;
15- selectByIds: (s: S, p: PropIds) => Entity[];
16-}
17-
18 function tableSelectors<
19 Entity extends AnyState = AnyState,
20 S extends AnyState = AnyState,
21 >(
22 selectTable: (s: S) => Record<IdProp, Entity>,
23- empty: Entity | (() => Entity),
24-): TableSelectors<Entity, S> {
25- const must = mustSelectEntity(empty);
26+ empty?: Entity | (() => Entity) | undefined,
27+) {
28+ const must = empty ? mustSelectEntity(empty) : null;
29 const tableAsList = (data: Record<IdProp, Entity>): Entity[] =>
30 Object.values(data).filter(excludesFalse);
31 const findById = (data: Record<IdProp, Entity>, { id }: PropId) => data[id];
32@@ -63,13 +50,18 @@ function tableSelectors<
33 data: Record<IdProp, Entity>,
34 { ids }: PropIds,
35 ): Entity[] => ids.map((id) => data[id]).filter(excludesFalse);
36- const selectById = (state: S, { id }: PropId): Entity | undefined => {
37+ const selectById = (
38+ state: S,
39+ { id }: PropId,
40+ ): typeof empty extends undefined ? (Entity | undefined) : Entity => {
41 const data = selectTable(state);
42 return findById(data, { id });
43 };
44
45+ const sbi = must ? must(selectById) : selectById;
46+
47 return {
48- findById: must(findById),
49+ findById: must ? must(findById) : findById,
50 findByIds,
51 tableAsList,
52 selectTable,
53@@ -77,7 +69,7 @@ function tableSelectors<
54 selectTable,
55 (data): Entity[] => tableAsList(data),
56 ),
57- selectById: must(selectById),
58+ selectById: sbi,
59 selectByIds: createSelector(
60 selectTable,
61 (_: S, p: PropIds) => p,
62@@ -86,8 +78,11 @@ function tableSelectors<
63 };
64 }
65
66-export interface TableOutput<Entity extends AnyState, S extends AnyState>
67- extends TableSelectors<Entity, S>, BaseSchema<Record<IdProp, Entity>> {
68+export interface TableOutput<
69+ Entity extends AnyState,
70+ S extends AnyState,
71+ Empty extends Entity | undefined = Entity | undefined,
72+> extends BaseSchema<Record<IdProp, Entity>> {
73 schema: "table";
74 initialState: Record<IdProp, Entity>;
75 add: (e: Record<IdProp, Entity>) => (s: S) => void;
76@@ -96,9 +91,22 @@ export interface TableOutput<Entity extends AnyState, S extends AnyState>
77 patch: (e: PatchEntity<Record<IdProp, Entity>>) => (s: S) => void;
78 merge: (e: PatchEntity<Record<IdProp, Entity>>) => (s: S) => void;
79 reset: () => (s: S) => void;
80+ findById: (
81+ d: Record<IdProp, Entity>,
82+ { id }: PropId,
83+ ) => Empty;
84+ findByIds: (d: Record<IdProp, Entity>, { ids }: PropIds) => Entity[];
85+ tableAsList: (d: Record<IdProp, Entity>) => Entity[];
86+ selectTable: (s: S) => Record<IdProp, Entity>;
87+ selectTableAsList: (state: S) => Entity[];
88+ selectById: (
89+ s: S,
90+ p: PropId,
91+ ) => Empty;
92+ selectByIds: (s: S, p: PropIds) => Entity[];
93 }
94
95-export const createTable = <
96+export function createTable<
97 Entity extends AnyState = AnyState,
98 S extends AnyState = AnyState,
99 >({
100@@ -107,9 +115,33 @@ export const createTable = <
101 initialState = {},
102 }: {
103 name: keyof S;
104+ initialState?: Record<IdProp, Entity>;
105 empty: Entity | (() => Entity);
106+}): TableOutput<Entity, S, Entity>;
107+export function createTable<
108+ Entity extends AnyState = AnyState,
109+ S extends AnyState = AnyState,
110+>({
111+ name,
112+ empty,
113+ initialState = {},
114+}: {
115+ name: keyof S;
116 initialState?: Record<IdProp, Entity>;
117-}): TableOutput<Entity, S> => {
118+ empty?: Entity | (() => Entity);
119+}): TableOutput<Entity, S, Entity | undefined>;
120+export function createTable<
121+ Entity extends AnyState = AnyState,
122+ S extends AnyState = AnyState,
123+>({
124+ name,
125+ empty,
126+ initialState = {},
127+}: {
128+ name: keyof S;
129+ initialState?: Record<IdProp, Entity>;
130+ empty?: Entity | (() => Entity);
131+}): TableOutput<Entity, S, Entity | undefined> {
132 const selectors = tableSelectors<Entity, S>((s: S) => s[name], empty);
133
134 return {
135@@ -162,13 +194,13 @@ export const createTable = <
136 },
137 ...selectors,
138 };
139-};
140+}
141
142 export function table<
143 V extends AnyState = AnyState,
144 >({ initialState, empty }: {
145 initialState?: Record<IdProp, V>;
146- empty: V | (() => V);
147+ empty?: V | (() => V);
148 }) {
149 return (name: string) => createTable<V>({ name, empty, initialState });
150 }