src/database/database.service.ts
Properties |
|
Methods |
|
constructor(configService: ConfigService)
|
||||||
|
Defined in src/database/database.service.ts:57
|
||||||
|
Parameters :
|
| Async enableShutdownHooks | ||||||
enableShutdownHooks(app: INestApplication)
|
||||||
|
Defined in src/database/database.service.ts:151
|
||||||
|
Parameters :
Returns :
any
|
| Async onModuleInit |
onModuleInit()
|
|
Defined in src/database/database.service.ts:98
|
|
Returns :
any
|
| Public Async prepareTestQueries |
prepareTestQueries()
|
|
Defined in src/database/database.service.ts:118
|
|
Returns :
any
|
| Public Async removeTestData |
removeTestData()
|
|
Defined in src/database/database.service.ts:142
|
|
Returns :
any
|
| Private Static connected |
Default value : false
|
|
Defined in src/database/database.service.ts:56
|
| Private Static instances |
Type : number
|
Default value : 0
|
|
Defined in src/database/database.service.ts:54
|
| Private Readonly logger |
Default value : new Logger(DatabaseService.name)
|
|
Defined in src/database/database.service.ts:53
|
| Private Static mwareBound |
Default value : false
|
|
Defined in src/database/database.service.ts:55
|
| Public Readonly read |
Type : PrismaClient
|
|
Defined in src/database/database.service.ts:49
|
| Private Static replicated |
Default value : false
|
|
Defined in src/database/database.service.ts:57
|
| Private Static sRead |
Type : PrismaClient
|
|
Defined in src/database/database.service.ts:51
|
| Private Static sWrite |
Type : PrismaClient
|
|
Defined in src/database/database.service.ts:52
|
| Public Readonly write |
Type : PrismaClient
|
|
Defined in src/database/database.service.ts:50
|
import { Injectable, INestApplication, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';
import { Logger } from '@nestjs/common';
import * as Sentry from "@sentry/node";
import "@sentry/tracing";
import { MiddlewareParams } from 'prisma';
function createSentryMiddleware(type: 'read' | 'write') {
return async (
params: MiddlewareParams,
next: (params: MiddlewareParams) => Promise<any>,
) => {
const { model, action, runInTransaction, args } = params;
const description = [model, action].filter(Boolean).join('.');
const data = {
model,
action,
runInTransaction,
args,
};
const hub = Sentry.getCurrentHub();
const transaction = hub.startTransaction({
name: `database ${type} query`,
});
const span = transaction.startChild({
op: 'db',
description,
data,
});
hub.configureScope((scope) => scope.setSpan(span));
hub?.addBreadcrumb({
category: 'db',
message: description,
data,
});
const result = await next(params);
span?.finish();
transaction.finish();
return result;
};
}
@Injectable()
export class DatabaseService implements OnModuleInit {
public readonly read: PrismaClient;
public readonly write: PrismaClient;
private static sRead: PrismaClient; // dont create 23023 db clients
private static sWrite: PrismaClient; // --||--
private readonly logger = new Logger(DatabaseService.name);
private static instances = 0;
private static mwareBound = false;
private static connected = false;
private static replicated = false;
constructor(private configService: ConfigService) {
if (DatabaseService.sRead && DatabaseService.sWrite) {
this.read = DatabaseService.sRead;
this.write = DatabaseService.sWrite;
} else {
DatabaseService.instances++;
this.logger.debug(
`Creating new database driver (static read: ${!!DatabaseService.sRead}, static write: ${!!DatabaseService.sWrite})`,
);
DatabaseService.sWrite = new PrismaClient({
datasources: { db: { url: configService.get<string>('DATABASE_URL') } },
});
if (this.configService.get('READ_REPLICA') === '1') {
this.logger.log(`Connecting to replica`);
DatabaseService.replicated = true;
DatabaseService.sRead = new PrismaClient({
datasources: {
db: { url: configService.get<string>('READ_DATABASE_URL') },
},
});
} else {
DatabaseService.sRead = DatabaseService.sWrite;
}
if (!DatabaseService.mwareBound) {
DatabaseService.mwareBound = true;
if (DatabaseService.replicated) {
DatabaseService.sRead.$use(createSentryMiddleware('read'));
}
DatabaseService.sWrite.$use(createSentryMiddleware('write'));
}
this.read = DatabaseService.sRead;
this.write = DatabaseService.sWrite;
this.logger.debug(`Created db instances: ${DatabaseService.instances}`);
}
}
async onModuleInit() {
if (!DatabaseService.connected) {
DatabaseService.connected = true;
try {
await Promise.all([this.read.$connect(), this.write.$connect()]).catch(
(err) => {
throw err;
},
);
} catch (err) {
this.logger.error(`Prisma failed to connect to database`, err);
throw err;
}
} else {
this.logger.debug(
'Not connecting to the database again, connection was already estabilished',
);
}
}
public async prepareTestQueries() {
await this.removeTestData();
await this.write.users.create({
data: {
snowflake: (Math.random() + 1).toString(36).substring(7),
username: 'sex bear',
email_hash:
'54abacfd35a6a6e342d3e19e13908ddf83ae12899ee735ccf1ad862ca591c14b',
email:
'c37d8650f63631ca5513b67a6d42aa2b2d33b4b15b8a1ec98ff62155448cc07a',
password:
'$2b$10$mu031q8qKUZAofFOzov.IeHFnbv5fy2d8Tv9su1UW71975Sn8rB9W',
blocked: false,
admin: false,
twostep: false,
date: Date.now().toString(),
init_ip: '127.0.0.1',
sus: false,
mock: true,
},
});
this.logger.log('Added mock data to database');
}
public async removeTestData() {
await this.write.users.deleteMany({
where: {
mock: true,
},
});
this.logger.log('Removed mock data from database');
}
async enableShutdownHooks(app: INestApplication) {
this.write.$on('beforeExit', async () => {
await this.write.$disconnect();
await this.read.$disconnect();
await app.close();
});
}
}