repos / starfx

supercharged async flow control library.
git clone https://github.com/neurosnap/starfx.git

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
M store/slice/table.test.ts
+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+});
M store/slice/table.ts
+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 }