Skip to content

Commit e7335ab

Browse files
committed
feat(database): scaffold core persistence layer and ORM foundation
1 parent c14b2df commit e7335ab

4 files changed

Lines changed: 140 additions & 0 deletions

File tree

src/database/data-source.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import 'reflect-metadata';
2+
3+
import { DataSource } from 'typeorm';
4+
5+
import { getTypeOrmConfig } from './orm.config';
6+
7+
export const AppDataSource = new DataSource(
8+
getTypeOrmConfig(),
9+
);
10+
11+
export default AppDataSource;

src/database/database.module.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Global, Module } from '@nestjs/common';
2+
import { TypeOrmModule } from '@nestjs/typeorm';
3+
4+
import { DatabaseService } from './database.service';
5+
import { getTypeOrmConfig } from './orm.config';
6+
7+
@Global()
8+
@Module({
9+
imports: [
10+
TypeOrmModule.forRootAsync({
11+
useFactory: getTypeOrmConfig,
12+
}),
13+
],
14+
providers: [DatabaseService],
15+
exports: [DatabaseService, TypeOrmModule],
16+
})
17+
export class DatabaseModule {}

src/database/database.service.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
Injectable,
3+
Logger,
4+
OnApplicationBootstrap,
5+
OnApplicationShutdown,
6+
} from '@nestjs/common';
7+
import { DataSource } from 'typeorm';
8+
9+
@Injectable()
10+
export class DatabaseService
11+
implements OnApplicationBootstrap, OnApplicationShutdown
12+
{
13+
private readonly logger = new Logger(DatabaseService.name);
14+
15+
constructor(private readonly dataSource: DataSource) {}
16+
17+
async onApplicationBootstrap(): Promise<void> {
18+
if (!this.dataSource.isInitialized) {
19+
await this.dataSource.initialize();
20+
}
21+
22+
this.logger.log(
23+
`Database connection established (${this.dataSource.options.type})`,
24+
);
25+
}
26+
27+
async onApplicationShutdown(): Promise<void> {
28+
if (this.dataSource.isInitialized) {
29+
await this.dataSource.destroy();
30+
31+
this.logger.log('Database connection closed.');
32+
}
33+
}
34+
35+
async health() {
36+
return {
37+
connected: this.dataSource.isInitialized,
38+
database: this.dataSource.options.database,
39+
type: this.dataSource.options.type,
40+
};
41+
}
42+
43+
async execute<T>(
44+
callback: (dataSource: DataSource) => Promise<T>,
45+
): Promise<T> {
46+
return callback(this.dataSource);
47+
}
48+
49+
get connection(): DataSource {
50+
return this.dataSource;
51+
}
52+
}

src/database/orm.config.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
2+
3+
export function getTypeOrmConfig(): TypeOrmModuleOptions {
4+
return {
5+
type: 'postgres',
6+
7+
host: process.env.DB_HOST,
8+
9+
port: Number(process.env.DB_PORT ?? 5432),
10+
11+
username: process.env.DB_USERNAME,
12+
13+
password: process.env.DB_PASSWORD,
14+
15+
database: process.env.DB_DATABASE,
16+
17+
autoLoadEntities: true,
18+
19+
synchronize: false,
20+
21+
logging:
22+
process.env.NODE_ENV !== 'production',
23+
24+
ssl:
25+
process.env.DB_SSL === 'true'
26+
? {
27+
rejectUnauthorized: false,
28+
}
29+
: false,
30+
31+
migrations: [
32+
'dist/database/migrations/*.js',
33+
],
34+
35+
migrationsRun: false,
36+
37+
entities: ['dist/**/*.entity.js'],
38+
39+
extra: {
40+
max: Number(
41+
process.env.DB_POOL_SIZE ?? 20,
42+
),
43+
44+
min: Number(
45+
process.env.DB_POOL_MIN ?? 5,
46+
),
47+
48+
idleTimeoutMillis: Number(
49+
process.env.DB_IDLE_TIMEOUT ??
50+
30000,
51+
),
52+
53+
connectionTimeoutMillis:
54+
Number(
55+
process.env.DB_CONNECTION_TIMEOUT ??
56+
5000,
57+
),
58+
},
59+
};
60+
}

0 commit comments

Comments
 (0)