Lesson 13-NestJS Database Integration

NestJS with MySQL Integration and Usage

Integrating NestJS with a MySQL database is typically achieved using TypeORM or directly with the MySQL driver. This section demonstrates how to use TypeORM to connect to a MySQL database and perform basic CRUD operations.

Installing Dependencies

Install the required dependencies for TypeORM and MySQL support:

npm install --save @nestjs/typeorm typeorm mysql2 reflect-metadata

Configuring Database Connection

Configure TypeORM to connect to the MySQL database, typically in a file like ormconfig.json:

// ormconfig.json
{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "yourpassword",
  "database": "testdb",
  "synchronize": true, // Note: Do not use this in production
  "logging": false,
  "entities": [
    "src/**/*.entity{.ts,.js}"
  ],
  "migrations": [
    "src/migration/*{.ts,.js}"
  ],
  "subscribers": [
    "src/subscriber/*{.ts,.js}"
  ],
  "cli": {
    "entitiesDir": "src",
    "migrationsDir": "src/migration",
    "subscribersDir": "src/subscriber"
  }
}

Creating an Entity

Entities in TypeORM map to database tables. Create a simple User entity:

// src/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  password: string;
}

Creating a Service

Create a service to handle database interactions:

// src/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  async findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  async findOne(id: number): Promise<User | undefined> {
    return this.usersRepository.findOneBy({ id });
  }

  async create(user: User): Promise<User> {
    return this.usersRepository.save(user);
  }

  async update(id: number, user: User): Promise<void> {
    await this.usersRepository.update(id, user);
  }

  async delete(id: number): Promise<void> {
    await this.usersRepository.delete(id);
  }
}

Creating a Controller

Create a controller to handle HTTP requests:

// src/users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './user.entity';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User | undefined> {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() user: User): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: User): Promise<void> {
    return this.usersService.update(+id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<void> {
    return this.usersService.delete(+id);
  }
}

Registering the Module

Register the module and import the TypeORM module to establish the database connection:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './users/user.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'yourpassword',
      database: 'testdb',
      entities: [User],
      synchronize: true, // Note: Do not use this in production
      logging: false,
    }),
    UsersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Running the Application

Start the NestJS application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

NestJS with PostgreSQL Integration and Usage

Integrating PostgreSQL with NestJS is typically done using TypeORM or Prisma. This section focuses on using TypeORM.

Installing Dependencies

Install TypeORM and PostgreSQL dependencies:

npm install --save @nestjs/typeorm typeorm pg reflect-metadata

Configuring Database Connection

Configure TypeORM to connect to PostgreSQL in ormconfig.json:

// ormconfig.json
{
  "type": "postgres",
  "host": "localhost",
  "port": 5432,
  "username": "your_username",
  "password": "your_password",
  "database": "your_database",
  "synchronize": true, // Note: Do not use this in production
  "logging": false,
  "entities": [
    "src/**/*.entity{.ts,.js}"
  ],
  "migrations": [
    "src/migration/*{.ts,.js}"
  ],
  "subscribers": [
    "src/subscriber/*{.ts,.js}"
  ],
  "cli": {
    "entitiesDir": "src",
    "migrationsDir": "src/migration",
    "subscribersDir": "src/subscriber"
  }
}

Creating an Entity

Create a User entity:

// src/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  password: string;
}

Creating a Service

Create a service for database interactions:

// src/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  async findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  async findOne(id: number): Promise<User | undefined> {
    return this.usersRepository.findOneBy({ id });
  }

  async create(user: User): Promise<User> {
    return this.usersRepository.save(user);
  }

  async update(id: number, user: User): Promise<void> {
    await this.usersRepository.update(id, user);
  }

  async delete(id: number): Promise<void> {
    await this.usersRepository.delete(id);
  }
}

Creating a Controller

Create a controller for HTTP requests:

// src/users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './user.entity';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User | undefined> {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() user: User): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: User): Promise<void> {
    return this.usersService.update(+id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<void> {
    return this.usersService.delete(+id);
  }
}

Registering the Module

Register the module and import TypeORM:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './users/user.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'your_username',
      password: 'your_password',
      database: 'your_database',
      entities: [User],
      synchronize: true, // Note: Do not use this in production
      logging: false,
    }),
    UsersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

NestJS with MongoDB Integration and Usage

Integrating MongoDB with NestJS is typically done using Mongoose, a MongoDB object modeling tool that provides a straightforward API.

Installing Dependencies

Install Mongoose and its NestJS support:

npm install --save @nestjs/mongoose mongoose

Configuring Database Connection

Configure Mongoose to connect to MongoDB in database.config.ts:

// database.config.ts
import { Connection, connect } from 'mongoose';

export const databaseConfig = {
  uri: 'mongodb://localhost:27017/testdb',
};

export async function connectToDatabase(config: typeof databaseConfig): Promise<Connection> {
  const connection = await connect(config.uri, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  });

  console.log('Connected to MongoDB');

  return connection;
}

Creating a Module

Create a module to manage the database connection:

// database.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { connectToDatabase, databaseConfig } from './database.config';

@Module({
  imports: [
    MongooseModule.forRootAsync({
      useFactory: () => databaseConfig,
    }),
  ],
})
export class DatabaseModule {}

Creating Schema and Model

Define a Schema and Model for the data structure:

// user.schema.ts
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Creating a Service

Create a service for database interactions:

// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './user.schema';

@Injectable()
export class UsersService {
  constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}

  async findAll(): Promise<User[]> {
    return this.userModel.find().exec();
  }

  async findOne(id: string): Promise<User | null> {
    return this.userModel.findById(id).exec();
  }

  async create(user: User): Promise<User> {
    const createdUser = new this.userModel(user);
    return createdUser.save();
  }

  async update(id: string, user: User): Promise<User | null> {
    return this.userModel.findByIdAndUpdate(id, user, { new: true }).exec();
  }

  async delete(id: string): Promise<User | null> {
    return this.userModel.findByIdAndDelete(id).exec();
  }
}

Creating a Controller

Create a controller for HTTP requests:

// users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './user.schema';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User | null> {
    return this.usersService.findOne(id);
  }

  @Post()
  create(@Body() user: User): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: User): Promise<User | null> {
    return this.usersService.update(id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<User | null> {
    return this.usersService.delete(id);
  }
}

Registering the Module

Register the module and import Mongoose:

// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [DatabaseModule, UsersModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

NestJS with Redis Integration and Usage

Integrating Redis with NestJS can be done using the @nestjs/redis module or third-party libraries like ioredis. This section uses @nestjs/redis.

Installing Dependencies

Install the required dependencies:

npm install --save @nestjs/redis ioredis

Configuring Redis

Configure Redis connection options in redis.config.ts:

// redis.config.ts
import { RedisOptions } from '@nestjs/redis';

export const redisConfig: RedisOptions = {
  url: 'redis://localhost:6379',
};

Creating a Redis Module

Create a module to manage Redis connections:

// redis.module.ts
import { Module } from '@nestjs/common';
import { RedisModule } from '@nestjs/redis';
import { redisConfig } from './redis.config';

@Module({
  imports: [RedisModule.register(redisConfig)],
  exports: [RedisModule],
})
export class RedisModule {}

Creating a Redis Service

Create a service to encapsulate common Redis operations:

// redis.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { ClientRedis } from '@nestjs/redis';

@Injectable()
export class RedisService {
  constructor(private readonly client: ClientRedis, private readonly logger: Logger) {}

  async set(key: string, value: string, ttl?: number): Promise<void> {
    await this.client.set(key, value, 'EX', ttl || 60);
    this.logger.log(`Set key ${key} with value ${value}`);
  }

  async get(key: string): Promise<string | null> {
    const value = await this.client.get(key);
    this.logger.log(`Got key ${key} with value ${value}`);
    return value;
  }

  async del(key: string): Promise<number> {
    const result = await this.client.del(key);
    this.logger.log(`Deleted key ${key}`);
    return result;
  }
}

Registering the Redis Module

Register the Redis module in the main module:

// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RedisModule } from './redis/redis.module';

@Module({
  imports: [RedisModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Using the Redis Service

Inject and use the RedisService in a controller:

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { RedisService } from './redis/redis.service';

@Controller()
export class AppController {
  constructor(private readonly redisService: RedisService) {}

  @Get('/set')
  async setRedisKey(): Promise<void> {
    await this.redisService.set('test', 'Hello, Redis!');
  }

  @Get('/get')
  async getRedisKey(): Promise<string | null> {
    return await this.redisService.get('test');
  }

  @Get('/del')
  async delRedisKey(): Promise<number> {
    return await this.redisService.del('test');
  }
}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/set to set a Redis key-value pair, http://localhost:3000/get to retrieve it, and http://localhost:3000/del to delete it.

NestJS with TypeORM Integration and Usage

Integrating TypeORM with NestJS enables interaction with various relational databases. This section provides a comprehensive guide.

Installing Dependencies

Install TypeORM and the MySQL driver:

npm install --save @nestjs/typeorm typeorm mysql2

Configuring Database Connection

Configure TypeORM in ormconfig.json:

// ormconfig.json
{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "your_password",
  "database": "your_database",
  "synchronize": true, // Note: Do not use this in production
  "logging": false,
  "entities": [
    "src/**/*.entity{.ts,.js}"
  ],
  "migrations": [
    "src/migration/*{.ts,.js}"
  ],
  "subscribers": [
    "src/subscriber/*{.ts,.js}"
  ],
  "cli": {
    "entitiesDir": "src",
    "migrationsDir": "src/migration",
    "subscribersDir": "src/subscriber"
  }
}

Creating an Entity

Create a User entity:

// src/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  password: string;
}

Creating a Service

Create a service for database interactions:

// src/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  async findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  async findOne(id: number): Promise<User | undefined> {
    return this.usersRepository.findOneBy({ id });
  }

  async create(user: User): Promise<User> {
    return this.usersRepository.save(user);
  }

  async update(id: number, user: User): Promise<void> {
    await this.usersRepository.update(id, user);
  }

  async delete(id: number): Promise<void> {
    await this.usersRepository.delete(id);
  }
}

Creating a Controller

Create a controller for HTTP requests:

// src/users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './user.entity';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User | undefined> {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() user: User): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: User): Promise<void> {
    return this.usersService.update(+id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<void> {
    return this.usersService.delete(+id);
  }
}

Registering the Module

Register the module and import TypeORM:

// src/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'your_password',
      database: 'your_database',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true, // Note: Do not use this in production
      logging: false,
    }),
    UsersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

TypeORM Transactions

TypeORM supports transactions using the @Transactional decorator or the EntityManager transaction method:

// src/users/users.service.ts
import { Injectable, InjectRepository } from '@nestjs/common';
import { Repository, EntityManager, Connection, Transactional } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    private connection: Connection,
  ) {}

  @Transactional()
  async createUserAndProfile(user: User): Promise<User> {
    const entityManager: EntityManager = this.connection.manager;
    try {
      const newUser = await entityManager.save(user);
      // Assume Profile is another entity
      const profile = new Profile();
      profile.user = newUser;
      await entityManager.save(profile);
      return newUser;
    } catch (error) {
      throw error;
    }
  }

  async createUserAndProfileWithTransaction(user: User): Promise<User> {
    return this.connection.transaction(async (entityManager) => {
      const newUser = await entityManager.save(user);
      // Assume Profile is another entity
      const profile = new Profile();
      profile.user = newUser;
      await entityManager.save(profile);
      return newUser;
    });
  }
}

Unit Testing

Write unit tests to ensure services and controllers work as expected:

Install testing dependencies:

npm install --save-dev jest @types/jest ts-jest

Configure Jest in jest.config.js:

// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
  },
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
};

Create a test file users.service.spec.ts:

// src/users/users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { User } from './user.entity';
import { Repository } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';

describe('UsersService', () => {
  let service: UsersService;
  let repository: Repository<User>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        {
          provide: getRepositoryToken(User),
          useValue: {
            find: jest.fn(),
            findOneBy: jest.fn(),
            save: jest.fn(),
            update: jest.fn(),
            delete: jest.fn(),
          },
        },
      ],
    }).compile();

    service = module.get<UsersService>(UsersService);
    repository = module.get<Repository<User>>(getRepositoryToken(User));
  });

  describe('findAll', () => {
    it('should return an array of users', async () => {
      const users = [{ id: 1, username: 'test', password: 'test' }];
      jest.spyOn(repository, 'find').mockResolvedValue(users);

      expect(await service.findAll()).toBe(users);
    });
  });

  // Additional test cases...
});

Integration Testing

For complex tests, use integration testing to simulate the entire system:

Create an integration test file users.integration.spec.ts:

// src/users/users.integration.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../app.module';
import { User } from './user.entity';

describe('Users (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  afterAll(async () => {
    await app.close();
  });

  describe('GET /users', () => {
    it('should return all users', () => {
      return request(app.getHttpServer())
        .get('/users')
        .expect(200)
        .then((response) => {
          expect(response.body).toEqual(expect.arrayContaining([
            expect.objectContaining({
              id: expect.any(Number),
              username: expect.any(String),
              password: expect.any(String),
            })
          ]));
        });
    });
  });

  // Additional test cases...
});

Deployment

Deploy NestJS applications using Docker, Heroku, AWS, etc. Here’s an example with Docker:

Create Dockerfile:

# Dockerfile
FROM node:14-alpine

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "start"]

Build Docker Image:

docker build -t your-image-name .

Run Docker Container:

docker run -p 3000:3000 your-image-name

NestJS with Sequelize Integration and Usage

Integrating Sequelize with NestJS enables interaction with relational databases. This section provides a comprehensive guide.

Installing Dependencies

Install Sequelize and the MySQL driver:

npm install --save @nestjs/sequelize sequelize sequelize-cli mysql2

Install Sequelize CLI for development:

npx sequelize-cli init

This creates a basic folder structure and configuration files.

Configuring Database Connection

Configure Sequelize in config/config.json:

// config/config.json
{
  "development": {
    "username": "root",
    "password": "your_password",
    "database": "your_database",
    "host": "localhost",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": "your_password",
    "database": "your_database",
    "host": "localhost",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": "your_password",
    "database": "your_database",
    "host": "localhost",
    "dialect": "mysql"
  }
}

Creating a Model

Models in Sequelize map to database tables. Create a User model:

// src/models/user.model.ts
import { Table, Column, Model, DataType, AllowNull, PrimaryKey, AutoIncrement } from 'sequelize-typescript';

@Table
export class User extends Model<User> {
  @AllowNull(false)
  @PrimaryKey
  @AutoIncrement
  @Column(DataType.INTEGER)
  id: number;

  @AllowNull(false)
  @Column(DataType.STRING)
  username: string;

  @AllowNull(false)
  @Column(DataType.STRING)
  password: string;
}

Creating a Service

Create a service for database interactions:

// src/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { User } from '../models/user.model';

@Injectable()
export class UsersService {
  constructor(
    @InjectModel(User)
    private userModel: typeof User,
  ) {}

  async findAll(): Promise<User[]> {
    return this.userModel.findAll();
  }

  async findOne(id: number): Promise<User | null> {
    return this.userModel.findByPk(id);
  }

  async create(user: User): Promise<User> {
    return this.userModel.create(user);
  }

  async update(id: number, user: User): Promise<[number]> {
    return this.userModel.update(user, { where: { id } });
  }

  async delete(id: number): Promise<number> {
    return this.userModel.destroy({ where: { id } });
  }
}

Creating a Controller

Create a controller for HTTP requests:

// src/users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from '../models/user.model';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User | null> {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() user: User): Promise<User> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: User): Promise<[number]> {
    return this.usersService.update(+id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<number> {
    return this.usersService.delete(+id);
  }
}

Registering the Module

Register the module and import Sequelize:

// src/users.module.ts
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { User } from '../models/user.model';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [SequelizeModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { SequelizeModule } from '@nestjs/sequelize';

@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'your_password',
      database: 'your_database',
      models: [__dirname + '/**/*.model{.ts,.js}'],
      autoLoadModels: true,
      synchronize: true, // Note: Do not use this in production
      logging: false,
    }),
    UsersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

Sequelize Transactions

Sequelize supports transactions using the sequelize.transaction() method:

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { User } from './user.model';
import { Model, Sequelize } from 'sequelize';

@Injectable()
export class UsersService {
  constructor(
    @InjectModel(User)
    private userModel: typeof User,
    private sequelize: Sequelize,
  ) {}

  async createUserAndProfile(user: User): Promise<User> {
    return this.sequelize.transaction(async (t) => {
      try {
        const newUser = await this.userModel.create(user, { transaction: t });
        // Assume Profile is another model
        const profile = new Profile();
        profile.userId = newUser.id;
        await profile.save({ transaction: t });
        return newUser;
      } catch (error) {
        throw error;
      }
    });
  }
}

NestJS with Prisma Integration and Usage

Integrating Prisma with NestJS simplifies interaction with relational databases. This section provides a comprehensive guide.

Installing Dependencies

Install Prisma and the PostgreSQL driver:

npm install --save prisma @prisma/client

Install Prisma CLI for development:

npx prisma@latest --version
npx prisma generate

Optionally, install Prisma CLI globally:

npm install -g prisma

Configuring Prisma

Configure Prisma to connect to PostgreSQL in prisma/schema.prisma:

// prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

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

model User {
  id        Int      @id @default(autoincrement())
  username  String   @unique
  password  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Generating Prisma Client

Generate the Prisma client:

npx prisma generate

This creates the Prisma client in node_modules/@prisma/client.

Creating a Service

Create a service for database interactions:

// src/users/users.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class UsersService implements OnModuleInit, OnModuleDestroy {
  constructor(private prisma: PrismaClient) {}

  onModuleInit() {
    this.prisma.$connect();
  }

  onModuleDestroy() {
    this.prisma.$disconnect();
  }

  async findAll(): Promise<any[]> {
    return this.prisma.user.findMany();
  }

  async findOne(id: number): Promise<any | null> {
    return this.prisma.user.findUnique({ where: { id } });
  }

  async create(data: any): Promise<any> {
    return this.prisma.user.create({ data });
  }

  async update(id: number, data: any): Promise<any> {
    return this.prisma.user.update({ where: { id }, data });
  }

  async delete(id: number): Promise<any> {
    return this.prisma.user.delete({ where: { id } });
  }
}

Creating a Controller

Create a controller for HTTP requests:

// src/users/users.controller.ts
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<any[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<any | null> {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() user: any): Promise<any> {
    return this.usersService.create(user);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() user: any): Promise<any> {
    return this.usersService.update(+id, user);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<any> {
    return this.usersService.delete(+id);
  }
}

Registering the Module

Register the module and set up Prisma:

// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [],
  controllers: [UsersController],
  providers: [UsersService, PrismaService],
  exports: [PrismaService],
})
export class UsersModule {}

// src/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();
  }

  onModuleInit() {
    this.$connect();
  }

  onModuleDestroy() {
    this.$disconnect();
  }
}

// src/app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { PrismaService } from './prisma.service';

@Module({
  imports: [UsersModule],
  controllers: [],
  providers: [PrismaService],
})
export class AppModule {}

Running the Application

Start the application:

npm run start:dev

Visit http://localhost:3000/users to view all user information.

Prisma Transactions

Prisma 2.x introduced transaction support:

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  async createUserAndProfile(user: any): Promise<any> {
    return this.prisma.$transaction(async (tx) => {
      try {
        const newUser = await tx.user.create({ data: user });
        // Assume Profile is another model
        const profile = await tx.profile.create({ data: { userId: newUser.id } });
        return newUser;
      } catch (error) {
        throw error;
      }
    });
  }
}
Share your love