transactionResult

open fun <T> transactionResult(propagation: TransactionPropagation = TransactionPropagation.REQUIRED, isolation: TransactionIsolationLevel? = null, readOnly: Boolean = false, statementTimeout: Duration? = null, transactionTimeout: Duration? = null, block: OctaviusClient.() -> DataResult<T>): DataResult<T>

Runs block in a transaction that understands a returned failure, and hands back what it produced.

This is transaction for the result style, and it exists because the two do not compose by themselves. A plain transaction rolls back on a throw and on nothing else, so a dbResult inside one turns the failure into a value, the block finishes normally, and the transaction commits over the very failure that was caught - the same trap runCatching sets in the same place. Here a returned DataResult.Failure rolls back, and comes out as the value it already was.

val created = db.transactionResult {
val id = rawQuery("INSERT INTO citizens (name) VALUES (@n) RETURNING id")
.asResult().fetchFieldStrict<Int>("n" to name)
.getOrElse { return@transactionResult it }

rawQuery("INSERT INTO citizen_profiles (citizen_id, bio) VALUES (@id, @bio)")
.asResult().update("id" to id, "bio" to bio)
.map { id }
}

Three ways out, and they are not the same:

  • DataResult.Success. The transaction commits and that result is returned.

  • DataResult.Failure. The transaction rolls back and that same failure is returned. A failure that reached the return value is one the block chose not to handle, so it takes the transaction with it.

  • A throw. The transaction rolls back. A database failure the boundary counts as recoverable comes back as a DataResult.Failure; anything else - an exception from your own code, a bug the boundary counts as fatal - keeps going up. A NullPointerException in the block is a bug in the block, and turning it into a value would only hide it.

Everything else is transaction's: the receiver, the propagation, the per-thread binding.

Return

What the block produced, or the failure that rolled it back.

Parameters

propagation

What to do about a transaction already running on this thread.

isolation

The isolation level to run at, or null for the server's.

readOnly

Whether the transaction refuses writes.

statementTimeout

Aborts any single statement running longer than this.

transactionTimeout

Aborts the transaction once it has been open longer than this.

block

The work to run in the transaction.