How to Temporarily Override a Layer at Runtime in Effect Typescript
Question from X: Is it possible to temporarily override a layer at runtime?
For example, I have a Prisma service that sometimes I want to override the prisma context to be a prisma transaction context.
I don't want to have to call runPromise again though because I understand thats bad
For example, I have a Prisma service that sometimes I want to override the prisma context to be a prisma transaction context.
I don't want to have to call runPromise again though because I understand thats bad
import { Effect, Layer } from "effect"
import { DatabaseClientTag } from "@myapp/db"
import { TransactionServiceTag, TransactionError } from "@myapp/contracts"
export const TransactionServiceLive = Layer.effect(
TransactionServiceTag,
Effect.gen(function* () {
const { prisma } = yield* DatabaseClientTag
return {
withTransaction: <A, E, R>(
operation: Effect.Effect<A, E, R>
): Effect.Effect<A, E | TransactionError, R> =>
Effect.async<A, E | TransactionError, R>((resume) => {
prisma.$transaction(async (tx) => {
try {
// Create transaction layer
const transactionLayer = Layer.succeed(
DatabaseClientTag,
{ prisma: tx }
)
// Provide transaction layer to the operation
const result = await Effect.runPromise(
Effect.provide(operation, transactionLayer)
)
resume(Effect.succeed(result))
} catch (error) {
resume(Effect.fail(new TransactionError(`Transaction failed: ${error}`)))
}
}).catch((error) => {
resume(Effect.fail(new TransactionError(`Transaction setup failed: ${error}`)))
})
})
}
})
)import { Effect, Layer } from "effect"
import { DatabaseClientTag } from "@myapp/db"
import { TransactionServiceTag, TransactionError } from "@myapp/contracts"
export const TransactionServiceLive = Layer.effect(
TransactionServiceTag,
Effect.gen(function* () {
const { prisma } = yield* DatabaseClientTag
return {
withTransaction: <A, E, R>(
operation: Effect.Effect<A, E, R>
): Effect.Effect<A, E | TransactionError, R> =>
Effect.async<A, E | TransactionError, R>((resume) => {
prisma.$transaction(async (tx) => {
try {
// Create transaction layer
const transactionLayer = Layer.succeed(
DatabaseClientTag,
{ prisma: tx }
)
// Provide transaction layer to the operation
const result = await Effect.runPromise(
Effect.provide(operation, transactionLayer)
)
resume(Effect.succeed(result))
} catch (error) {
resume(Effect.fail(new TransactionError(`Transaction failed: ${error}`)))
}
}).catch((error) => {
resume(Effect.fail(new TransactionError(`Transaction setup failed: ${error}`)))
})
})
}
})
)