ngATL Conference Atlanta, GA

NestJS on 2018 ngATL Conference Atlanta, GA

NestJS 2018 ngATL

LEARN MORE

SQL

To reduce a boilerplate necessary to start the adventure with the databases, Nest comes with the ready to use @nestjs/typeorm package. We have selected TypeORM because it is definitely the most mature Object Relational Mapper (ORM) available in the node.js world. Since it's written in TypeScript, it works pretty well with the Nest framework.

Firstly, we need to install all of the required dependencies:


$ npm install --save @nestjs/typeorm typeorm mysql
Notice In this chapter we'll use a MySQL database, but TypeORM provides a support for a lot of different ones such as PostgreSQL, SQLite, and even MongoDB (NoSQL).

Once the installation process is completed, we can import the TypeOrmModule into the root ApplicationModule.

app.module.ts
JavaScript TypeScript
TypeScript

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [__dirname + '/../**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
  ],
})
export class ApplicationModule {}

The forRoot() method accepts the same configuration object as createConnection() from the TypeORM package. Futhermore, instead of passing anything to the forRoot(), we can create an ormconfig.json file in the project root directory.

ormconfig.json
JSON

{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "root",
  "database": "test",
  "entities": ["src/**/**.entity{.ts,.js}"],
  "synchronize": true
}

Now we can simply leave the parenthesis empty:

app.module.ts
JavaScript TypeScript
TypeScript

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forRoot()],
})
export class ApplicationModule {}

Afterwards, the Connection and EntityManager will be available to inject across entire project (without importing any module elsewhere), for example in this way:

app.module.ts
JavaScript TypeScript
TypeScript

import { Connection } from 'typeorm';

@Module({
  imports: [TypeOrmModule.forRoot(), PhotoModule],
})
export class ApplicationModule {
  constructor(private readonly connection: Connection) {}
}
TypeScript

import { Connection } from 'typeorm';

@Dependencies(Connection)
@Module({
  imports: [TypeOrmModule.forRoot(), PhotoModule],
})
export class ApplicationModule {
  constructor(connection) {
    this.connection = connection;
  }
}

Repository pattern

The TypeORM supports the repository design pattern, so each entity has its own Repository. These repositories can be obtained from the database connection.

Firstly, we need at least one entity. We're gonna reuse the Photo entity from the offical documentation.

photo/photo.entity.ts
JavaScript TypeScript
TypeScript

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column({ length: 500 })
  name: string;

  @Column('text')
  description: string;

  @Column()
  filename: string;

  @Column('int')
  views: number;

  @Column()
  isPublished: boolean;
}

The Photo entity belongs to the photo directory. This directory represents the PhotoModule. 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.

Let's have a look at the PhotoModule:

photo/photo.module.ts
JavaScript TypeScript
TypeScript

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PhotoService } from './photo.service';
import { PhotoController } from './photo.controller';
import { Photo } from './photo.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Photo])],
  components: [PhotoService],
  controllers: [PhotoController],
})
export class PhotoModule {}

This module uses forFeature() method to define which repositories shall be registered in the current scope.

Now we can inject the PhotoRepository to the PhotoService using the @InjectRepository() decorator:

photo/photo.service.ts
JavaScript TypeScript
TypeScript

import { Component, Inject } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Photo } from './photo.entity';

@Component()
export class PhotoService {
  constructor(
    @InjectRepository(Photo)
    private readonly photoRepository: Repository<Photo>,
  ) {}

  async findAll(): Promise<Photo[]> {
    return await this.photoRepository.find();
  }
}
TypeScript

import { Component, Dependencies } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Photo } from './photo.entity';

@Component()
@Dependencies(InjectRepository(Photo))
export class PhotoService {
  constructor(photoRepository) {
    this.photoRepository = photoRepository;
  }

  async findAll() {
    return await this.photoRepository.find();
  }
}

That's all. The full source code's available here.

Hint Don't forget to import the PhotoModule into the root ApplicationModule.

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