Effect CommunityEC
Effect Community16mo ago
23 replies
Chris

Implementing Rollbacks, inferring types from effect returned from function

I'm building some utility to standardise how I deal with "soft transactions" aka roll back changes if they failed some latter steps, Using acquireRelease to so so but having a hard time infering the R from the effect inside, not even sure it is possible tbh, This is the 2 approaches I came up with so far:
type TransactionResource<R = never> = {
    addRollbackEffect: (rollbackEffect: RollbackEffect<R>) => void
    rollbackEffects: RollbackEffect<R>[]
}

type RollbackEffect<R = never> = Effect.Effect<void, never, R>

const Transaction = <R = never>() =>
    Effect.acquireRelease(
        Effect.sync(() => {
            const rollbackEffects: RollbackEffect<R>[] = []
            const addRollbackEffect = (rollbackEffect: RollbackEffect<R>) => {
                rollbackEffects.push(rollbackEffect)
            }
            return { addRollbackEffect, rollbackEffects }
        }),
        (transaction: TransactionResource<R>, exit: Exit<unknown, unknown>) =>
            exit._tag === 'Failure'
                ? Effect.all(transaction.rollbackEffects.slice().reverse(), {
                      concurrency: 1,
                  })
                : Effect.succeed(undefined),
    )

const TransactionScope = <A, E, R>(
    eff: (tx: TransactionResource<R>) => Effect.Effect<A, E, R>,
) =>
    Effect.acquireUseRelease(
        Effect.sync(() => {
            const rollbackEffects: RollbackEffect<R>[] = []
            const addRollbackEffect = (rollbackEffect: RollbackEffect<R>) => {
                rollbackEffects.push(rollbackEffect)
            }
            return { addRollbackEffect, rollbackEffects }
        }),
        eff,
        (transaction: TransactionResource<R>, exit: Exit<unknown, unknown>) =>
            exit._tag === 'Failure'
                ? Effect.all(transaction.rollbackEffects.slice().reverse(), {
                      concurrency: 1,
                  })
                : Effect.succeed(undefined),
    )
Was this page helpful?