Last active
August 26, 2024 11:47
-
-
Save JPBM135/b229bb9d15a3f1482af94da3e342b6eb to your computer and use it in GitHub Desktop.
PrismaGenericbaseService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { IPaginatedType } from "@common/generics/paginated.type"; | |
import { useConnection } from "@common/utils/connection"; | |
import { paginated } from "@common/utils/paginated"; | |
import { PrismaService } from "@infra/prisma/pprisma.service"; | |
import { Prisma } from "@prisma/client"; | |
import { Result } from "@prisma/client/runtime/library"; | |
type PrismaModelsUnion = Prisma.TypeMap["meta"]["modelProps"]; | |
// Get the model type from the prisma client based on the model name | |
type PrismaModel<M extends PrismaModelsUnion> = Prisma.TypeMap["model"][Capitalize<M>]; | |
// Get all in common operations for all models | |
type OperationType = keyof PrismaModel<PrismaModelsUnion>["operations"]; | |
// Get the arguments for each operation | |
type OperationArguments<M extends PrismaModelsUnion, O extends OperationType> = PrismaModel<M>["operations"][O]["args"]; | |
// The `Result` requires this specific structure to work, thanks 3d triangle | |
type InternalPrismaReturnMethod<M extends PrismaModelsUnion> = { | |
[K: symbol]: { | |
types: { | |
payload: PrismaModel<M>["payload"]; | |
}; | |
}; | |
}; | |
// The return type for each operation, needs to change based on the arguments provided | |
type OperationReturnType<M extends PrismaModelsUnion, O extends OperationType, A> = Result<InternalPrismaReturnMethod<M>, A, O>; | |
export class BaseService<T extends PrismaModelsUnion> { | |
protected readonly prismaService: PrismaService; | |
private readonly tableName: T; | |
constructor(prismaService: PrismaService, tableName: T) { | |
this.prismaService = prismaService; | |
this.tableName = tableName; | |
} | |
async findMany<A extends OperationArguments<T, "findMany">>(args: A): Promise<IPaginatedType<OperationReturnType<T, "findMany", A>>> { | |
const [totalCount, edges] = await Promise.all([ | |
this.callPrismaOperation("count", { | |
where: args.where, | |
} as OperationArguments<T, "count">), | |
this.callPrismaOperation("findMany", args as OperationArguments<T, "findMany">), | |
]); | |
const connections = useConnection(edges as (PrismaModel<T> & { created_at: Date })[]); | |
return paginated(connections, totalCount as number); | |
} | |
async findFirst<A extends OperationArguments<T, "findFirst">>(args: A): Promise<OperationReturnType<T, "findFirst", A>> { | |
return this.callPrismaOperation("findFirst", args); | |
} | |
async create<A extends OperationArguments<T, "create">>(args: A): Promise<OperationReturnType<T, "create", A>> { | |
return this.callPrismaOperation("create", args); | |
} | |
async update<A extends OperationArguments<T, "update">>(args: A): Promise<OperationReturnType<T, "update", A>> { | |
return this.callPrismaOperation("update", args); | |
} | |
async delete<A extends OperationArguments<T, "delete">>(args: A): Promise<OperationReturnType<T, "delete", A>> { | |
return this.callPrismaOperation("delete", args); | |
} | |
/** | |
* Ultra hacky way to call prisma operations dynamically and still have type safety. | |
*/ | |
private callPrismaOperation<O extends OperationType, A extends OperationArguments<T, O>>( | |
operation: O, | |
args: A, | |
): Promise<OperationReturnType<T, O, A>> { | |
return ( | |
this.prismaService[this.tableName] as { | |
[K in O]: (...args: any) => any; | |
} | |
)[operation](args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment