TinyBase logoTinyBase

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
TypeDescription
actions() => Return

The function to be executed as a transaction.

doRollback?DoRollback

An optional callback that should return true if you want to rollback the transaction at the end. Since v1.2.

returnsReturn

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. It is called with getTransactionChanges and getTransactionLog parameters, which inform you of the net changes that have been made during the transaction, at different levels of detail. 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.

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.

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.

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']),
  (_, getTransactionLog) => {
    const {changedCells, invalidCells, changedValues, invalidValues} =
      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}