tinybase 8.0.0-beta.1 → 8.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/middleware/index.d.ts +146 -29
- package/@types/middleware/with-schemas/index.d.ts +169 -29
- package/index.js +61 -3
- package/mergeable-store/index.js +40 -3
- package/mergeable-store/with-schemas/index.js +40 -3
- package/middleware/index.js +39 -0
- package/middleware/with-schemas/index.js +39 -0
- package/min/index.js +1 -1
- package/min/index.js.gz +0 -0
- package/min/mergeable-store/index.js +1 -1
- package/min/mergeable-store/index.js.gz +0 -0
- package/min/mergeable-store/with-schemas/index.js +1 -1
- package/min/mergeable-store/with-schemas/index.js.gz +0 -0
- package/min/middleware/index.js +1 -1
- package/min/middleware/index.js.gz +0 -0
- package/min/middleware/with-schemas/index.js +1 -1
- package/min/middleware/with-schemas/index.js.gz +0 -0
- package/min/omni/index.js +1 -1
- package/min/omni/index.js.gz +0 -0
- package/min/omni/with-schemas/index.js +1 -1
- package/min/omni/with-schemas/index.js.gz +0 -0
- package/min/store/index.js +1 -1
- package/min/store/index.js.gz +0 -0
- package/min/store/with-schemas/index.js +1 -1
- package/min/store/with-schemas/index.js.gz +0 -0
- package/min/ui-react-inspector/index.js +1 -1
- package/min/ui-react-inspector/index.js.gz +0 -0
- package/min/ui-react-inspector/with-schemas/index.js +1 -1
- package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
- package/min/with-schemas/index.js +1 -1
- package/min/with-schemas/index.js.gz +0 -0
- package/omni/index.js +60 -3
- package/omni/with-schemas/index.js +60 -3
- package/package.json +1 -1
- package/readme.md +3 -3
- package/releases.md +19 -3
- package/store/index.js +40 -3
- package/store/with-schemas/index.js +40 -3
- package/ui-react-inspector/index.js +40 -3
- package/ui-react-inspector/with-schemas/index.js +40 -3
- package/with-schemas/index.js +61 -3
|
@@ -28,17 +28,17 @@ import type {
|
|
|
28
28
|
* The WillSetContentCallback type describes a function that is called before
|
|
29
29
|
* Content is set in the Store.
|
|
30
30
|
*
|
|
31
|
-
* The callback receives the Content (a [Tables, Values] tuple) that is about
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* The callback receives the Content (a [Tables, Values] tuple) that is about to
|
|
32
|
+
* be set. It can return the Content (possibly transformed) to allow the write,
|
|
33
|
+
* or `undefined` to prevent the Content from being set.
|
|
34
34
|
*
|
|
35
35
|
* Multiple WillSetContentCallback functions can be registered and they will be
|
|
36
36
|
* called sequentially, the Content being updated successively. If any callback
|
|
37
37
|
* returns `undefined`, the chain short-circuits and the Content will not be
|
|
38
38
|
* set.
|
|
39
39
|
* @param content The Content about to be set.
|
|
40
|
-
* @returns The Content to use (possibly transformed), or `undefined` to
|
|
41
|
-
*
|
|
40
|
+
* @returns The Content to use (possibly transformed), or `undefined` to prevent
|
|
41
|
+
* the write.
|
|
42
42
|
* @category Callback
|
|
43
43
|
* @since v8.0.0
|
|
44
44
|
*/
|
|
@@ -54,8 +54,7 @@ export type WillSetContentCallback = (content: Content) => Content | undefined;
|
|
|
54
54
|
*
|
|
55
55
|
* Multiple WillSetTablesCallback functions can be registered and they will be
|
|
56
56
|
* called sequentially, the Tables being updated successively. If any callback
|
|
57
|
-
* returns `undefined`, the chain short-circuits and the Tables will not be
|
|
58
|
-
* set.
|
|
57
|
+
* returns `undefined`, the chain short-circuits and the Tables will not be set.
|
|
59
58
|
* @param tables The Tables object about to be set.
|
|
60
59
|
* @returns The Tables to use (possibly transformed), or `undefined` to prevent
|
|
61
60
|
* the write.
|
|
@@ -216,11 +215,11 @@ export type WillDelTablesCallback = () => boolean;
|
|
|
216
215
|
export type WillDelTableCallback = (tableId: Id) => boolean;
|
|
217
216
|
|
|
218
217
|
/**
|
|
219
|
-
* The WillDelRowCallback type describes a function that is called before a
|
|
220
|
-
*
|
|
218
|
+
* The WillDelRowCallback type describes a function that is called before a Row
|
|
219
|
+
* is deleted from the Store.
|
|
221
220
|
*
|
|
222
|
-
* The callback receives the table Id and row Id of the Row about to be
|
|
223
|
-
*
|
|
221
|
+
* The callback receives the table Id and row Id of the Row about to be deleted.
|
|
222
|
+
* It returns `true` to allow the deletion, or `false` to prevent it.
|
|
224
223
|
*
|
|
225
224
|
* Multiple WillDelRowCallback functions can be registered and they will be
|
|
226
225
|
* called sequentially. If any callback returns `false`, the chain
|
|
@@ -303,8 +302,8 @@ export type WillDelValueCallback = (valueId: Id) => boolean;
|
|
|
303
302
|
* callback returns `undefined`, the chain short-circuits and the Changes will
|
|
304
303
|
* not be applied.
|
|
305
304
|
* @param changes The Changes about to be applied.
|
|
306
|
-
* @returns The Changes to use (possibly transformed), or `undefined` to
|
|
307
|
-
*
|
|
305
|
+
* @returns The Changes to use (possibly transformed), or `undefined` to prevent
|
|
306
|
+
* the write.
|
|
308
307
|
* @category Callback
|
|
309
308
|
* @since v8.0.0
|
|
310
309
|
*/
|
|
@@ -312,6 +311,49 @@ export type WillApplyChangesCallback = (
|
|
|
312
311
|
changes: Changes,
|
|
313
312
|
) => Changes | undefined;
|
|
314
313
|
|
|
314
|
+
/**
|
|
315
|
+
* The DidSetRowCallback type describes a function called after a Row is changed
|
|
316
|
+
* during a transaction, and after mutator listeners have fired.
|
|
317
|
+
*
|
|
318
|
+
* Unlike the `willSet*` callbacks, which intercept writes as they happen,
|
|
319
|
+
* `didSetRow` fires once per touched Row after all cell writes in the
|
|
320
|
+
* transaction have completed. This means multiple cell changes to the same Row
|
|
321
|
+
* within a single transaction result in just one `didSetRow` call, with the
|
|
322
|
+
* full before-transaction and after-transaction Row states.
|
|
323
|
+
*
|
|
324
|
+
* The callback receives the Table Id, Row Id, the Row as it was at the start of
|
|
325
|
+
* the transaction (`oldRow`), and the Row as it is now (`newRow`). It must
|
|
326
|
+
* return a Row:
|
|
327
|
+
*
|
|
328
|
+
* - `newRow` to accept the changes.
|
|
329
|
+
* - a different `Row` to replace the final state.
|
|
330
|
+
* - `oldRow` to revert all changes to the Row.
|
|
331
|
+
* - an empty object to delete the Row.
|
|
332
|
+
*
|
|
333
|
+
* Multiple DidSetRowCallback functions can be registered for the same table and
|
|
334
|
+
* they will be called sequentially, each receiving the Row returned by the
|
|
335
|
+
* previous callback. The chain never short-circuits: all registered callbacks
|
|
336
|
+
* always run.
|
|
337
|
+
*
|
|
338
|
+
* Note that `addDidSetRowCallback` is table-scoped: you must specify the table
|
|
339
|
+
* Id when registering. Callbacks are only invoked for rows in the specified
|
|
340
|
+
* table, keeping overhead to zero for other tables.
|
|
341
|
+
* @param tableId The Id of the Table containing the changed Row.
|
|
342
|
+
* @param rowId The Id of the Row that was changed.
|
|
343
|
+
* @param oldRow The Row as it was at the start of the transaction.
|
|
344
|
+
* @param newRow The Row as it is now, after all cell writes including those
|
|
345
|
+
* made by mutating listeners.
|
|
346
|
+
* @returns The Row to use as the final state.
|
|
347
|
+
* @category Callback
|
|
348
|
+
* @since v8.0.0
|
|
349
|
+
*/
|
|
350
|
+
export type DidSetRowCallback = (
|
|
351
|
+
tableId: Id,
|
|
352
|
+
rowId: Id,
|
|
353
|
+
oldRow: Row,
|
|
354
|
+
newRow: Row,
|
|
355
|
+
) => Row;
|
|
356
|
+
|
|
315
357
|
/**
|
|
316
358
|
* A Middleware object lets you intercept and validate writes to a Store.
|
|
317
359
|
*
|
|
@@ -360,14 +402,13 @@ export interface Middleware {
|
|
|
360
402
|
getStore(): Store;
|
|
361
403
|
|
|
362
404
|
/**
|
|
363
|
-
* The addWillSetContentCallback method registers a
|
|
364
|
-
*
|
|
365
|
-
* Store.
|
|
405
|
+
* The addWillSetContentCallback method registers a WillSetContentCallback
|
|
406
|
+
* that will be called before Content is set in the Store.
|
|
366
407
|
*
|
|
367
|
-
* The callback can transform the Content or return `undefined` to prevent
|
|
368
|
-
*
|
|
369
|
-
* sequentially, each receiving the (possibly transformed) Content from
|
|
370
|
-
*
|
|
408
|
+
* The callback can transform the Content or return `undefined` to prevent the
|
|
409
|
+
* write. Multiple callbacks can be registered and they are called
|
|
410
|
+
* sequentially, each receiving the (possibly transformed) Content from the
|
|
411
|
+
* previous callback.
|
|
371
412
|
* @param callback The WillSetContentCallback to register.
|
|
372
413
|
* @returns A reference to the Middleware object, for chaining.
|
|
373
414
|
* @example
|
|
@@ -756,9 +797,9 @@ export interface Middleware {
|
|
|
756
797
|
* The addWillDelTablesCallback method registers a WillDelTablesCallback that
|
|
757
798
|
* will be called before all Tables are deleted from the Store.
|
|
758
799
|
*
|
|
759
|
-
* The callback returns `true` to allow the deletion or `false` to prevent
|
|
760
|
-
*
|
|
761
|
-
*
|
|
800
|
+
* The callback returns `true` to allow the deletion or `false` to prevent it.
|
|
801
|
+
* Multiple callbacks can be registered and they are called sequentially. If
|
|
802
|
+
* any callback returns `false`, the deletion is prevented.
|
|
762
803
|
* @param callback The WillDelTablesCallback to register.
|
|
763
804
|
* @returns A reference to the Middleware object, for chaining.
|
|
764
805
|
* @example
|
|
@@ -790,9 +831,9 @@ export interface Middleware {
|
|
|
790
831
|
* The addWillDelTableCallback method registers a WillDelTableCallback that
|
|
791
832
|
* will be called before any Table is deleted from the Store.
|
|
792
833
|
*
|
|
793
|
-
* The callback returns `true` to allow the deletion or `false` to prevent
|
|
794
|
-
*
|
|
795
|
-
*
|
|
834
|
+
* The callback returns `true` to allow the deletion or `false` to prevent it.
|
|
835
|
+
* Multiple callbacks can be registered and they are called sequentially. If
|
|
836
|
+
* any callback returns `false`, the deletion is prevented.
|
|
796
837
|
* @param callback The WillDelTableCallback to register.
|
|
797
838
|
* @returns A reference to the Middleware object, for chaining.
|
|
798
839
|
* @example
|
|
@@ -957,9 +998,9 @@ export interface Middleware {
|
|
|
957
998
|
addWillDelValueCallback(callback: WillDelValueCallback): Middleware;
|
|
958
999
|
|
|
959
1000
|
/**
|
|
960
|
-
* The addWillApplyChangesCallback method registers a
|
|
961
|
-
*
|
|
962
|
-
*
|
|
1001
|
+
* The addWillApplyChangesCallback method registers a WillApplyChangesCallback
|
|
1002
|
+
* that will be called before Changes are applied to the Store via the
|
|
1003
|
+
* applyChanges method.
|
|
963
1004
|
*
|
|
964
1005
|
* This callback receives the Changes object and can return it (to allow),
|
|
965
1006
|
* return a modified Changes object (to transform), or return `undefined` (to
|
|
@@ -1003,6 +1044,82 @@ export interface Middleware {
|
|
|
1003
1044
|
*/
|
|
1004
1045
|
addWillApplyChangesCallback(callback: WillApplyChangesCallback): Middleware;
|
|
1005
1046
|
|
|
1047
|
+
/**
|
|
1048
|
+
* The addDidSetRowCallback method registers a DidSetRowCallback for a
|
|
1049
|
+
* specific table that will be called after any Row in that table is changed
|
|
1050
|
+
* during a transaction, after mutator listeners have fired.
|
|
1051
|
+
*
|
|
1052
|
+
* Unlike `willSetRow`, which fires synchronously during each write, this
|
|
1053
|
+
* callback fires once per changed Row after all cell writes in the
|
|
1054
|
+
* transaction have landed. Multiple cell changes to the same Row within a
|
|
1055
|
+
* transaction produce a single callback with the full before/after Row
|
|
1056
|
+
* states.
|
|
1057
|
+
*
|
|
1058
|
+
* The callback receives `oldRow` (the Row at the start of the transaction)
|
|
1059
|
+
* and `newRow` (the Row after all writes). Return `newRow` to accept, a
|
|
1060
|
+
* different `Row` to replace, `oldRow` to revert, or an empty object to
|
|
1061
|
+
* delete.
|
|
1062
|
+
* @param tableId The Id of the Table to watch.
|
|
1063
|
+
* @param callback The DidSetRowCallback to register.
|
|
1064
|
+
* @returns A reference to the Middleware object, for chaining.
|
|
1065
|
+
* @example
|
|
1066
|
+
* This example registers a callback that validates the 'pets' table,
|
|
1067
|
+
* reverting any row that ends up without a required 'species' cell.
|
|
1068
|
+
*
|
|
1069
|
+
* ```js
|
|
1070
|
+
* import {createMiddleware, createStore} from 'tinybase';
|
|
1071
|
+
*
|
|
1072
|
+
* const store = createStore();
|
|
1073
|
+
* const middleware = createMiddleware(store);
|
|
1074
|
+
*
|
|
1075
|
+
* middleware.addDidSetRowCallback('pets', (_tableId, _rowId, oldRow, newRow) =>
|
|
1076
|
+
* 'species' in newRow ? newRow : oldRow,
|
|
1077
|
+
* );
|
|
1078
|
+
*
|
|
1079
|
+
* store.setRow('pets', 'fido', {species: 'dog', name: 'Fido'});
|
|
1080
|
+
* console.log(store.getRow('pets', 'fido'));
|
|
1081
|
+
* // -> {species: 'dog', name: 'Fido'}
|
|
1082
|
+
*
|
|
1083
|
+
* store.setRow('pets', 'nemo', {name: 'Nemo'});
|
|
1084
|
+
* console.log(store.getRow('pets', 'nemo'));
|
|
1085
|
+
* // -> {}
|
|
1086
|
+
*
|
|
1087
|
+
* middleware.destroy();
|
|
1088
|
+
* ```
|
|
1089
|
+
* @example
|
|
1090
|
+
* This example shows that multiple cell changes in one transaction result in
|
|
1091
|
+
* a single didSetRow callback with the full before/after row states.
|
|
1092
|
+
*
|
|
1093
|
+
* ```js
|
|
1094
|
+
* import {createMiddleware, createStore} from 'tinybase';
|
|
1095
|
+
*
|
|
1096
|
+
* const store = createStore();
|
|
1097
|
+
* const middleware = createMiddleware(store);
|
|
1098
|
+
*
|
|
1099
|
+
* const seen = [];
|
|
1100
|
+
* middleware.addDidSetRowCallback('pets', (_tableId, rowId, oldRow, newRow) => {
|
|
1101
|
+
* seen.push({rowId, oldRow: {...oldRow}, newRow: {...newRow}});
|
|
1102
|
+
* return newRow;
|
|
1103
|
+
* });
|
|
1104
|
+
*
|
|
1105
|
+
* store.transaction(() => {
|
|
1106
|
+
* store.setCell('pets', 'fido', 'name', 'Fido');
|
|
1107
|
+
* store.setCell('pets', 'fido', 'species', 'dog');
|
|
1108
|
+
* });
|
|
1109
|
+
* console.log(seen.length);
|
|
1110
|
+
* // -> 1
|
|
1111
|
+
* console.log(seen[0].rowId);
|
|
1112
|
+
* // -> 'fido'
|
|
1113
|
+
* console.log(seen[0].newRow);
|
|
1114
|
+
* // -> {name: 'Fido', species: 'dog'}
|
|
1115
|
+
*
|
|
1116
|
+
* middleware.destroy();
|
|
1117
|
+
* ```
|
|
1118
|
+
* @category Configuration
|
|
1119
|
+
* @since v8.0.0
|
|
1120
|
+
*/
|
|
1121
|
+
addDidSetRowCallback(tableId: Id, callback: DidSetRowCallback): Middleware;
|
|
1122
|
+
|
|
1006
1123
|
/**
|
|
1007
1124
|
* The destroy method should be called when this Middleware object is no
|
|
1008
1125
|
* longer used. It removes all hooks and listeners from the Store, and
|
|
@@ -40,17 +40,17 @@ import type {
|
|
|
40
40
|
* (content: Content) => Content | undefined;
|
|
41
41
|
* ```
|
|
42
42
|
*
|
|
43
|
-
* The callback receives the Content (a [Tables, Values] tuple) that is about
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* The callback receives the Content (a [Tables, Values] tuple) that is about to
|
|
44
|
+
* be set. It can return the Content (possibly transformed) to allow the write,
|
|
45
|
+
* or `undefined` to prevent the Content from being set.
|
|
46
46
|
*
|
|
47
47
|
* Multiple WillSetContentCallback functions can be registered and they will be
|
|
48
48
|
* called sequentially, the Content being updated successively. If any callback
|
|
49
49
|
* returns `undefined`, the chain short-circuits and the Content will not be
|
|
50
50
|
* set.
|
|
51
51
|
* @param content The Content about to be set.
|
|
52
|
-
* @returns The Content to use (possibly transformed), or `undefined` to
|
|
53
|
-
*
|
|
52
|
+
* @returns The Content to use (possibly transformed), or `undefined` to prevent
|
|
53
|
+
* the write.
|
|
54
54
|
* @category Callback
|
|
55
55
|
* @since v8.0.0
|
|
56
56
|
*/
|
|
@@ -74,8 +74,7 @@ export type WillSetContentCallback<Schemas extends OptionalSchemas> = (
|
|
|
74
74
|
*
|
|
75
75
|
* Multiple WillSetTablesCallback functions can be registered and they will be
|
|
76
76
|
* called sequentially, the Tables being updated successively. If any callback
|
|
77
|
-
* returns `undefined`, the chain short-circuits and the Tables will not be
|
|
78
|
-
* set.
|
|
77
|
+
* returns `undefined`, the chain short-circuits and the Tables will not be set.
|
|
79
78
|
* @param tables The Tables object about to be set.
|
|
80
79
|
* @returns The Tables to use (possibly transformed), or `undefined` to prevent
|
|
81
80
|
* the write.
|
|
@@ -328,8 +327,8 @@ export type WillDelTableCallback<
|
|
|
328
327
|
> = (...params: Params | [tableId: never]) => boolean;
|
|
329
328
|
|
|
330
329
|
/**
|
|
331
|
-
* The WillDelRowCallback type describes a function that is called before a
|
|
332
|
-
*
|
|
330
|
+
* The WillDelRowCallback type describes a function that is called before a Row
|
|
331
|
+
* is deleted from the Store.
|
|
333
332
|
*
|
|
334
333
|
* This has schema-based typing. The following is a simplified representation:
|
|
335
334
|
*
|
|
@@ -337,8 +336,8 @@ export type WillDelTableCallback<
|
|
|
337
336
|
* (tableId: Id, rowId: Id) => boolean;
|
|
338
337
|
* ```
|
|
339
338
|
*
|
|
340
|
-
* The callback receives the table Id and row Id of the Row about to be
|
|
341
|
-
*
|
|
339
|
+
* The callback receives the table Id and row Id of the Row about to be deleted.
|
|
340
|
+
* It returns `true` to allow the deletion, or `false` to prevent it.
|
|
342
341
|
*
|
|
343
342
|
* Multiple WillDelRowCallback functions can be registered and they will be
|
|
344
343
|
* called sequentially. If any callback returns `false`, the chain
|
|
@@ -468,8 +467,8 @@ export type WillDelValueCallback<
|
|
|
468
467
|
* callback returns `undefined`, the chain short-circuits and the Changes will
|
|
469
468
|
* not be applied.
|
|
470
469
|
* @param changes The Changes about to be applied.
|
|
471
|
-
* @returns The Changes to use (possibly transformed), or `undefined` to
|
|
472
|
-
*
|
|
470
|
+
* @returns The Changes to use (possibly transformed), or `undefined` to prevent
|
|
471
|
+
* the write.
|
|
473
472
|
* @category Callback
|
|
474
473
|
* @since v8.0.0
|
|
475
474
|
*/
|
|
@@ -477,6 +476,63 @@ export type WillApplyChangesCallback<Schemas extends OptionalSchemas> = (
|
|
|
477
476
|
changes: Changes<Schemas>,
|
|
478
477
|
) => Changes<Schemas> | undefined;
|
|
479
478
|
|
|
479
|
+
/**
|
|
480
|
+
* The DidSetRowCallback type describes a function called after a Row is changed
|
|
481
|
+
* during a transaction, and after mutator listeners have fired.
|
|
482
|
+
*
|
|
483
|
+
* This has schema-based typing. The following is a simplified representation:
|
|
484
|
+
*
|
|
485
|
+
* ```ts override
|
|
486
|
+
* (
|
|
487
|
+
* tableId: Id,
|
|
488
|
+
* rowId: Id,
|
|
489
|
+
* oldRow: Row,
|
|
490
|
+
* newRow: Row,
|
|
491
|
+
* ) => Row;
|
|
492
|
+
* ```
|
|
493
|
+
*
|
|
494
|
+
* Unlike the `willSet*` callbacks, which intercept writes as they happen,
|
|
495
|
+
* `didSetRow` fires once per touched Row after all cell writes in the
|
|
496
|
+
* transaction have completed. This means multiple cell changes to the same Row
|
|
497
|
+
* within a single transaction result in just one `didSetRow` call, with the
|
|
498
|
+
* full before-transaction and after-transaction Row states.
|
|
499
|
+
*
|
|
500
|
+
* The callback receives the Table Id, Row Id, the Row as it was at the start of
|
|
501
|
+
* the transaction (`oldRow`), and the Row as it is now (`newRow`). It must
|
|
502
|
+
* return a Row:
|
|
503
|
+
*
|
|
504
|
+
* - `newRow` to accept the changes.
|
|
505
|
+
* - a different `Row` to replace the final state.
|
|
506
|
+
* - `oldRow` to revert all changes to the Row.
|
|
507
|
+
* - an empty object to delete the Row.
|
|
508
|
+
*
|
|
509
|
+
* Multiple DidSetRowCallback functions can be registered for the same table and
|
|
510
|
+
* they will be called sequentially, each receiving the Row returned by the
|
|
511
|
+
* previous callback. The chain never short-circuits: all registered callbacks
|
|
512
|
+
* always run.
|
|
513
|
+
*
|
|
514
|
+
* Note that `addDidSetRowCallback` is table-scoped: you must specify the table
|
|
515
|
+
* Id when registering. Callbacks are only invoked for rows in the specified
|
|
516
|
+
* table, keeping overhead to zero for other tables.
|
|
517
|
+
* @param tableId The Id of the Table containing the changed Row.
|
|
518
|
+
* @param rowId The Id of the Row that was changed.
|
|
519
|
+
* @param oldRow The Row as it was at the start of the transaction.
|
|
520
|
+
* @param newRow The Row as it is now, after all cell writes including those
|
|
521
|
+
* made by mutating listeners.
|
|
522
|
+
* @returns The Row to use as the final state.
|
|
523
|
+
* @category Callback
|
|
524
|
+
* @since v8.0.0
|
|
525
|
+
*/
|
|
526
|
+
export type DidSetRowCallback<
|
|
527
|
+
Schema extends OptionalTablesSchema,
|
|
528
|
+
TableId extends TableIdFromSchema<Schema>,
|
|
529
|
+
> = (
|
|
530
|
+
tableId: TableId,
|
|
531
|
+
rowId: Id,
|
|
532
|
+
oldRow: Row<Schema, TableId>,
|
|
533
|
+
newRow: Row<Schema, TableId>,
|
|
534
|
+
) => Row<Schema, TableId>;
|
|
535
|
+
|
|
480
536
|
/**
|
|
481
537
|
* A Middleware object lets you intercept and validate writes to a Store.
|
|
482
538
|
*
|
|
@@ -531,9 +587,8 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
531
587
|
getStore(): Store<Schemas>;
|
|
532
588
|
|
|
533
589
|
/**
|
|
534
|
-
* The addWillSetContentCallback method registers a
|
|
535
|
-
*
|
|
536
|
-
* Store.
|
|
590
|
+
* The addWillSetContentCallback method registers a WillSetContentCallback
|
|
591
|
+
* that will be called before Content is set in the Store.
|
|
537
592
|
*
|
|
538
593
|
* This has schema-based typing. The following is a simplified representation:
|
|
539
594
|
*
|
|
@@ -541,10 +596,10 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
541
596
|
* addWillSetContentCallback(callback: WillSetContentCallback): Middleware;
|
|
542
597
|
* ```
|
|
543
598
|
*
|
|
544
|
-
* The callback can transform the Content or return `undefined` to prevent
|
|
545
|
-
*
|
|
546
|
-
* sequentially, each receiving the (possibly transformed) Content from
|
|
547
|
-
*
|
|
599
|
+
* The callback can transform the Content or return `undefined` to prevent the
|
|
600
|
+
* write. Multiple callbacks can be registered and they are called
|
|
601
|
+
* sequentially, each receiving the (possibly transformed) Content from the
|
|
602
|
+
* previous callback.
|
|
548
603
|
* @param callback The WillSetContentCallback to register.
|
|
549
604
|
* @returns A reference to the Middleware object, for chaining.
|
|
550
605
|
* @example
|
|
@@ -989,9 +1044,9 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
989
1044
|
* addWillDelTablesCallback(callback: WillDelTablesCallback): Middleware;
|
|
990
1045
|
* ```
|
|
991
1046
|
*
|
|
992
|
-
* The callback returns `true` to allow the deletion or `false` to prevent
|
|
993
|
-
*
|
|
994
|
-
*
|
|
1047
|
+
* The callback returns `true` to allow the deletion or `false` to prevent it.
|
|
1048
|
+
* Multiple callbacks can be registered and they are called sequentially. If
|
|
1049
|
+
* any callback returns `false`, the deletion is prevented.
|
|
995
1050
|
* @param callback The WillDelTablesCallback to register.
|
|
996
1051
|
* @returns A reference to the Middleware object, for chaining.
|
|
997
1052
|
* @example
|
|
@@ -1031,9 +1086,9 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
1031
1086
|
* addWillDelTableCallback(callback: WillDelTableCallback): Middleware;
|
|
1032
1087
|
* ```
|
|
1033
1088
|
*
|
|
1034
|
-
* The callback returns `true` to allow the deletion or `false` to prevent
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1089
|
+
* The callback returns `true` to allow the deletion or `false` to prevent it.
|
|
1090
|
+
* Multiple callbacks can be registered and they are called sequentially. If
|
|
1091
|
+
* any callback returns `false`, the deletion is prevented.
|
|
1037
1092
|
* @param callback The WillDelTableCallback to register.
|
|
1038
1093
|
* @returns A reference to the Middleware object, for chaining.
|
|
1039
1094
|
* @example
|
|
@@ -1232,9 +1287,9 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
1232
1287
|
): Middleware<Schemas>;
|
|
1233
1288
|
|
|
1234
1289
|
/**
|
|
1235
|
-
* The addWillApplyChangesCallback method registers a
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1290
|
+
* The addWillApplyChangesCallback method registers a WillApplyChangesCallback
|
|
1291
|
+
* that will be called before Changes are applied to the Store via the
|
|
1292
|
+
* applyChanges method.
|
|
1238
1293
|
*
|
|
1239
1294
|
* This has schema-based typing. The following is a simplified representation:
|
|
1240
1295
|
*
|
|
@@ -1286,6 +1341,91 @@ export interface Middleware<in out Schemas extends OptionalSchemas> {
|
|
|
1286
1341
|
callback: WillApplyChangesCallback<Schemas>,
|
|
1287
1342
|
): Middleware<Schemas>;
|
|
1288
1343
|
|
|
1344
|
+
/**
|
|
1345
|
+
* The addDidSetRowCallback method registers a DidSetRowCallback for a
|
|
1346
|
+
* specific table that will be called after any Row in that table is changed
|
|
1347
|
+
* during a transaction, after mutator listeners have fired.
|
|
1348
|
+
*
|
|
1349
|
+
* This has schema-based typing. The following is a simplified representation:
|
|
1350
|
+
*
|
|
1351
|
+
* ```ts override
|
|
1352
|
+
* addDidSetRowCallback(tableId: Id, callback: DidSetRowCallback): Middleware;
|
|
1353
|
+
* ```
|
|
1354
|
+
*
|
|
1355
|
+
* Unlike `willSetRow`, which fires synchronously during each write, this
|
|
1356
|
+
* callback fires once per changed Row after all cell writes in the
|
|
1357
|
+
* transaction have landed. Multiple cell changes to the same Row within a
|
|
1358
|
+
* transaction produce a single callback with the full before/after Row
|
|
1359
|
+
* states.
|
|
1360
|
+
*
|
|
1361
|
+
* The callback receives `oldRow` (the Row at the start of the transaction)
|
|
1362
|
+
* and `newRow` (the Row after all writes). Return `newRow` to accept, a
|
|
1363
|
+
* different `Row` to replace, `oldRow` to revert, or an empty object to
|
|
1364
|
+
* delete.
|
|
1365
|
+
* @param tableId The Id of the Table to watch.
|
|
1366
|
+
* @param callback The DidSetRowCallback to register.
|
|
1367
|
+
* @returns A reference to the Middleware object, for chaining.
|
|
1368
|
+
* @example
|
|
1369
|
+
* This example registers a callback that validates the 'pets' table,
|
|
1370
|
+
* reverting any row that ends up without a required 'species' cell.
|
|
1371
|
+
*
|
|
1372
|
+
* ```js
|
|
1373
|
+
* import {createMiddleware, createStore} from 'tinybase';
|
|
1374
|
+
*
|
|
1375
|
+
* const store = createStore();
|
|
1376
|
+
* const middleware = createMiddleware(store);
|
|
1377
|
+
*
|
|
1378
|
+
* middleware.addDidSetRowCallback('pets', (_tableId, _rowId, oldRow, newRow) =>
|
|
1379
|
+
* 'species' in newRow ? newRow : oldRow,
|
|
1380
|
+
* );
|
|
1381
|
+
*
|
|
1382
|
+
* store.setRow('pets', 'fido', {species: 'dog', name: 'Fido'});
|
|
1383
|
+
* console.log(store.getRow('pets', 'fido'));
|
|
1384
|
+
* // -> {species: 'dog', name: 'Fido'}
|
|
1385
|
+
*
|
|
1386
|
+
* store.setRow('pets', 'nemo', {name: 'Nemo'});
|
|
1387
|
+
* console.log(store.getRow('pets', 'nemo'));
|
|
1388
|
+
* // -> {}
|
|
1389
|
+
*
|
|
1390
|
+
* middleware.destroy();
|
|
1391
|
+
* ```
|
|
1392
|
+
* @example
|
|
1393
|
+
* This example shows that multiple cell changes in one transaction result in
|
|
1394
|
+
* a single didSetRow callback with the full before/after row states.
|
|
1395
|
+
*
|
|
1396
|
+
* ```js
|
|
1397
|
+
* import {createMiddleware, createStore} from 'tinybase';
|
|
1398
|
+
*
|
|
1399
|
+
* const store = createStore();
|
|
1400
|
+
* const middleware = createMiddleware(store);
|
|
1401
|
+
*
|
|
1402
|
+
* const seen = [];
|
|
1403
|
+
* middleware.addDidSetRowCallback('pets', (_tableId, rowId, oldRow, newRow) => {
|
|
1404
|
+
* seen.push({rowId, oldRow: {...oldRow}, newRow: {...newRow}});
|
|
1405
|
+
* return newRow;
|
|
1406
|
+
* });
|
|
1407
|
+
*
|
|
1408
|
+
* store.transaction(() => {
|
|
1409
|
+
* store.setCell('pets', 'fido', 'name', 'Fido');
|
|
1410
|
+
* store.setCell('pets', 'fido', 'species', 'dog');
|
|
1411
|
+
* });
|
|
1412
|
+
* console.log(seen.length);
|
|
1413
|
+
* // -> 1
|
|
1414
|
+
* console.log(seen[0].rowId);
|
|
1415
|
+
* // -> 'fido'
|
|
1416
|
+
* console.log(seen[0].newRow);
|
|
1417
|
+
* // -> {name: 'Fido', species: 'dog'}
|
|
1418
|
+
*
|
|
1419
|
+
* middleware.destroy();
|
|
1420
|
+
* ```
|
|
1421
|
+
* @category Configuration
|
|
1422
|
+
* @since v8.0.0
|
|
1423
|
+
*/
|
|
1424
|
+
addDidSetRowCallback<TableId extends TableIdFromSchema<Schemas[0]>>(
|
|
1425
|
+
tableId: TableId,
|
|
1426
|
+
callback: DidSetRowCallback<Schemas[0], TableId>,
|
|
1427
|
+
): Middleware<Schemas>;
|
|
1428
|
+
|
|
1289
1429
|
/**
|
|
1290
1430
|
* The destroy method should be called when this Middleware object is no
|
|
1291
1431
|
* longer used. It removes all hooks and listeners from the Store, and
|
package/index.js
CHANGED
|
@@ -131,6 +131,7 @@ const isObject = (obj) =>
|
|
|
131
131
|
const objIds = object.keys;
|
|
132
132
|
const objFreeze = object.freeze;
|
|
133
133
|
const objNew = (entries = []) => object.fromEntries(entries);
|
|
134
|
+
const objMerge = (...objs) => object.assign({}, ...objs);
|
|
134
135
|
const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
|
|
135
136
|
const objHas = (obj, id) => id in obj;
|
|
136
137
|
const objDel = (obj, id) => {
|
|
@@ -1863,6 +1864,10 @@ const createStore = () => {
|
|
|
1863
1864
|
return 1;
|
|
1864
1865
|
}
|
|
1865
1866
|
};
|
|
1867
|
+
const clonedChangedCells = (changedCells2) =>
|
|
1868
|
+
mapClone(changedCells2, (map) =>
|
|
1869
|
+
mapClone(map, (map2) => mapClone(map2, pairClone)),
|
|
1870
|
+
);
|
|
1866
1871
|
const callTabularListenersForChanges = (mutator) => {
|
|
1867
1872
|
const hasHasTablesListeners = !collIsEmpty(hasTablesListeners[mutator]);
|
|
1868
1873
|
const hasSortedRowIdListeners = !collIsEmpty(
|
|
@@ -1894,9 +1899,7 @@ const createStore = () => {
|
|
|
1894
1899
|
mapClone(changedRowCount),
|
|
1895
1900
|
mapClone2(changedRowIds),
|
|
1896
1901
|
mapClone3(changedCellIds),
|
|
1897
|
-
|
|
1898
|
-
mapClone(map, (map2) => mapClone(map2, pairClone)),
|
|
1899
|
-
),
|
|
1902
|
+
clonedChangedCells(changedCells),
|
|
1900
1903
|
]
|
|
1901
1904
|
: [
|
|
1902
1905
|
changedTableIds,
|
|
@@ -2461,6 +2464,37 @@ const createStore = () => {
|
|
|
2461
2464
|
mapToObj3(changedCellIds),
|
|
2462
2465
|
mapToObj(changedValueIds),
|
|
2463
2466
|
];
|
|
2467
|
+
const doDidSetRows = () => {
|
|
2468
|
+
if (middleware[14]) {
|
|
2469
|
+
const changedCells2 = clonedChangedCells(changedCells);
|
|
2470
|
+
collForEach(changedCells2, (rows, tableId) =>
|
|
2471
|
+
collForEach(rows, (cells, rowId) => {
|
|
2472
|
+
if (
|
|
2473
|
+
!arrayEvery(
|
|
2474
|
+
collValues(cells),
|
|
2475
|
+
([oldCell, newCell]) => oldCell === newCell,
|
|
2476
|
+
)
|
|
2477
|
+
) {
|
|
2478
|
+
const newRow = getRow(tableId, rowId);
|
|
2479
|
+
const oldRow = objMerge(newRow);
|
|
2480
|
+
collForEach(cells, ([oldCell], cellId) =>
|
|
2481
|
+
isUndefined(oldCell)
|
|
2482
|
+
? objDel(oldRow, cellId)
|
|
2483
|
+
: (oldRow[cellId] = oldCell),
|
|
2484
|
+
);
|
|
2485
|
+
const didSetRow = middleware[14](tableId, rowId, oldRow, newRow);
|
|
2486
|
+
if (!objIsEqual(didSetRow, newRow)) {
|
|
2487
|
+
const setOrDelRow = objMap(newRow, () => void 0);
|
|
2488
|
+
objMap(didSetRow, (cell, cellId) => (setOrDelRow[cellId] = cell));
|
|
2489
|
+
objMap(setOrDelRow, (cell, cellId) =>
|
|
2490
|
+
setOrDelCell(tableId, rowId, cellId, cell, true),
|
|
2491
|
+
);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
}),
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2464
2498
|
const finishTransaction = (doRollback) => {
|
|
2465
2499
|
if (transactions > 0) {
|
|
2466
2500
|
transactions--;
|
|
@@ -2470,6 +2504,7 @@ const createStore = () => {
|
|
|
2470
2504
|
callInvalidCellListeners(1);
|
|
2471
2505
|
if (!collIsEmpty(changedCells)) {
|
|
2472
2506
|
callTabularListenersForChanges(1);
|
|
2507
|
+
doDidSetRows();
|
|
2473
2508
|
}
|
|
2474
2509
|
callInvalidValueListeners(1);
|
|
2475
2510
|
if (!collIsEmpty(changedValues)) {
|
|
@@ -2628,6 +2663,7 @@ const createStore = () => {
|
|
|
2628
2663
|
willDelValues,
|
|
2629
2664
|
willDelValue,
|
|
2630
2665
|
willApplyChanges,
|
|
2666
|
+
didSetRow,
|
|
2631
2667
|
) =>
|
|
2632
2668
|
(middleware = [
|
|
2633
2669
|
willSetContent,
|
|
@@ -2644,6 +2680,7 @@ const createStore = () => {
|
|
|
2644
2680
|
willDelValues,
|
|
2645
2681
|
willDelValue,
|
|
2646
2682
|
willApplyChanges,
|
|
2683
|
+
didSetRow,
|
|
2647
2684
|
]);
|
|
2648
2685
|
const setInternalListeners = (
|
|
2649
2686
|
preStartTransaction,
|
|
@@ -3521,6 +3558,7 @@ const createMiddleware = getCreateFunction((store) => {
|
|
|
3521
3558
|
const willDelValuesCallbacks = [];
|
|
3522
3559
|
const willDelValueCallbacks = [];
|
|
3523
3560
|
const willApplyChangesCallbacks = [];
|
|
3561
|
+
const didSetRowCallbacksMap = mapNew();
|
|
3524
3562
|
const willSetContent = (content) =>
|
|
3525
3563
|
reduceCallbacks(willSetContentCallbacks, content);
|
|
3526
3564
|
const willSetTables = (tables) =>
|
|
@@ -3547,6 +3585,17 @@ const createMiddleware = getCreateFunction((store) => {
|
|
|
3547
3585
|
everyCallback(willDelValueCallbacks, valueId);
|
|
3548
3586
|
const willApplyChanges = (changes) =>
|
|
3549
3587
|
reduceCallbacks(willApplyChangesCallbacks, changes);
|
|
3588
|
+
const didSetRow = (tableId, rowId, oldRow, newRow) =>
|
|
3589
|
+
ifNotUndefined(
|
|
3590
|
+
mapGet(didSetRowCallbacksMap, tableId),
|
|
3591
|
+
(callbacks) =>
|
|
3592
|
+
arrayReduce(
|
|
3593
|
+
callbacks,
|
|
3594
|
+
(current, callback) => callback(tableId, rowId, oldRow, current),
|
|
3595
|
+
newRow,
|
|
3596
|
+
),
|
|
3597
|
+
() => newRow,
|
|
3598
|
+
);
|
|
3550
3599
|
const getStore = () => store;
|
|
3551
3600
|
const addWillSetContentCallback = addCallback(willSetContentCallbacks);
|
|
3552
3601
|
const addWillSetTablesCallback = addCallback(willSetTablesCallbacks);
|
|
@@ -3562,6 +3611,13 @@ const createMiddleware = getCreateFunction((store) => {
|
|
|
3562
3611
|
const addWillDelValuesCallback = addCallback(willDelValuesCallbacks);
|
|
3563
3612
|
const addWillDelValueCallback = addCallback(willDelValueCallbacks);
|
|
3564
3613
|
const addWillApplyChangesCallback = addCallback(willApplyChangesCallbacks);
|
|
3614
|
+
const addDidSetRowCallback = (tableId, callback) =>
|
|
3615
|
+
fluent(() =>
|
|
3616
|
+
arrayPush(
|
|
3617
|
+
mapEnsure(didSetRowCallbacksMap, tableId, () => []),
|
|
3618
|
+
callback,
|
|
3619
|
+
),
|
|
3620
|
+
);
|
|
3565
3621
|
const destroy = () => {};
|
|
3566
3622
|
const middleware = objFreeze({
|
|
3567
3623
|
getStore,
|
|
@@ -3579,6 +3635,7 @@ const createMiddleware = getCreateFunction((store) => {
|
|
|
3579
3635
|
addWillDelValuesCallback,
|
|
3580
3636
|
addWillDelValueCallback,
|
|
3581
3637
|
addWillApplyChangesCallback,
|
|
3638
|
+
addDidSetRowCallback,
|
|
3582
3639
|
destroy,
|
|
3583
3640
|
});
|
|
3584
3641
|
store.setMiddleware(
|
|
@@ -3596,6 +3653,7 @@ const createMiddleware = getCreateFunction((store) => {
|
|
|
3596
3653
|
willDelValues,
|
|
3597
3654
|
willDelValue,
|
|
3598
3655
|
willApplyChanges,
|
|
3656
|
+
didSetRow,
|
|
3599
3657
|
);
|
|
3600
3658
|
return middleware;
|
|
3601
3659
|
});
|