chore(repo) init AppDatabase module
This commit is contained in:
parent
9f35377481
commit
0d60b73816
@ -1,11 +1,12 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { AppConfigModule } from './modules/config/config.module';
|
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
|
import { AppConfigModule } from './modules/config/config.module';
|
||||||
|
import { AppDatabaseModule } from './modules/database/database.module';
|
||||||
import { AppLoggerModule } from './modules/logger/logger.module';
|
import { AppLoggerModule } from './modules/logger/logger.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [AppConfigModule, AppLoggerModule],
|
imports: [AppConfigModule, AppLoggerModule, AppDatabaseModule],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
})
|
})
|
||||||
|
63
apps/ebitemp-api/src/app/config/database.config.ts
Normal file
63
apps/ebitemp-api/src/app/config/database.config.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { registerAs } from '@nestjs/config';
|
||||||
|
import { ConnectionString } from 'connection-string';
|
||||||
|
import { first } from 'lodash';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import coerceRecordTypes from '../modules/config/coerce-record-types';
|
||||||
|
|
||||||
|
export const databaseSchema = z.object({
|
||||||
|
connectionString: z.string(),
|
||||||
|
type: z.enum([
|
||||||
|
'mysql',
|
||||||
|
'postgres',
|
||||||
|
'cockroachdb',
|
||||||
|
'sap',
|
||||||
|
'mariadb',
|
||||||
|
'sqlite',
|
||||||
|
'cordova',
|
||||||
|
'react-native',
|
||||||
|
'nativescript',
|
||||||
|
'sqljs',
|
||||||
|
'oracle',
|
||||||
|
'mssql',
|
||||||
|
'mongodb',
|
||||||
|
'aurora-mysql',
|
||||||
|
'aurora-postgres',
|
||||||
|
'expo',
|
||||||
|
'better-sqlite3',
|
||||||
|
'capacitor',
|
||||||
|
'spanner',
|
||||||
|
]),
|
||||||
|
host: z.string(),
|
||||||
|
port: z.number().optional(),
|
||||||
|
username: z.string(),
|
||||||
|
password: z.string(),
|
||||||
|
database: z.string(),
|
||||||
|
secure: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type DatabaseConfig = z.TypeOf<typeof databaseSchema>;
|
||||||
|
const rawDatabaseSchema = z.object({
|
||||||
|
connectionString: z.string(),
|
||||||
|
secure: z.boolean().default(true),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const databaseConfig = registerAs('database', () => {
|
||||||
|
const env = coerceRecordTypes(process.env);
|
||||||
|
const envParsed = rawDatabaseSchema.strict().parse({
|
||||||
|
connectionString: env['DATABASE_CONNECTION_STRING'],
|
||||||
|
secure: env['DATABASE_SECURE'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectionString = new ConnectionString(envParsed.connectionString);
|
||||||
|
const config: DatabaseConfig = databaseSchema.strict().parse({
|
||||||
|
connectionString: connectionString.toString(),
|
||||||
|
type: connectionString.protocol,
|
||||||
|
host: first(connectionString.hosts)?.name,
|
||||||
|
port: first(connectionString.hosts)?.port,
|
||||||
|
username: connectionString.user,
|
||||||
|
password: connectionString.password,
|
||||||
|
database: first(connectionString.path),
|
||||||
|
secure: envParsed.secure,
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
});
|
@ -3,13 +3,14 @@ import { Module } from '@nestjs/common';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { localConfig } from '../../config/local.config';
|
import { localConfig } from '../../config/local.config';
|
||||||
import { loggerConfig } from '../../config/logger.config';
|
import { loggerConfig } from '../../config/logger.config';
|
||||||
|
import { databaseConfig } from '../../config/database.config';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
expandVariables: true,
|
expandVariables: true,
|
||||||
load: [localConfig, loggerConfig],
|
load: [localConfig, loggerConfig, databaseConfig],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export const APP_DATASOURCES = Symbol('APP_DATASOURCES');
|
40
apps/ebitemp-api/src/app/modules/database/database.module.ts
Normal file
40
apps/ebitemp-api/src/app/modules/database/database.module.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
import { APP_DATASOURCES } from './database.constants';
|
||||||
|
import { DatabaseConfig, databaseConfig } from '../../config/database.config';
|
||||||
|
import { typeormTransactionalDataSourceFactory } from './typeorm-data-source-factory';
|
||||||
|
import { typeormModuleOptionsFactory } from './typeorm-module-options-factory';
|
||||||
|
import { typeormEntitiesFromImport } from './typeorm-import-entities';
|
||||||
|
|
||||||
|
const dataSources: DataSource[] = [];
|
||||||
|
|
||||||
|
const typeormModules = [
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
|
name: 'ebitemp-api',
|
||||||
|
dataSourceFactory: typeormTransactionalDataSourceFactory('ebitemp-api', dataSources),
|
||||||
|
useFactory: async (dbConfig: DatabaseConfig) => {
|
||||||
|
// const entities = await import('./path/to/entities');
|
||||||
|
const entities = {};
|
||||||
|
|
||||||
|
const config = await typeormModuleOptionsFactory('ebitemp-api', dbConfig, [
|
||||||
|
typeormEntitiesFromImport(entities),
|
||||||
|
]);
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
inject: [databaseConfig.KEY],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const dataSourcesProvider = {
|
||||||
|
provide: APP_DATASOURCES,
|
||||||
|
useValue: dataSources,
|
||||||
|
};
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
imports: [...typeormModules],
|
||||||
|
providers: [dataSourcesProvider],
|
||||||
|
exports: [...typeormModules, dataSourcesProvider],
|
||||||
|
})
|
||||||
|
export class AppDatabaseModule {}
|
@ -0,0 +1,15 @@
|
|||||||
|
import { DataSource, DataSourceOptions } from 'typeorm';
|
||||||
|
|
||||||
|
export const typeormDataSourceFactory = (dataSources: DataSource[]) => async (options?: DataSourceOptions) => {
|
||||||
|
const dataSource = await new DataSource(options!).initialize();
|
||||||
|
dataSources.push(dataSource);
|
||||||
|
return dataSource;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const typeormTransactionalDataSourceFactory =
|
||||||
|
(name: string, dataSources: DataSource[]) => async (options?: DataSourceOptions) => {
|
||||||
|
const tt = await import('typeorm-transactional');
|
||||||
|
const dataSource = tt.addTransactionalDataSource({ name: name, dataSource: new DataSource(options!) });
|
||||||
|
dataSources.push(dataSource);
|
||||||
|
return dataSource;
|
||||||
|
};
|
@ -0,0 +1,5 @@
|
|||||||
|
export const typeormEntitiesFromImport = async <T>(entities: T) => {
|
||||||
|
return (Object.keys(entities) as Array<keyof typeof entities>).map(
|
||||||
|
(entity: keyof typeof entities) => entities[entity]
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||||
|
import { DatabaseConfig } from '../../config/database.config';
|
||||||
|
|
||||||
|
export const typeormModuleOptionsFactory = async (
|
||||||
|
name: string,
|
||||||
|
databaseConfig: DatabaseConfig,
|
||||||
|
entities: any[]
|
||||||
|
): Promise<TypeOrmModuleOptions> => {
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
type: databaseConfig.type as any,
|
||||||
|
host: databaseConfig.host,
|
||||||
|
port: databaseConfig.port,
|
||||||
|
username: databaseConfig.username,
|
||||||
|
password: databaseConfig.password,
|
||||||
|
database: databaseConfig.database,
|
||||||
|
entities: [...entities],
|
||||||
|
synchronize: false,
|
||||||
|
logging: process.env['NODE_ENV'] !== 'production',
|
||||||
|
options: {
|
||||||
|
...(!databaseConfig.secure ? { trustServerCertificate: true } : {}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
export async function patchTypeOrm() {
|
||||||
|
(await import('typeorm-transactional')).initializeTransactionalContext();
|
||||||
|
(await import('typeorm-scoped')).patchSelectQueryBuilder();
|
||||||
|
};
|
@ -3,14 +3,17 @@
|
|||||||
* This is only a minimal backend to get started.
|
* This is only a minimal backend to get started.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { Logger } from '@nestjs/common';
|
import { Logger } from '@nestjs/common';
|
||||||
import { Logger as PinoLogger } from 'nestjs-pino';
|
import { Logger as PinoLogger } from 'nestjs-pino';
|
||||||
|
|
||||||
import { NestFactory } from '@nestjs/core';
|
|
||||||
import { AppModule } from './app/app.module';
|
import { AppModule } from './app/app.module';
|
||||||
import { LocalConfig, localConfig } from './app/config/local.config';
|
import { LocalConfig, localConfig } from './app/config/local.config';
|
||||||
|
import { patchTypeOrm } from './app/modules/database/typeorm-patch';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
|
await patchTypeOrm();
|
||||||
|
|
||||||
const appOpts = (() => {
|
const appOpts = (() => {
|
||||||
const loggerOpts = { bufferLogs: true };
|
const loggerOpts = { bufferLogs: true };
|
||||||
return {
|
return {
|
||||||
|
@ -10,13 +10,16 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"10": "^0.0.1",
|
||||||
"@autotelic/pino-seq-transport": "^0.1.0",
|
"@autotelic/pino-seq-transport": "^0.1.0",
|
||||||
"@nestjs/common": "^10.0.2",
|
"@nestjs/common": "^10.0.2",
|
||||||
"@nestjs/config": "^4.0.0",
|
"@nestjs/config": "^4.0.0",
|
||||||
"@nestjs/core": "^10.0.2",
|
"@nestjs/core": "^10.0.2",
|
||||||
"@nestjs/platform-express": "^10.0.2",
|
"@nestjs/platform-express": "^10.0.2",
|
||||||
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@nx/devkit": "20.4.1",
|
"@nx/devkit": "20.4.1",
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
|
"connection-string": "^4.4.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nestjs-pino": "^4.3.0",
|
"nestjs-pino": "^4.3.0",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
@ -24,6 +27,9 @@
|
|||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.0",
|
"rxjs": "^7.8.0",
|
||||||
|
"typeorm": "^0.3.20",
|
||||||
|
"typeorm-scoped": "^1.2.0",
|
||||||
|
"typeorm-transactional": "^0.5.0",
|
||||||
"zod": "^3.24.1"
|
"zod": "^3.24.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
307
pnpm-lock.yaml
generated
307
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user