mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-11-16 12:00:24 +00:00
add TransactionsDSL
This commit is contained in:
82
transactions/src/commonMain/kotlin/TransactionsDSL.kt
Normal file
82
transactions/src/commonMain/kotlin/TransactionsDSL.kt
Normal file
@@ -0,0 +1,82 @@
|
||||
package dev.inmo.micro_utils.transactions
|
||||
|
||||
typealias TransactionDSLRollbackLambda = suspend (Throwable) -> Unit
|
||||
class TransactionsDSL internal constructor() {
|
||||
internal val rollbackActions = LinkedHashSet<TransactionDSLRollbackLambda>()
|
||||
|
||||
internal fun addRollbackAction(rollbackAction: TransactionDSLRollbackLambda) {
|
||||
rollbackActions.add(rollbackAction)
|
||||
}
|
||||
}
|
||||
class RollbackContext<T> internal constructor (
|
||||
val actionResult: T,
|
||||
val error: Throwable
|
||||
)
|
||||
|
||||
/**
|
||||
* Calls [action] and, if it succeeded - saving [rollback] action for future usage for cases when some other
|
||||
* action or even main one throwing an error
|
||||
*
|
||||
* @param rollback Will be called if
|
||||
*/
|
||||
suspend fun <T> TransactionsDSL.rollbackableOperation(
|
||||
rollback: suspend RollbackContext<T>.() -> Unit,
|
||||
action: suspend () -> T
|
||||
): T {
|
||||
return runCatching { action() }
|
||||
.onSuccess {
|
||||
addRollbackAction { e ->
|
||||
val context = RollbackContext(it, e)
|
||||
context.rollback()
|
||||
}
|
||||
}
|
||||
.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts transaction with opportunity to add actions [rollbackableOperation]. How to use:
|
||||
*
|
||||
* ```kotlin
|
||||
* doSuspendTransaction {
|
||||
* println("start of action")
|
||||
*
|
||||
* withRollback({ // it - result of action
|
||||
* // some rollback action
|
||||
* }) {
|
||||
* // Some action with rollback
|
||||
* }
|
||||
*
|
||||
* withRollback({
|
||||
* repository.delete(it) // it - result of createSomething, if it completes successfully
|
||||
* }) {
|
||||
* repository.createSomething()
|
||||
* }
|
||||
*
|
||||
* withRollback({
|
||||
* // will not be triggered due to error in action
|
||||
* }) {
|
||||
* error("It is just a simple error") // Will trigger rolling back previously successfully completed actions
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param onRollbackStepError Will be called if rollback action throwing some error
|
||||
*/
|
||||
suspend fun <T> doSuspendTransaction(
|
||||
onRollbackStepError: suspend (TransactionDSLRollbackLambda, Throwable) -> Unit = { _, _ -> },
|
||||
block: suspend TransactionsDSL.() -> T
|
||||
): Result<T> {
|
||||
val transactionsDSL = TransactionsDSL()
|
||||
|
||||
return runCatching {
|
||||
transactionsDSL.block()
|
||||
}.onFailure { e ->
|
||||
transactionsDSL.rollbackActions.forEach {
|
||||
runCatching {
|
||||
it.invoke(e)
|
||||
}.onFailure { ee ->
|
||||
onRollbackStepError(it, ee)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user