@@ -33,7 +33,7 @@ console.log(store.getValue('shopName'));
3333
3434## Available Callbacks
3535
36- A Middleware object supports 14 different callbacks that you can register. Each
36+ A Middleware object supports 15 different callbacks that you can register. Each
3737callback is passed relevant parameters for the operation, and can return a
3838value. The meaning of this return value depends on the type of callback:
3939
@@ -42,6 +42,9 @@ value. The meaning of this return value depends on the type of callback:
4242 If the function returns undefined (or void), the operation is cancelled.
4343* For ` willDel* ` callbacks, the return value is a boolean that indicates whether
4444 the delete operation should proceed (true) or be cancelled (false).
45+ * For ` didSetRow ` , the return value is the final Row state to apply. Return
46+ ` newRow ` to accept, a different ` Row ` to replace, ` oldRow ` to revert, or an
47+ empty object to delete. See below for more details.
4548
4649The full list of ` willSet* ` callbacks you can register is as follows:
4750
@@ -56,7 +59,16 @@ The full list of `willSet*` callbacks you can register is as follows:
5659| willSetValue | valueId, value | When setValue is called. | Value or undefined |
5760| willApplyChanges | changes | When applyChanges is called. | Changes or undefined |
5861
59- The full list of ` willDel* ` callbacks you can register is as follows:
62+ There is also one special ` did* ` callback that is called at the end of the
63+ transaction - after all ` will* ` callbacks have settled and before any listeners
64+ are called. This gives you a chance to inspect or validate the final state of a
65+ Row for a specific table:
66+
67+ | Callback | Parameters | Called | Return |
68+ | --------- | ------------------------------ | ---------------------------------------------- | ------ |
69+ | didSetRow | tableId, rowId, oldRow, newRow | After all row changes settle in a transaction. | Row |
70+
71+ Finally, the full list of ` willDel* ` callbacks you can register is as follows:
6072
6173| Callback | Parameters | Called | Return |
6274| ------------- | ---------------------- | ------------------------- | ------- |
@@ -164,8 +176,8 @@ might prefer to use the more granular Cell and Value callbacks where possible.
164176## Middleware And Listeners
165177
166178Mutator listeners (that is, listeners registered with the ` isMutator ` flag set
167- to ` true ` ) are allowed to write data back to the Store during a transaction.
168- Any writes made by a mutator listener will also pass through the middleware
179+ to ` true ` ) are allowed to write data back to the Store during a transaction. Any
180+ writes made by a mutator listener will also pass through the middleware
169181pipeline:
170182
171183``` js
@@ -187,6 +199,55 @@ console.log(store.getCell('pets', 'fido', 'slug'));
187199In the example above, both the original ` setCell ` call and the listener's
188200` setCell ` call pass through the uppercase middleware.
189201
202+ ## Post-Transaction Row Callback
203+
204+ The ` will* ` callbacks fire synchronously as each write happens. Sometimes you
205+ want to inspect or validate a Row * after* all the dust has settled — after every
206+ cell change in a transaction has been applied and the Row is in its final state.
207+ That's what ` didSetRow ` is for.
208+
209+ ` addDidSetRowCallback ` is ** table-scoped** : you register it for a specific
210+ table, so there is zero overhead for tables you don't care about.
211+
212+ ``` js
213+ const store2 = createStore ();
214+ const middleware2 = createMiddleware (store2);
215+
216+ middleware2 .addDidSetRowCallback (' pets' , (tableId , rowId , oldRow , newRow ) => {
217+ // Require 'species' — revert rows that don't have it
218+ return ' species' in newRow ? newRow : oldRow;
219+ });
220+
221+ store2 .setRow (' pets' , ' fido' , {species: ' dog' , name: ' Fido' });
222+ console .log (store2 .getRow (' pets' , ' fido' ));
223+ // -> {species: 'dog', name: 'Fido'}
224+
225+ store2 .setRow (' pets' , ' nemo' , {name: ' Nemo' });
226+ console .log (store2 .getRow (' pets' , ' nemo' ));
227+ // -> {}
228+ ```
229+
230+ The callback receives ` oldRow ` (the Row as it was at the start of the
231+ transaction), and ` newRow ` (the Row as it is now, after all cell writes).
232+
233+ The callback needs to return the Row that should be the final state of the Row
234+ after any corrections. Return:
235+
236+ - ` newRow ` to accept the changes.
237+ - a different ` Row ` to replace the final state.
238+ - ` oldRow ` to revert all changes to the Row.
239+ - an empty object to delete the Row.
240+
241+ Unlike ` willSet* ` callbacks, the ` didSetRow ` chain never short-circuits: all
242+ registered callbacks for the table always run, each receiving the Row returned
243+ by the previous one.
244+
245+ Because ` didSetRow ` fires * after* mutating listeners, ` newRow ` reflects the
246+ truly final state of the Row — including any writes those listeners made.
247+
248+ Also note that multiple cell changes to the same Row within one transaction
249+ produce only one ` didSetRow ` call, not one per cell.
250+
190251## Middleware And Schemas
191252
192253The callbacks are called after the schema has been applied to the data. So, for
0 commit comments