nest js and prisma integration

 Hello Everyone,

    We will nest js with prisma integration in this tutorial blog. we will cover this following topics.

  1. setting nestjs application 
  2. configuring prisma and database connection.
  3. creating schema/data model
  4. creating CRUD operations
Folder Structure
template
  ├── node_modules
  ├── prisma
  │   ├── schema.prisma
  ├── src
  │   ├── common
  │   │   ├── bcrypt.module.ts
  │   │   ├── bcrypt.service.ts
  │   ├── prisma
  │   │   ├── prisma.module.ts
  │   │   ├── prisma.service.ts
  │   ├── user
  │   │   ├── dto
  │   │   │   ├── user.dto.ts
  │   │   ├── user.controller.ts
  │   │   ├── user.module.ts
  │   │   ├── user.service.ts
  │   ├── app.controller.spec.ts
  │   ├── app.controller.ts
  │   ├── app.module.ts
  │   ├── app.service.ts
  │   └── main.ts
  ├── test
  │   ├── app.e2e-spec.ts
  │   └── jest-e2e.json
  ├── README.md
  ├── nest-cli.json
  ├── package-lock.json
  ├── package.json
  ├── tsconfig.build.json
  └── tsconfig.json
1. Setting nestJs application :     
$ npm i -g @nestjs/cli
$ nest new project-name
This command will create nest Js application. using npm run start:dev  you can start your development server. 

2. Configuring Prisma and database connection.
To establish a connection between Prisma and our PostgreSQL database, we need to configure the database URL and set up the Prisma client. Here's how you can do it:

Step 1: Open your terminal or command prompt.

Step 2: Navigate to your project directory and Install prisma .
$ npm install prisma --save-dev
Step 3: npx prisma is a command-line tool used for database management, migrations, and ORM operations in Node.js applications. It helps developers interact with databases easily and efficiently.
$ npx prisma
Step 4: Now create your initial Prisma setup using the init command of the Prisma CLI
$ npx prisma init
Step 5: Open the .env file (create one if it doesn't exist) and add the following line:
DATABASE_URL="postgresql://postgres:<password>@localhost:5432/<databaseName>?schema=public"
Step 6: Now let's configure the Prisma client. Create prisma folder and inside it create file called prisma.service.ts and  prisma.module.ts in your project's root directory and add the following code.
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}
    This code defines a custom PrismaService that extends the PrismaClient and establishes a connection to the database when the module is initialized. 
    This PrismaService can be used as a centralized service for interacting with the database using the Prisma client in a Nest.js application.

  3. Creating Schema/Data Model
 
    Now that we have our application and database connection set up, let's define our schema and data models. We'll use Prisma's schema file for this purpose.
 
Step 1: Open the schema.prisma file in your project's root directory (create one if it doesn't exist) and create schema like this...
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}


model User {
  userId    Int       @default(autoincrement()) @id
  email     String    @unique
  password  String
  role      Role
  
}

model Orders {
  orderId        Int      @default(autoincrement()) @id
  orderNumber     String
}

enum Role {
  PICKER
  PACKER
  SUPERVISOR
}
In this example, we have defined two models: User and Order.

4. Creating CRUD operation.
user.controller.ts

@Controller('user')
export class UserController {
  constructor(
    private readonly userService: UserService,
    ) {}

  @Get('getAllUser')
  async getAllTodos() {
    return this.userService.getAllUser();
  }

  @Get('getUserById/:id')
  async getUserById(@Param('id', ParseIntPipe) userId : number) {
    return this.userService.getUserById(userId);
  }

  @Post('create')
  async createUser( @Body() userData : CreateUserDto){
    return this.userService.createUser(userData);
  }

  @Put('update/:userId')
  async updateUser(@Body() userBody : CreateUserDto, @Param('userId', ParseIntPipe) userId : number){
    return this.userService.updateUser(userBody, userId);
  }

  @Delete('delete/:userId')
  async deleteUser(@Param('userId', ParseIntPipe) userId : number){
    return this.userService.deleteUser(userId);
  }
}
user.service.ts
import { HttpException, HttpStatus, Injectable, NotFoundException } from '@nestjs/common';
import { BcryptService } from 'src/common/bcrypt_module/bcrypt.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateUserDto } from 'src/user/dto/user.dto'

@Injectable()
export class UserService {

    constructor(
        private prismaService: PrismaService,
        private bcryptService: BcryptService
    ) { }

    async getAllUser() {
        return this.prismaService.user.findMany();
    }

    async createUser(userData: CreateUserDto) {
        const hashPassword = await this.bcryptService.plainToHash(userData.password)
        try {
            const { email, password, role } = userData;
            if (!email || !password || !role) {
                throw new NotFoundException('ENTER FULL DETAILS');
            }
            else {
                if (userData.role.toUpperCase() === 'SUPERVISOR') {
                    const user = await this.prismaService.user.create({
                        data: {
                            email: userData.email,
                            password: hashPassword,
                            role: 'SUPERVISOR'
                        }
                    })
                    return user
                } else if (userData.role.toUpperCase() === 'PICKER') {
                    const user = await this.prismaService.user.create({
                        data: {
                            email: userData.email,
                            password: hashPassword,
                            role: 'PICKER'
                        }
                    })
                    return user
                } else if (userData.role.toUpperCase() === 'PACKER') {
                    const user = await this.prismaService.user.create({
                        data: {
                            email: userData.email,
                            password: hashPassword,
                            role: 'PACKER'
                        }
                    })
                    return user
                }
            }
        } catch (e) {
            console.log(e)
            throw new HttpException({ msg: 'FAILED' }, HttpStatus.FORBIDDEN);
        }
    }

    async getUserById(userId: number) {
        try {
            const user = this.prismaService.user.findUnique({
                where: {
                    userId: 1
                }
            })
            return user;
        } catch (e) {
            console.log(e)
            throw new HttpException({ msg: 'FAILED!' }, HttpStatus.FORBIDDEN);
        }
    }

    async updateUser(userBody: any, userId: number) {
        try {
            const user = this.prismaService.user.update({
              where: {
                userId: userId
              },
              data: {
                ...userBody
              },
            })
            return user;
        } catch (e) {
            console.log(e)
            throw new HttpException({ msg: 'FAILED!' }, HttpStatus.FORBIDDEN);
        }
    }

    async deleteUser(userId: number) {
        try {
            const user = this.prismaService.user.delete({
                where: {
                    userId: userId
                },
            })
            return user;
        } catch (e) {
            console.log(e)
            throw new HttpException({ msg: 'FAILED!' }, HttpStatus.FORBIDDEN);
        }
    }
Thanks for