Skip to content

Commit 8701520

Browse files
committed
[middleware] WillSetTablesCallback
1 parent 2f066ad commit 8701520

8 files changed

Lines changed: 466 additions & 19 deletions

File tree

‎src/@types/middleware/docs.js‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,25 @@
108108
* @since v8.0.0
109109
*/
110110
/// WillSetValuesCallback
111+
/**
112+
* The WillSetTablesCallback type describes a function that is called before
113+
* Tables are set in the Store.
114+
*
115+
* The callback receives the Tables object that is about to be set. It can
116+
* return the Tables (possibly transformed) to allow the write, or `undefined`
117+
* to prevent the Tables from being set.
118+
*
119+
* Multiple WillSetTablesCallback functions can be registered and they will be
120+
* called sequentially, the Tables being updated successively. If any callback
121+
* returns `undefined`, the chain short-circuits and the Tables will not be
122+
* set.
123+
* @param tables The Tables object about to be set.
124+
* @returns The Tables to use (possibly transformed), or `undefined` to prevent
125+
* the write.
126+
* @category Callback
127+
* @since v8.0.0
128+
*/
129+
/// WillSetTablesCallback
111130
/**
112131
* The WillDelCellCallback type describes a function that is called before a
113132
* Cell is deleted from the Store.
@@ -516,6 +535,75 @@
516535
* @since v8.0.0
517536
*/
518537
/// Middleware.addWillSetValuesCallback
538+
/**
539+
* The addWillSetTablesCallback method registers a WillSetTablesCallback that
540+
* will be called before Tables are set in the Store.
541+
*
542+
* The callback can transform the Tables or return `undefined` to prevent the
543+
* write. Multiple callbacks can be registered and they are called
544+
* sequentially, each receiving the (possibly transformed) tables from the
545+
* previous callback.
546+
* @param callback The WillSetTablesCallback to register.
547+
* @returns A reference to the Middleware object, for chaining.
548+
* @example
549+
* This example registers a callback that upper-cases all string Cell values
550+
* when entire Tables are set in the pet store.
551+
*
552+
* ```js
553+
* import {createMiddleware, createStore} from 'tinybase';
554+
*
555+
* const store = createStore();
556+
* const middleware = createMiddleware(store);
557+
*
558+
* middleware.addWillSetTablesCallback((tables) =>
559+
* Object.fromEntries(
560+
* Object.entries(tables).map(([tableId, table]) => [
561+
* tableId,
562+
* Object.fromEntries(
563+
* Object.entries(table).map(([rowId, row]) => [
564+
* rowId,
565+
* Object.fromEntries(
566+
* Object.entries(row).map(([k, v]) => [
567+
* k,
568+
* typeof v === 'string' ? v.toUpperCase() : v,
569+
* ]),
570+
* ),
571+
* ]),
572+
* ),
573+
* ]),
574+
* ),
575+
* );
576+
*
577+
* store.setTables({pets: {fido: {species: 'dog'}, felix: {species: 'cat'}}});
578+
* console.log(store.getTables());
579+
* // -> {pets: {fido: {species: 'DOG'}, felix: {species: 'CAT'}}}
580+
*
581+
* middleware.destroy();
582+
* ```
583+
* @example
584+
* This example registers a callback that prevents setting any Tables that
585+
* include a 'banned' table.
586+
*
587+
* ```js
588+
* import {createMiddleware, createStore} from 'tinybase';
589+
*
590+
* const store = createStore();
591+
* const middleware = createMiddleware(store);
592+
*
593+
* middleware.addWillSetTablesCallback((tables) =>
594+
* 'banned' in tables ? undefined : tables,
595+
* );
596+
*
597+
* store.setTables({banned: {r1: {c1: 1}}, pets: {fido: {species: 'dog'}}});
598+
* console.log(store.getTables());
599+
* // -> {}
600+
*
601+
* middleware.destroy();
602+
* ```
603+
* @category Configuration
604+
* @since v8.0.0
605+
*/
606+
/// Middleware.addWillSetTablesCallback
519607
/**
520608
* The addWillDelCellCallback method registers a WillDelCellCallback that will
521609
* be called before any Cell is deleted from the Store.

‎src/@types/middleware/index.d.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
Row,
77
Store,
88
Table,
9+
Tables,
910
Value,
1011
ValueOrUndefined,
1112
Values,
@@ -38,6 +39,9 @@ export type WillSetValueCallback = (
3839
value: Value,
3940
) => ValueOrUndefined;
4041

42+
/// WillSetTablesCallback
43+
export type WillSetTablesCallback = (tables: Tables) => Tables | undefined;
44+
4145
/// WillSetValuesCallback
4246
export type WillSetValuesCallback = (values: Values) => Values | undefined;
4347

@@ -77,6 +81,9 @@ export interface Middleware {
7781
/// Middleware.addWillSetValueCallback
7882
addWillSetValueCallback(callback: WillSetValueCallback): Middleware;
7983

84+
/// Middleware.addWillSetTablesCallback
85+
addWillSetTablesCallback(callback: WillSetTablesCallback): Middleware;
86+
8087
/// Middleware.addWillSetValuesCallback
8188
addWillSetValuesCallback(callback: WillSetValuesCallback): Middleware;
8289

‎src/@types/middleware/with-schemas/index.d.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
Row,
1414
Store,
1515
Table,
16+
Tables,
1617
Value,
1718
Values,
1819
} from '../../store/with-schemas/index.d.ts';
@@ -74,6 +75,13 @@ export type WillSetValueCallback<
7475
...params: Params | [valueId: never, value: never]
7576
) => Params[1] | undefined;
7677

78+
/// WillSetTablesCallback
79+
export type WillSetTablesCallback<
80+
Schema extends OptionalTablesSchema,
81+
> = (
82+
tables: Tables<Schema>,
83+
) => Tables<Schema> | undefined;
84+
7785
/// WillSetValuesCallback
7886
export type WillSetValuesCallback<Schema extends OptionalValuesSchema> = (
7987
values: Values<Schema>,
@@ -153,6 +161,11 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
153161
callback: WillSetValueCallback<Schemas[1]>,
154162
): Middleware<Schemas>;
155163

164+
/// Middleware.addWillSetTablesCallback
165+
addWillSetTablesCallback(
166+
callback: WillSetTablesCallback<Schemas[0]>,
167+
): Middleware<Schemas>;
168+
156169
/// Middleware.addWillSetValuesCallback
157170
addWillSetValuesCallback(
158171
callback: WillSetValuesCallback<Schemas[1]>,

‎src/middleware/index.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
WillSetCellCallback,
1010
WillSetRowCallback,
1111
WillSetTableCallback,
12+
WillSetTablesCallback,
1213
WillSetValueCallback,
1314
WillSetValuesCallback,
1415
createMiddleware as createMiddlewareDecl,
@@ -19,6 +20,7 @@ import type {
1920
Row,
2021
Store,
2122
Table,
23+
Tables,
2224
Value,
2325
ValueOrUndefined,
2426
Values,
@@ -32,6 +34,7 @@ export const createMiddleware = getCreateFunction(
3234
(store: Store): Middleware => {
3335
const willSetCellCallbacks: WillSetCellCallback[] = [];
3436
const willSetTableCallbacks: WillSetTableCallback[] = [];
37+
const willSetTablesCallbacks: WillSetTablesCallback[] = [];
3538
const willSetRowCallbacks: WillSetRowCallback[] = [];
3639
const willSetValueCallbacks: WillSetValueCallback[] = [];
3740
const willSetValuesCallbacks: WillSetValuesCallback[] = [];
@@ -95,6 +98,16 @@ export const createMiddleware = getCreateFunction(
9598
values as Values | undefined,
9699
);
97100

101+
const willSetTables = (tables: Tables): Tables | undefined =>
102+
arrayReduce(
103+
willSetTablesCallbacks,
104+
(current, callback) =>
105+
isUndefined(current)
106+
? current
107+
: callback(current as Tables),
108+
tables as Tables | undefined,
109+
);
110+
98111
const willDelCell = (tableId: Id, rowId: Id, cellId: Id): boolean =>
99112
arrayEvery(willDelCellCallbacks, (callback) =>
100113
callback(tableId, rowId, cellId),
@@ -123,6 +136,7 @@ export const createMiddleware = getCreateFunction(
123136
willDelValues,
124137
willSetTable,
125138
willDelTable,
139+
willSetTables,
126140
);
127141

128142
const getStore = (): Store => store;
@@ -144,6 +158,11 @@ export const createMiddleware = getCreateFunction(
144158
): Middleware =>
145159
fluent(() => arrayPush(willSetTableCallbacks, callback));
146160

161+
const addWillSetTablesCallback = (
162+
callback: WillSetTablesCallback,
163+
): Middleware =>
164+
fluent(() => arrayPush(willSetTablesCallbacks, callback));
165+
147166
const addWillSetValueCallback = (
148167
callback: WillSetValueCallback,
149168
): Middleware => fluent(() => arrayPush(willSetValueCallbacks, callback));
@@ -179,6 +198,7 @@ export const createMiddleware = getCreateFunction(
179198
getStore,
180199
addWillSetCellCallback,
181200
addWillSetTableCallback,
201+
addWillSetTablesCallback,
182202
addWillSetRowCallback,
183203
addWillSetValueCallback,
184204
addWillSetValuesCallback,

‎src/store/index.ts‎

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const createStore: typeof createStoreDecl = (): Store => {
178178
willDelValues?: () => boolean,
179179
willSetTable?: (tableId: Id, table: Table) => Table | undefined,
180180
willDelTable?: (tableId: Id) => boolean,
181+
willSetTables?: (tables: Tables) => Tables | undefined,
181182
] = [];
182183
let internalListeners: [
183184
preStartTransaction?: () => void,
@@ -465,13 +466,24 @@ export const createStore: typeof createStoreDecl = (): Store => {
465466
(objIsEmpty(values) ? delValues : setValues)(values);
466467
};
467468

468-
const setValidTables = (tables: Tables): TablesMap =>
469-
mapMatch(
470-
tablesMap,
471-
tables,
472-
(_tables, tableId, table) => setValidTable(tableId, table),
473-
(_tables, tableId) => delValidTable(tableId),
474-
);
469+
const setValidTables = (tables: Tables, forceDel?: boolean): TablesMap =>
470+
ifNotUndefined(
471+
forceDel
472+
? tables
473+
: ifNotUndefined(
474+
internalWillSets[10],
475+
(willSetTables) => willSetTables(tables),
476+
() => tables,
477+
),
478+
(validTables) =>
479+
mapMatch(
480+
tablesMap,
481+
validTables,
482+
(_tables, tableId, table) =>
483+
setValidTable(tableId, table),
484+
(_tables, tableId) => delValidTable(tableId),
485+
),
486+
) as TablesMap;
475487

476488
const setValidTable = (
477489
tableId: Id,
@@ -1476,7 +1488,8 @@ export const createStore: typeof createStoreDecl = (): Store => {
14761488
setValuesSchema(valuesSchema as ValuesSchema);
14771489
});
14781490

1479-
const delTables = (): Store => fluentTransaction(() => setValidTables({}));
1491+
const delTables = (): Store =>
1492+
fluentTransaction(() => setValidTables({}, true));
14801493

14811494
const delTable = (tableId: Id): Store =>
14821495
fluentTransaction(
@@ -1808,6 +1821,7 @@ export const createStore: typeof createStoreDecl = (): Store => {
18081821
willDelValues: () => boolean,
18091822
willSetTable: (tableId: Id, table: Table) => Table | undefined,
18101823
willDelTable: (tableId: Id) => boolean,
1824+
willSetTables: (tables: Tables) => Tables | undefined,
18111825
) =>
18121826
(internalWillSets = [
18131827
willSetCell,
@@ -1820,6 +1834,7 @@ export const createStore: typeof createStoreDecl = (): Store => {
18201834
willDelValues,
18211835
willSetTable,
18221836
willDelTable,
1837+
willSetTables,
18231838
]);
18241839

18251840
const setInternalListeners = (

0 commit comments

Comments
 (0)