Skip to content

Instantly share code, notes, and snippets.

@arekmaz
Created October 27, 2023 14:59
Show Gist options
  • Save arekmaz/6fdcf9e84e7f7a46172ce256e81a403b to your computer and use it in GitHub Desktop.
Save arekmaz/6fdcf9e84e7f7a46172ce256e81a403b to your computer and use it in GitHub Desktop.
prisma + effect-ts integration - client which returns effects instead of promises
import { db } from "../services/db.server";
import { Data, Effect } from "effect";
import type { 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>
? <R, E>(...a: Args) => Effect.Effect<R, E, Result>
: 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]>;
};
const createEffectClient = () => {
return new Proxy(
{},
{
get(_target, model) {
return new Proxy(
{},
{
get(_target, method) {
return (...args: any[]) =>
Effect.tryPromise(() => (db as any)[model][method](...args));
},
}
);
},
}
) as EffectPrisma;
};
// example usage:
// standard prisma:
const a = await db.log.findMany();
// a: {
// id: number;
// date: Date;
// login: string | null;
// info: string | null;
// }[]
// standard prisma:
const e = createEffectClient().log.findMany();
// Effect.Effect<unknown, unknown, {
// id: number;
// date: Date;
// login: string | null;
// info: string | null;
// }[]>
const e1 = createEffectClient().log.findMany<never, PrismaError>();
// Effect.Effect<never, PrismaError, {
// id: number;
// date: Date;
// login: string | null;
// info: string | null;
// }[]>
@IRediTOTO
Copy link

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment