import { PrismaPg } from "@prisma/adapter-pg"; import { type Request } from "express"; import { PrismaClient } from "../../generated/prisma/client.js"; import type { UserModel } from "../../generated/prisma/models.js"; import { Injectable } from "../../infrastructure/di/injectable-decorator.js"; type ExtendedClient = ReturnType; export type SafeClient = Omit< ExtendedClient, | "$connect" | "$disconnect" | "$on" | "$transaction" | "$executeRaw" | "$executeRawUnsafe" | "$queryRaw" | "$queryRawUnsafe" | "$extends" >; function createExtendedClient(client: PrismaClient) { return client.$extends({ client: { async ensureUserKnown(userId: string): Promise { let user = await client.user.findUnique({ where: { id: userId }, }); if (user == null) { user = await client.user.create({ data: { id: userId } }); } return user; }, }, }); } @Injectable() export class DatabaseService { private readonly prismaClient: ExtendedClient; public constructor() { const dbUser = process.env["TKD_DB_USER"]!; const dbPassword = process.env["TKD_DB_PASSWORD"]!; const dbHost = process.env["TKD_DB_HOST"]!; const connectionString = `postgresql://${dbUser}:${dbPassword}@${dbHost}:5432/taekwondo?schema=public`; const adapter = new PrismaPg({ connectionString }); this.prismaClient = createExtendedClient(new PrismaClient({ adapter })); } public async doRequest( command: (prisma: SafeClient) => Promise, request: Request | null, ): Promise { const transaction: SafeClient | null = (request as any | null) ?.transaction; const effectiveClient = transaction ?? this.prismaClient; return await command(effectiveClient); } }