DEV Community

Cover image for Populate your tables with Nest.js, TypeORM & Docker
Amin
Amin

Posted on

Populate your tables with Nest.js, TypeORM & Docker

Requirements

Create a brand-new Nest.js application

mkdir seed-demo
cd seed-demo
touch .env 
Enter fullscreen mode Exit fullscreen mode
DATABASE_NAME=database
DATABASE_USER=user
DATABASE_PASSWORD=password
Enter fullscreen mode Exit fullscreen mode
touch docker-compose.yaml
Enter fullscreen mode Exit fullscreen mode
version: "3"

services:
  node:
    image: node:19.0.0-alpine
    user: node
    working_dir: /home/node
    tty: true
    stdin_open: true
    env_file: .env
    ports:
      - 3000:3000
    volumes:
      - .:/home/node

  postgresql:
    image: postgres:15.2-alpine3.17
    environment:
      POSTGRES_DB: $DATABASE_NAME
      POSTGRES_USER: $DATABASE_USER
      POSTGRES_PASSWORD: $DATABASE_PASSWORD
Enter fullscreen mode Exit fullscreen mode
docker compose up --detach
docker compose exec node npx @nestjs/cli new .
docker compose exec node npm run start:dev
Enter fullscreen mode Exit fullscreen mode

Install TypeORM

docker compose exec node npm install --save --save-exact typeorm @nestjs/typeorm pg
Enter fullscreen mode Exit fullscreen mode

Setup TypeORM

import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { TypeOrmModule } from "@nestjs/typeorm";

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "postgres",
      host: "postgresql",
      port: 5432,
      username: "user",
      password: "password",
      database: "database",
      autoLoadEntities: true,
      synchronize: process.env.ENVIRONMENT === "seed"
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Create a module

docker compose exec node npx nest generate module posts
Enter fullscreen mode Exit fullscreen mode

Create an entity

touch src/posts/posts.entity.ts
Enter fullscreen mode Exit fullscreen mode
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Post {
  @PrimaryGeneratedColumn("uuid")
  public id: string;

  @Column({
    type: "varchar",
    length: 50,
    nullable: false,
    unique: true
  })
  public title: string;

  @Column({
    type: "text",
    nullable: false
  })
  public body: string;
}
Enter fullscreen mode Exit fullscreen mode

Create a service

docker compose exec node npx nest generate service posts
Enter fullscreen mode Exit fullscreen mode
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Post } from "./posts.entity";

@Injectable()
export class PostsService {
  public constructor(@InjectRepository(Post) private readonly postRepository: Repository<Post>) { }

  public async seed() {
    const post1 = this.postRepository.create({
      title: "How to use TypeORM with NestJS",
      body: "This is a test post."
    });

    const post2 = this.postRepository.create({
      title: "How to use React with NestJS",
      body: "This is another test post."
    });

    await this.postRepository.delete({});
    await this.postRepository.save([post1, post2]);
  }
}
Enter fullscreen mode Exit fullscreen mode

Update the module

import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { Post } from "./posts.entity";
import { PostsService } from "./posts.service";

@Module({
  imports: [
    TypeOrmModule.forFeature([
      Post
    ])
  ],
  providers: [
    PostsService
  ],
  exports: [
    PostsService
  ]
})
export class PostsModule { }
Enter fullscreen mode Exit fullscreen mode

Create the seeder service

docker compose exec node npx nest generate service seed
Enter fullscreen mode Exit fullscreen mode
import { Injectable } from "@nestjs/common";
import { PostsService } from "../posts/posts.service";

@Injectable()
export class SeedService {
  public constructor(private readonly postsService: PostsService) { }

  public async seed() {
    await this.postsService.seed();
  }
}
Enter fullscreen mode Exit fullscreen mode

Create the seeder script

touch src/seed.ts
Enter fullscreen mode Exit fullscreen mode
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { SeedService } from "./seed/seed.service";

const bootstrap = async () => {
  const app = await NestFactory.createApplicationContext(AppModule);
  const seedService = app.get(SeedService);

  await seedService.seed();
  await app.close();

  console.log("Seed complete.");
}

bootstrap();
Enter fullscreen mode Exit fullscreen mode

Update the package

{
  "scripts": {
    "seed": "ENVIRONMENT=seed ts-node src/seed.ts"
  }
}
Enter fullscreen mode Exit fullscreen mode

Run the seeds

docker compose exec node npm run seed
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
pierrewahlberg profile image
Pierre Vahlberg • Edited

Did you consider using typeorm factory package along with faker for the actual data seeding?

We are using it to populate integration tests (with sqlite), it drastically eased setting up related data and faking emails, content, addresses and such.

Collapse
 
aminnairi profile image
Amin

Hi Pierre and thanks for your comment!

I don't use Factories too much because I was in search of an official solution from TypeORM but as far as I can tell there are only few libraries that will do such work.

I'm waiting for a library that will have a great developer experience to setup MTM relationships between factories without the hassle and setting up data that are related easily.

Have you found any interesting ones?