Prisma Transaction Rollback with Effects
Hello I've created a little code snippet to wrap an effect so that if it returns failure, it rollback the sql transaction using prisma :
`
And use like
class DatabaseTransactionService extends Context.Tag(
"DatabaseTransactionService",
)<
DatabaseTransactionService,
{
readonly tx: Omit<
PrismaClient<Prisma.PrismaClientOptions, never>,
"$connect" | "$disconnect" | "$on" | "$transaction" | "$use" | "$extends"
>;
}
>() {}
const WithDatabaseTransaction = <T, Err>(
toWrap: Effect.Effect<T, Err, DatabaseTransactionService>,
) => {
return Effect.tryPromise({
try: () =>
db.$transaction(async (tx) => {
const either = await Effect.runPromise(
Effect.either(
toWrap.pipe(
Effect.provide(Layer.succeed(DatabaseTransactionService, { tx })),
),
),
);
return Either.match(either, {
onLeft: (err) => {
throw err;
},
onRight: (val) => val,
});
}),
catch(error: unknown) {
return error as Err;
},
});
};class DatabaseTransactionService extends Context.Tag(
"DatabaseTransactionService",
)<
DatabaseTransactionService,
{
readonly tx: Omit<
PrismaClient<Prisma.PrismaClientOptions, never>,
"$connect" | "$disconnect" | "$on" | "$transaction" | "$use" | "$extends"
>;
}
>() {}
const WithDatabaseTransaction = <T, Err>(
toWrap: Effect.Effect<T, Err, DatabaseTransactionService>,
) => {
return Effect.tryPromise({
try: () =>
db.$transaction(async (tx) => {
const either = await Effect.runPromise(
Effect.either(
toWrap.pipe(
Effect.provide(Layer.succeed(DatabaseTransactionService, { tx })),
),
),
);
return Either.match(either, {
onLeft: (err) => {
throw err;
},
onRight: (val) => val,
});
}),
catch(error: unknown) {
return error as Err;
},
});
};And use like
const effect = Effect.gen(function* () {
const { tx } = yield* DatabaseTransactionService;
yield* Effect.promise(() =>
tx.entity.create({
data: {
id: "fK_1234,
firstname: "should not be created",
lastname: "should not be created",
},
}),
);
return yield* Effect.fail("Should rollback");
}); const effect = Effect.gen(function* () {
const { tx } = yield* DatabaseTransactionService;
yield* Effect.promise(() =>
tx.entity.create({
data: {
id: "fK_1234,
firstname: "should not be created",
lastname: "should not be created",
},
}),
);
return yield* Effect.fail("Should rollback");
});