refactor(server): config system (#11081)

This commit is contained in:
forehalo
2025-03-27 12:32:28 +00:00
parent 7091111f85
commit 0ea38680fa
274 changed files with 7583 additions and 5841 deletions
@@ -1,17 +1,27 @@
import type { Prisma } from '@prisma/client';
import { z } from 'zod';
import { defineStartupConfig, ModuleConfig } from '../config';
import { defineModuleConfig } from '../config';
interface PrismaStartupConfiguration extends Prisma.PrismaClientOptions {
datasourceUrl: string;
}
declare module '../config' {
interface AppConfig {
prisma: ModuleConfig<PrismaStartupConfiguration>;
declare global {
interface AppConfigSchema {
db: {
datasourceUrl: string;
prisma: ConfigItem<Prisma.PrismaClientOptions>;
};
}
}
defineStartupConfig('prisma', {
datasourceUrl: '',
defineModuleConfig('db', {
datasourceUrl: {
desc: 'The datasource url for the prisma client.',
default: 'postgresql://localhost:5432/affine',
env: 'DATABASE_URL',
shape: z.string().url(),
},
prisma: {
desc: 'The config for the prisma client.',
default: {},
link: 'https://www.prisma.io/docs/reference/api-reference/prisma-client-reference',
},
});
@@ -0,0 +1,25 @@
import type { OnModuleDestroy } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { Config } from '../config';
@Injectable()
export class PrismaFactory implements OnModuleDestroy {
static INSTANCE: PrismaClient | null = null;
readonly #instance: PrismaClient;
constructor(config: Config) {
this.#instance = new PrismaClient(config.db.prisma);
PrismaFactory.INSTANCE = this.#instance;
}
get() {
return this.#instance;
}
async onModuleDestroy() {
await PrismaFactory.INSTANCE?.$disconnect();
PrismaFactory.INSTANCE = null;
}
}
@@ -3,29 +3,24 @@ import './config';
import { Global, Module, Provider } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { Config } from '../config';
import { PrismaService } from './service';
import { PrismaFactory } from './factory';
// only `PrismaClient` can be injected
const clientProvider: Provider = {
provide: PrismaClient,
useFactory: (config: Config) => {
if (PrismaService.INSTANCE) {
return PrismaService.INSTANCE;
}
return new PrismaService(config.prisma);
useFactory: (factory: PrismaFactory) => {
return factory.get();
},
inject: [Config],
inject: [PrismaFactory],
};
@Global()
@Module({
providers: [clientProvider],
providers: [PrismaFactory, clientProvider],
exports: [clientProvider],
})
export class PrismaModule {}
export { PrismaService } from './service';
export { PrismaFactory };
export type PrismaTransaction = Parameters<
Parameters<PrismaClient['$transaction']>[0]
@@ -1,27 +0,0 @@
import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { Prisma, PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit, OnApplicationShutdown
{
static INSTANCE: PrismaService | null = null;
constructor(opts: Prisma.PrismaClientOptions) {
super(opts);
PrismaService.INSTANCE = this;
}
async onModuleInit() {
await this.$connect();
}
async onApplicationShutdown(): Promise<void> {
if (!AFFiNE.node.test) {
await this.$disconnect();
PrismaService.INSTANCE = null;
}
}
}