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),
)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),
)