transactionMiddleware
Overview
The transaction middleware makes a model action or flow atomic: if it throws, changes made during that action and its child actions are reverted before the error is rethrown.
The rollback restores the values each change replaced, so the nodes the action removed, moved or edited are the same instances afterwards. If a patch listener or patch recorder throws during rollback, the remaining restoration is still attempted. If rollback succeeds, the original action error is rethrown unchanged. If any rollback callback fails, a MobxKeystoneAggregateError is thrown instead: its first error is the original action error, followed by the rollback callback failures.
Mark an action or flow as a transaction either with the @transaction decorator or by attaching transactionMiddleware programmatically.
As a decorator:
@model("MyApp/MyBalance")
class MyBalance extends Model({
balance: prop<number>(),
}) {
@transaction
@modelAction
addMoney(cents: number) {
this.balance += cents
// imagine that something else goes wrong
// in this case balance will be reverted to the value that
// was there before the action started
throw new Error("...")
}
}
Programmatically:
@model("MyApp/MyBalance")
class MyBalance extends Model({
balance: prop<number>(),
}) {
@modelAction
addMoney(cents: number) {
this.balance += cents
// imagine that something else goes wrong
// in this case balance will be reverted to the value that
// was there before the action started
throw new Error("...")
}
// we could for example add it on init (for all instances)
onInit() {
transactionMiddleware({
model: this,
actionName: "addMoney",
})
}
}
// or for a particular instance
const myBalance = new MyBalance({ balance: 100 })
transactionMiddleware({
model: myBalance,
actionName: "addMoney",
})