Created
October 23, 2024 21:17
-
-
Save gamedevsam/3930258b947679bc1bdb09d001105a67 to your computer and use it in GitHub Desktop.
NestJS Prisma server with an extension to log all queries
This file contains 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