mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-03 21:51:59 +00:00 
			
		
		
		
	add TransactionsDSL
This commit is contained in:
		@@ -4,6 +4,8 @@
 | 
			
		||||
 | 
			
		||||
* `Coroutines`:
 | 
			
		||||
  * Add extensions `SmartRWLocker.alsoWithUnlockingOnSuccessAsync` and `SmartRWLocker.alsoWithUnlockingOnSuccess`
 | 
			
		||||
* `Transactions`:
 | 
			
		||||
  * Add `TransactionsDSL`
 | 
			
		||||
 | 
			
		||||
## 0.25.2
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ rootProject.name='micro_utils'
 | 
			
		||||
String[] includes = [
 | 
			
		||||
    ":common",
 | 
			
		||||
    ":common:compose",
 | 
			
		||||
    ":transactions",
 | 
			
		||||
    ":matrix",
 | 
			
		||||
    ":safe_wrapper",
 | 
			
		||||
    ":crypto",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								transactions/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								transactions/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id "org.jetbrains.kotlin.multiplatform"
 | 
			
		||||
    id "org.jetbrains.kotlin.plugin.serialization"
 | 
			
		||||
    id "com.android.library"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
 | 
			
		||||
							
								
								
									
										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