Updated on 2026-08-14
This commit is contained in:
parent
c3d8722f57
commit
4589332282
10 changed files with 233 additions and 13 deletions
|
|
@ -1,7 +1,19 @@
|
|||
package com.tangem.domain.core.chain
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.EitherNel
|
||||
|
||||
/**
|
||||
* A chain in the [ChainProcessor] class for processing a chain of operations with the ability to handle errors.
|
||||
* @param E the type of error
|
||||
* @param R the type of result
|
||||
*/
|
||||
interface Chain<E, R> {
|
||||
suspend operator fun invoke(previousChainResult: Either<E, R>): Either<E, R>
|
||||
|
||||
/**
|
||||
* Invokes the chain with the previous chain result as input and returns an [Either] result.
|
||||
* @param previousChainResult the previous chain result as an [EitherNel]
|
||||
* @return the result of the chain processing as an [Either]
|
||||
*/
|
||||
suspend operator fun invoke(previousChainResult: EitherNel<E, R>): Either<E, R>
|
||||
}
|
||||
|
|
@ -1,28 +1,63 @@
|
|||
package com.tangem.domain.core.chain
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.EitherNel
|
||||
import arrow.core.left
|
||||
import arrow.core.nel
|
||||
import arrow.core.right
|
||||
import arrow.core.toEitherNel
|
||||
|
||||
/**
|
||||
* A class for processing a chain of operations with the ability to handle errors.
|
||||
* @param E the type of error
|
||||
* @param R the type of result
|
||||
*/
|
||||
class ChainProcessor<E, R> {
|
||||
|
||||
/**
|
||||
* The list of chains to be executed in order.
|
||||
*/
|
||||
private val chains: MutableList<Chain<E, R>> = mutableListOf()
|
||||
|
||||
/**
|
||||
* Adds chains to the existing list of chains to be executed.
|
||||
* @param chains the chains to be added to the list
|
||||
*/
|
||||
fun addChains(vararg chains: Chain<E, R>) {
|
||||
this.chains.addAll(chains)
|
||||
}
|
||||
|
||||
suspend fun launchChains(initial: R, returnOnFirstError: Boolean = true): Either<E, R> {
|
||||
return launchChains(initial = Either.Right(initial), returnOnFirstError)
|
||||
}
|
||||
|
||||
private suspend fun launchChains(initial: Either<E, R>, returnOnFirstError: Boolean = true): Either<E, R> {
|
||||
var result = initial
|
||||
|
||||
chains.forEach { chain ->
|
||||
result = chain(result)
|
||||
.onRight {
|
||||
if (returnOnFirstError) return result
|
||||
/**
|
||||
* Launches the chains with the given initial value as input.
|
||||
* @param initial the initial value to start the chain processing.
|
||||
* @param accumulateExceptions determines whether to accumulate exceptions or break on first exception.
|
||||
* Defaults to true.
|
||||
* @return the result of the chain processing as an EitherNel, which is a disjunction that may contain multiple errors.
|
||||
*/
|
||||
private suspend fun launchChains(initial: Either<E, R>, accumulateExceptions: Boolean = true): EitherNel<E, R> {
|
||||
return chains.fold(initial.toEitherNel()) { previousChainResult, chain ->
|
||||
chain.invoke(previousChainResult)
|
||||
.mapLeft { e ->
|
||||
previousChainResult.leftOrNull()?.plus(e)
|
||||
?: e.nel()
|
||||
}
|
||||
.onLeft { e ->
|
||||
if (!accumulateExceptions) {
|
||||
return e.left()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
/**
|
||||
* Launches the chains with the given initial value as input.
|
||||
* This function is a convenience function that assumes the initial value does not contain any errors.
|
||||
* @param initial the initial value to start the chain processing.
|
||||
* @param accumulateExceptions determines whether to accumulate exceptions or break on first exception.
|
||||
* Defaults to true.
|
||||
* @return the result of the chain processing as an EitherNel, which is a disjunction that may contain multiple errors.
|
||||
*/
|
||||
suspend fun launchChains(initial: R, accumulateExceptions: Boolean = true): EitherNel<E, R> {
|
||||
return launchChains(initial.right(), accumulateExceptions)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue