ngATL Conference Atlanta, GA

NestJS on 2018 ngATL Conference Atlanta, GA

NestJS 2018 ngATL

LEARN MORE

SQL (Sequelize)

This chapter applies only to TypeScript

Sequelize is the most popular Object Relational Mapper (ORM) available in the node.js world. It's written in plain JavaScript, but there's a sequelize-typescript TypeScript wrapper which provides a set of decorators and other extras for the base sequelize. To start the adventure with this library we have to install the following dependencies:

TypeScript

  $ npm install --save sequelize sequelize-typescript mysql2
  $ npm install --save-dev @types/sequelize

The first step we need to do is create a Sequelize instance with an options object passed into the constructor. Also, we need to add all of the models (the alternative is to use modelPaths property) and sync() our database tables.

database.providers.ts
TypeScript

import { Sequelize } from 'sequelize-typescript';
import { Cat } from '../cats/cat.entity';

export const databaseProviders = [
  {
    provide: 'SequelizeToken',
    useFactory: async () => {
      const sequelize = new Sequelize({
        dialect: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: 'password',
        database: 'nest',
      });
      sequelize.addModels([Cat]);
      await sequelize.sync();
      return sequelize;
    },
  },
];
Hint Following best practices, we've declared the custom component in the separated file which has a *.providers.ts suffix.

Then we need to export these providers to make them accessible for the rest part of the application.

database.module.ts
TypeScript

  import { Module } from '@nestjs/common';
  import { databaseProviders } from './database.providers';

  @Module({
    components: [...databaseProviders],
    exports: [...databaseProviders],
  })
  export class DatabaseModule {}

It's everything. Now we can inject the Sequelize object using @Inject() decorator. Each component which would depend on the Sequelize async component will wait until the Promise would be resolved.

Model injection

In Sequelize the Model represents a table in the database. Instances of this class represent a database row. Firstly, we need at least one entity:

cats/cat.entity.ts
TypeScript

import { Table, Column, Model } from 'sequelize-typescript';

@Table
export class Cat extends Model<Cat> {
  @Column
  name: string;

  @Column
  age: number;

  @Column
  breed: string;
}

The Cat entity belongs to the cats directory. This directory represents the CatsModule. It's your decision where you gonna keep your model files. From my point of view, the best way's to hold them nearly their domain, in the appropriate module directory.

Now it's time to create a Repository component:

cats.providers.ts
TypeScript

import { Cat } from './cat.entity';

export const catsProviders = [
  {
    provide: 'CatsRepository',
    useValue: Cat,
  },
];
Notice In the real-world applications you should avoid magic strings at all. Both CatsRepository and SequelizeToken should be kept in the separated constants.ts file.

In Sequelize we're using static methods to manipulate the data, so we're just creating an alias here.

Now we can inject the CatsRepository to the CatsService using the @Inject() decorator:

cats.service.ts
TypeScript

import { Component, Inject } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './cat.entity';

@Component()
export class CatsService {
  constructor(
    @Inject('CatsRepository') private readonly catsRepository: typeof Cat) {}

  async findAll(): Promise<Cat[]> {
    return await this.catsRepository.findAll<Cat>();
  }
}

The database connection's asynchronous, but Nest makes this process's completely invisible for the end-user. The CatsRepository component's waiting for the db connection, and the CatsService is delayed until repository would be ready to use. The entire application can start when each component is instantiated.

Here's a final CatsModule:

cats.module.ts
TypeScript

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { catsProviders } from './cats.providers';
import { DatabaseModule } from '../database/database.module';

@Module({
  imports: [DatabaseModule],
  controllers: [CatsController],
  components: [
    CatsService,
    ...catsProviders,
  ],
})
export class CatsModule {}
Hint Don't forget to import the CatsModule into the root ApplicationModule.

The full source code's available here.

Sponsors

Nest is an MIT-licensed open source project. It can grow thanks to the support by these awesome people. If you'd like to join them, please read more here. Thanks!

Become a sponsor