Skip to content

Instantly share code, notes, and snippets.

@adamgoose
Forked from arekmaz/prisma-effect.ts
Created February 9, 2025 19:51
Show Gist options
  • Save adamgoose/58e2ba1c8160d9e4760eb075ff9e9d03 to your computer and use it in GitHub Desktop.
Save adamgoose/58e2ba1c8160d9e4760eb075ff9e9d03 to your computer and use it in GitHub Desktop.
prisma + effect-ts integration - client which returns effects instead of promises
import { Data, Effect } from "effect";
import { Prisma, PrismaClient } from "@prisma/client";
import type {
PrismaClientKnownRequestError,
PrismaClientUnknownRequestError,
PrismaClientRustPanicError,
PrismaClientInitializationError,
PrismaClientValidationError,
} from "@prisma/client/runtime/library";
export class PrismaError extends Data.TaggedError("PrismaError")<{
details:
| PrismaClientKnownRequestError
| PrismaClientUnknownRequestError
| PrismaClientRustPanicError
| PrismaClientInitializationError
| PrismaClientValidationError;
}> {}
type FilterNotContaining<
Set,
Needle extends string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
> = Set extends `${infer _A}${Needle}${infer _B}` ? never : Set;
type ExcludeFromUnionOtherTypes<From, E> = From extends E ? From : never;
type ExcludeNonStringKeys<Obj> = {
[k in ExcludeFromUnionOtherTypes<keyof Obj, string>]: k extends string
? Obj[k]
: never;
};
type ExcludeKeysContaining<
Obj extends Record<string, any>,
Key extends string,
> = {
[key in FilterNotContaining<keyof Obj, Key>]: Obj[key];
};
export type Client = ExcludeKeysContaining<
ExcludeNonStringKeys<PrismaClient>,
"$" | "_"
> & {};
type LazyPromiseToLazyEffect<Fn extends (...a: any[]) => any> = Fn extends (
...a: infer Args
) => Promise<infer Result>
? (...a: Args) => Effect.Effect<Result, PrismaError, never>
: never;
type EffectifyObject<
Obj extends Record<string, F>,
F extends (...a: any[]) => any = any,
> = {
[op in keyof Obj]: LazyPromiseToLazyEffect<Obj[op]>;
};
type EffectPrisma = {
[model in keyof Client]: EffectifyObject<Client[model]>;
};
export class PrismaService extends Effect.Service<PrismaService>()("Prisma", {
sync: () => {
const prisma = new PrismaClient();
return new Proxy(
{},
{
getOwnPropertyDescriptor() {
return {
enumerable: true,
configurable: true,
};
},
ownKeys() {
return Object.values(Prisma.ModelName);
},
get(_target, model) {
return new Proxy(
{},
{
get(_target, method) {
return (...args: any[]) =>
Effect.tryPromise(() =>
(prisma as any)[model][method](...args),
);
},
},
);
},
},
) as EffectPrisma;
},
}) {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment