transaction
The transaction
method takes a function that makes multiple mutations to the Store
, buffering all calls to the relevant listeners until it completes.
transaction<Return>(
actions: () => Return,
doRollback?: DoRollback,
): Return
Type | Description | |
---|---|---|
actions | () => Return | The function to be executed as a transaction. |
doRollback? | DoRollback | An optional callback that should return |
returns | Return | Whatever value the provided transaction function returns. |
This method is useful for making bulk changes to the data in a Store
, and when you don't want listeners to be called as you make each change. Changes
are made silently during the transaction, and listeners relevant to the changes you have made will instead only be called when the whole transaction is complete.
If multiple changes are made to a piece of Store
data throughout the transaction, a relevant listener will only be called with the final value (assuming it is different to the value at the start of the transaction), regardless of the changes that happened in between. For example, if a Cell
had a value 'a'
and then, within a transaction, it was changed to 'b'
and then 'c'
, any CellListener
registered for that cell would be called once as if there had been a single change from 'a'
to 'c'
.
Transactions can be nested. Relevant listeners will be called only when the outermost one completes.
The second, optional parameter, doRollback
is a DoRollback
callback that you can use to rollback the transaction if it did not complete to your satisfaction. See the DoRollback
documentation for more details.
Examples
This example makes changes to two Cells, first outside, and secondly within, a transaction. In the second case, the Row
listener is only called once.
import {createStore} from 'tinybase';
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
store.addRowListener('pets', 'fido', () => console.log('Fido changed'));
store
.setCell('pets', 'fido', 'color', 'brown')
.setCell('pets', 'fido', 'sold', false);
// -> 'Fido changed'
// -> 'Fido changed'
store.transaction(() =>
store
.setCell('pets', 'fido', 'color', 'walnut')
.setCell('pets', 'fido', 'sold', true),
);
// -> 'Fido changed'
This example makes multiple changes to one Cell
. The Cell
listener is called once - and with the final value - only if there is a net overall change.
import {createStore} from 'tinybase';
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
store.addCellListener(
'pets',
'fido',
'color',
(store, tableId, rowId, cellId, newCell) => console.log(newCell),
);
store.transaction(() =>
store
.setCell('pets', 'fido', 'color', 'black')
.setCell('pets', 'fido', 'color', 'brown')
.setCell('pets', 'fido', 'color', 'walnut'),
);
// -> 'walnut'
store.transaction(() =>
store
.setCell('pets', 'fido', 'color', 'black')
.setCell('pets', 'fido', 'color', 'walnut'),
);
// -> undefined
// No net change during the transaction, so the listener is not called.
This example makes multiple changes to the Store
, including some attempts to update a Cell
and Value
with invalid values. The doRollback
callback receives information about the changes and invalid attempts, and then judges that the transaction should be rolled back to its original state.
import {createStore} from 'tinybase';
const store = createStore()
.setTables({pets: {fido: {species: 'dog', color: 'brown'}}})
.setValues({open: true});
store.transaction(
() =>
store
.setCell('pets', 'fido', 'color', 'black')
.setCell('pets', 'fido', 'eyes', ['left', 'right'])
.setCell('pets', 'fido', 'info', {sold: null})
.setValue('open', false)
.setValue('employees', ['alice', 'bob']),
() => {
const [, , changedCells, invalidCells, changedValues, invalidValues] =
store.getTransactionLog();
console.log(store.getTables());
console.log(changedCells);
console.log(invalidCells);
console.log(changedValues);
console.log(invalidValues);
return invalidCells['pets'] != null;
},
);
// -> {pets: {fido: {species: 'dog', color: 'black'}}}
// -> {pets: {fido: {color: ['brown', 'black']}}}
// -> {pets: {fido: {eyes: [['left', 'right']], info: [{sold: null}]}}}
// -> {open: [true, false]}
// -> {employees: [['alice', 'bob']]}
console.log(store.getTables());
// -> {pets: {fido: {species: 'dog', color: 'brown'}}}
console.log(store.getValues());
// -> {open: true}
Since
v1.0.0