6

Currently on my first NestJS project. I am using Prisma 2, and would like to log the queries to the console in debug mode, to learn and inspect and avoid n+1 etc!

I have created the prisma.service.ts:

import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'
import { PrismaClient } from '@prisma/client'

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
    constructor() {
        super();
    }

    async onModuleInit() {
        await this.$connect()
    }

    async onModuleDestroy() {
        await this.$disconnect()
    }
}

Works fine, I can use it across the API and access the DB. However, according to the Prisma 2 Docs on Logging, I need to pass

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient({
  log: [
    { level: 'warn', emit: 'event' },
    { level: 'info', emit: 'event' },
    { level: 'error', emit: 'event' },
  ],

and then use it like this:

@Injectable()
export class TestService {
    constructor(private prismaService: PrismaService) {
        this.prismaService.$on('query', e => {
            console.log("Query: " + e.query)
            console.log("Duration: " + e.duration + "ms")
        })
    }

Sadly, when compiling, I get these errors:

TSError: тип Unable to compile TypeScript:
src/test.service.ts:9:31 - error TS2345: Argument of type '"query"' is not assignable to parameter of type '"beforeExit"'.

9        this.prismaService.$on('query', e => {
                                ~~~~~~~
src/test.service.ts:10:39 - error TS2339: Property 'query' does not exist on type '() => Promise<void>'.

10             console.log("Query: " + e.query)
                                         ~~~~~
src/test.service.ts:11:42 - error TS2339: Property 'duration' does not exist on type '() => Promise<void>'.

11             console.log("Duration: " + e.duration + "ms")

I tried passing the log array into the super() in the service, without any luck.

Am I just missing something small?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
turbzcoding
  • 173
  • 1
  • 6

4 Answers4

16

Hey bro I'd been using prima 2 + nestjs, I put the configuration prima in super of parent like this. It has worked wonders for me.

I hope it helps you ;)

This is my prismaService.ts

prisma.service.ts

import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
    
    @Injectable()
    export class PrismaService extends PrismaClient implements OnModuleInit {
      constructor() {
        super({
          log: [
            { emit: 'event', level: 'query' },
            { emit: 'stdout', level: 'info' },
            { emit: 'stdout', level: 'warn' },
            { emit: 'stdout', level: 'error' },
          ],
          errorFormat: 'colorless',
        });
      }
      async onModuleInit() {
        await this.$connect();
      }
    
      async enableShutdownHooks(app: INestApplication) {
        this.$on('beforeExit', async (event) => {
          console.log(event.name);
          await app.close();
        });
      }
    }
@Injectable()
export class TestService {
  constructor(private prismaService: PrismaService) {
    prismaService.$on<any>('query', (event: Prisma.QueryEvent) => {
      console.log('Query: ' + event.query);
      console.log('Duration: ' + event.duration + 'ms');
    });
  }
}

Ps: I had to delete the dist folder and run again.

Kelman ts
  • 161
  • 1
  • 6
5

I used this solution founded on the Prisma GitHub issues.

@Injectable()
export class TestService {
  constructor(
    private prismaService: PrismaClient<Prisma.PrismaClientOptions, 'query'>,
  ) {
    this.prismaService.$on('query', (e) => {
      console.log('Query: ' + e.query);
      console.log('Duration: ' + e.duration + 'ms');
    });
  }
}
madcam
  • 61
  • 1
  • 2
4

You can specify the events you want in the PrismaClient generic.

@Injectable()
export class PrismaService extends PrismaClient<Prisma.PrismaClientOptions, 'query' | 'error'> implements OnModuleInit {
  private readonly logger = new Logger(PrismaService.name);

  constructor() {
    super({
      log: [
        {
          emit: 'event',
          level: 'query',
        },
        {
          emit: 'event',
          level: 'error',
        },
        {
          emit: 'stdout',
          level: 'info',
        },
        {
          emit: 'stdout',
          level: 'warn',
        },
      ],
    });
  }

  async onModuleInit() {
    this.$on('error', (event) => {
      this.logger.verbose(event.target);
    });
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}
goodonion
  • 1,401
  • 13
  • 25
2

Looks like an issue with the Prisma Client types. I'd recommend that you open an issue on the Prisma Github repo. Until then you'll need to ignore the provided types by casting to any or unknown

Jesse Carter
  • 20,062
  • 7
  • 64
  • 101