-
-
Save ludndev/db324f490089e5bb1e3eac1e132c8b45 to your computer and use it in GitHub Desktop.
NestJS Prisma server with an extension to log all queries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Global, INestApplication, Injectable, Logger, Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; | |
| import { Prisma, PrismaClient } from '@prisma/client'; | |
| import { ITXClientDenyList } from '@prisma/client/runtime/library'; | |
| import { PRISMA_ORM_LOG_LEVEL, PRISMA_SQL_LOG_LEVEL } from '~/server_config'; | |
| export type PrismaTransaction = Omit<PrismaClient, ITXClientDenyList>; | |
| const logger = new Logger('prisma'); | |
| export const logQueriesExtension = Prisma.defineExtension((client) => { | |
| return client.$extends({ | |
| name: 'log_queries', | |
| query: PRISMA_ORM_LOG_LEVEL | |
| ? { | |
| $allModels: { | |
| async $allOperations({ operation, model, args, query }) { | |
| const start = performance.now(); | |
| const result = await query(args); | |
| const time = performance.now() - start; | |
| logger[PRISMA_ORM_LOG_LEVEL]( | |
| `${model}.${operation}(${JSON.stringify(args)}) => ${Array.isArray(result) ? result.length : !!result ? 1 : 0} result(s) in ${time.toFixed(2)}ms`.replaceAll( | |
| /\\?"|"/g, | |
| '', | |
| ), | |
| ); | |
| return result; | |
| }, | |
| }, | |
| } | |
| : undefined, | |
| }); | |
| }); | |
| function extendClient(base: PrismaClient) { | |
| // Add as many as you'd like - no ugly types required! | |
| return base.$extends(logQueriesExtension); //.$extends(findManyAndCountExtension); | |
| } | |
| class UntypedExtendedClient extends PrismaClient { | |
| constructor(options?: ConstructorParameters<typeof PrismaClient>[0]) { | |
| super(options); | |
| if (PRISMA_SQL_LOG_LEVEL) { | |
| // @ts-expect-error: https://www.prisma.io/docs/orm/prisma-client/client-extensions#usage-of-on-and-use-with-extended-clients | |
| this.$on('query', ({ query, params }: Prisma.QueryEvent) => { | |
| let workingQuery = query; | |
| const paramsArray = JSON.parse(params); | |
| for (let i = 0; i < paramsArray.length; ++i) { | |
| workingQuery = workingQuery.replace( | |
| `$${i + 1}`, | |
| `'${typeof paramsArray[i] === 'object' ? JSON.stringify(paramsArray[i]) : paramsArray[i]}'`, | |
| ); | |
| } | |
| logger[PRISMA_SQL_LOG_LEVEL](workingQuery); | |
| }); | |
| } | |
| return extendClient(this) as this; | |
| } | |
| } | |
| const ExtendedPrismaClient = UntypedExtendedClient as unknown as new ( | |
| options?: ConstructorParameters<typeof PrismaClient>[0], | |
| ) => PrismaClient & ReturnType<typeof extendClient>; | |
| @Injectable() | |
| export class PrismaService extends ExtendedPrismaClient implements OnModuleInit, OnModuleDestroy { | |
| constructor() { | |
| super( | |
| PRISMA_SQL_LOG_LEVEL | |
| ? { | |
| log: [ | |
| { | |
| emit: 'event', | |
| level: 'query', | |
| }, | |
| ], | |
| } | |
| : undefined, | |
| ); | |
| } | |
| async onModuleInit() { | |
| // Uncomment this to establish a connection on startup, this is generally not necessary | |
| // https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-management#connect | |
| // await this.$connect(); | |
| } | |
| async onModuleDestroy() { | |
| await this.$disconnect(); | |
| } | |
| async enableShutdownHooks(app: INestApplication) { | |
| async function waitForAppClose() { | |
| await app.close(); | |
| } | |
| // https://prisma.io/docs/guides/upgrade-guides/upgrading-versions/upgrading-to-prisma-5#removal-of-the-beforeexit-hook-from-the-library-engine | |
| process.on('exit', waitForAppClose); | |
| process.on('beforeExit', waitForAppClose); | |
| process.on('SIGINT', waitForAppClose); | |
| process.on('SIGTERM', waitForAppClose); | |
| process.on('SIGUSR2', waitForAppClose); | |
| } | |
| } | |
| @Global() | |
| @Module({ | |
| exports: [PrismaService], | |
| providers: [PrismaService], | |
| }) | |
| export class PrismaModule {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment