63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
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<typeof createExtendedClient>;
|
|
|
|
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<UserModel> {
|
|
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<T>(
|
|
command: (prisma: SafeClient) => Promise<T>,
|
|
request: Request | null,
|
|
): Promise<T> {
|
|
const transaction: SafeClient | null = (request as any | null)
|
|
?.transaction;
|
|
const effectiveClient = transaction ?? this.prismaClient;
|
|
return await command(effectiveClient);
|
|
}
|
|
}
|