DEV Community

loading...

How to use Prisma with NestJs

Harry Horton
Toptal software engineer: ♥️ all things Typescript, aspiring 🧙‍♂️, recovering cowboy coder, senior yak shaver, bugs are my own.
・2 min read

In this short article, I show my approach to setting up and using a PrismaModule in NestJs.

This article assumes that you already have Prisma already setup and ready to go within a NestJs project.

Prisma Module

Create a Prisma module and service. These will be used to access Prisma in the rest of your application.

// src/prisma/prisma.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { PrismaService } from './prisma.service';

@Module({
  // Assumes that env variables are retrieved 
  // from the config module.
  imports: [ConfigModule],
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}
Enter fullscreen mode Exit fullscreen mode
// src/prisma/prisma.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Prisma, PrismaClient } from '@prisma/client';
import { EnvironmentVariables } from '../config/types';

/**
 * Extension of the PrismaClient for use with NestJs.
 */
@Injectable()
export class PrismaService extends PrismaClient
  implements OnModuleInit, OnModuleDestroy {
  constructor(private configService: ConfigService<EnvironmentVariables>) {
    /**
     * Get the database url from environmental variables and pass it in.
     */
    super({
      datasources: {
        db: {
          url: configService.get('DATABASE_URL'),
        },
      },
    });
  }

  /**
   * Connect to the database when the module is initialized.
   */
  async onModuleInit(): Promise<void> {
    await this.$connect();
  }

  /**
   * Disconnect from the database when the application is shutting down.
   */
  async onModuleDestroy(): Promise<void> {
    await this.$disconnect();
  }

  /**
   * A utility function used to clear all database rows for testing.
   */
  clearDatabase() {
    const modelNames = Prisma.dmmf.datamodel.models.map(model => model.name);

    return Promise.all(
      modelNames.map(modelName =>
        this[modelName[0].toLowerCase() + modelName.slice(1)].deleteMany(),
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Using the Prisma Service

When the application starts up, the PrismaService will attempt to connect to the database automatically.

To create something like a TodoService, import the PrismaModule, and use the PrismaService to create the access layer.

// src/todo/todo.service.ts
//... imports

@Injectable()
export class TodoService {
  private logger = new Logger(TodoService.name);

  constructor(private prismaService: PrismaService) {}

  /**
   * The easiest way to get started is to simply expose
   * the desired methods on the model's service.
   */
  public create = this.prismaService.todo.create;
  public findFirst = this.prismaService.todo.findFirst;
  public findMany = this.prismaService.todo.findMany;
  public update = this.prismaService.todo.update;
  public delete = this.prismaService.todo.delete;
  public count = this.prismaService.todo.count;

  /**
   * You can get access to the types to reuse them in custom function's
   * arguments.
   */
  public specialCreate(data: Prisma.TodoCreateArgs['data']) {
    return this.prismaService.planner.create({
      data: {
        text: 'do something',
        ...data,
      },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

From there, you should be able to begin to build out your NestJs application using Prisma.

If you're interested in a more longform explanation with more examples, please let me know in the comments!

Discussion (0)