How to Seed Your Database using TypeORM Seeding

Codegen using OpenAPI

Seeding your database is an essential step in the application development process. It not only facilitates prototyping but also streamlines the transition to a production environment. Whether you're in the early stages of ideation or have a fully-fledged application, database seeding can be a game-changer. In this tutorial, we'll walk you through how to seed your database using TypeORM and TypeORM Seeding, focusing on creating random data and establishing relationships.

Setting Up the Project

Setting up your project is a crucial initial step when you embark on a journey to seed your database using TypeORM Seeding. Properly configuring your project environment ensures a smooth and efficient database seeding process. In this section, we will delve deeper into setting up your project, covering essential aspects like project structure, dependencies, and configurations.

Project Structure

A well-organized project structure is essential for efficient development and maintenance. To set up your project for TypeORM Seeding, consider a structure like this:

my-project/
|-- src/
|   |-- db/
|   |   |-- entities/
|   |   |   |-- user.ts
|   |   |   |-- post.ts
|   |   |-- seeding/
|   |   |   |-- factories/
|   |   |   |   |-- user.factory.ts
|   |   |   |   |-- post.factory.ts
|   |   |   |-- seeds/
|   |   |   |   |-- initialSeed.ts
|   |   |-- dev.db
|   |-- seed.ts
|-- tsconfig.json
|-- package.json
my-project/
|-- src/
|   |-- db/
|   |   |-- entities/
|   |   |   |-- user.ts
|   |   |   |-- post.ts
|   |   |-- seeding/
|   |   |   |-- factories/
|   |   |   |   |-- user.factory.ts
|   |   |   |   |-- post.factory.ts
|   |   |   |-- seeds/
|   |   |   |   |-- initialSeed.ts
|   |   |-- dev.db
|   |-- seed.ts
|-- tsconfig.json
|-- package.json
  • src: This directory contains your application's source code. The db folder inside src is where you define your database entities and the database seeding-related code.

  • db/entities: Here, you define your TypeORM entities like User and Post. These entities represent your database tables and define their properties and relationships.

  • db/seeding: This is where you organize your database seeding code.

    • factories: In the factories directory, you define factories for generating random data for your entities. For each entity, create a corresponding factory file.

    • seeds: The seeds directory is where you define the seeders responsible for populating your database with data.

  • package.json: The package.json file is where you manage your project's dependencies and scripts.

Installing Dependencies

To start setting up your project, you need to install the necessary dependencies. As mentioned earlier, you will require two crucial packages: typeorm-seeding and faker. Here's how to install them:

npm i typeorm-extension @faker-js/faker typeorm reflect-metadata sqlite
npm i typeorm-extension @faker-js/faker typeorm reflect-metadata sqlite

Configuring Your Project

After setting up the directory structure and installing the required dependencies, it's crucial to configure your project properly. Key configuration steps include:

  • Defining your entities in the db/entities directory.

  • Creating factories for your entities in the db/seeding/factories directory.

  • Defining seeders in the db/seeding/seeds directory.

  • Creating a script in your package.json to execute the database seeding process.

With these project setup steps, you're well on your way to efficiently seeding your database using TypeORM Seeding. A well-structured project and the right dependencies are the foundation for creating a robust and testable database seeding process, ultimately leading to a more robust and production-ready application.

Understanding Factories

Before we dive into seeding, let's understand the concept of factories. Factories are essential for generating data to populate your application. For each entity in your application, you define a factory. Each factory is responsible for generating data corresponding to the properties of the entity.

For instance, if you have the following entities:

// @/src/db/entities/user.ts
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  OneToMany,
} from "typeorm";
import { Post } from "./post";
 
@Entity()
export class User {
  @PrimaryGeneratedColumn()
    id?: string;
 
  @Column()
    userName?: string;
 
  @OneToMany(() => Post, (post) => post.author)
    posts?: Post[];
}
 
// @/src/db/entities/post.ts
import typeorm, {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  ManyToOne,
} from "typeorm";
import { User } from "./user";
 
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
    id?: string;
 
  @Column()
    title!: string;
 
  @Column()
    content!: string;
 
  @ManyToOne(() => User, (user) => user.posts)
    author!: typeorm.Relation<User>;
}
// @/src/db/entities/user.ts
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  OneToMany,
} from "typeorm";
import { Post } from "./post";
 
@Entity()
export class User {
  @PrimaryGeneratedColumn()
    id?: string;
 
  @Column()
    userName?: string;
 
  @OneToMany(() => Post, (post) => post.author)
    posts?: Post[];
}
 
// @/src/db/entities/post.ts
import typeorm, {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  ManyToOne,
} from "typeorm";
import { User } from "./user";
 
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
    id?: string;
 
  @Column()
    title!: string;
 
  @Column()
    content!: string;
 
  @ManyToOne(() => User, (user) => user.posts)
    author!: typeorm.Relation<User>;
}

For the User entity, you might define a factory like this:

// @/src/db/seeding/factories/user.factory.ts
import { Faker } from "@faker-js/faker";
import { setSeederFactory } from "typeorm-extension";
import { User } from "../../entities/user";
 
export const UsersFactory = setSeederFactory(User, (faker: Faker) => {
  const user = new User();
  user.userName = faker.internet.userName();
  return user;
});
// @/src/db/seeding/factories/user.factory.ts
import { Faker } from "@faker-js/faker";
import { setSeederFactory } from "typeorm-extension";
import { User } from "../../entities/user";
 
export const UsersFactory = setSeederFactory(User, (faker: Faker) => {
  const user = new User();
  user.userName = faker.internet.userName();
  return user;
});

And for the Post entity:

// @/src/db/seeding/factories/post.factory.ts
import { Faker } from "@faker-js/faker";
import { setSeederFactory } from "typeorm-extension";
import { Post } from "../../entities/post";
 
export const PostsFactory = setSeederFactory(Post, (faker: Faker) => {
  const post = new Post();
  post.title = faker.lorem.sentence();
  post.content = faker.lorem.sentence();
  return post;
});
// @/src/db/seeding/factories/post.factory.ts
import { Faker } from "@faker-js/faker";
import { setSeederFactory } from "typeorm-extension";
import { Post } from "../../entities/post";
 
export const PostsFactory = setSeederFactory(Post, (faker: Faker) => {
  const post = new Post();
  post.title = faker.lorem.sentence();
  post.content = faker.lorem.sentence();
  return post;
});

With these factories defined, you can generate random data for your entities.

Creating a Seeder

Now, let's create a seeder, which is responsible for executing the database seeding. The seeder class name should match the name of the seed class (not the filename). Here's a basic structure for a seeder:

// @/src/db/seeding/seeds/initialSeed.ts
import { DataSource } from "typeorm";
import { Seeder, SeederFactoryManager } from "typeorm-extension";
import { User } from "../../entities/user";
import { Post } from "../../entities/post";
import { faker } from '@faker-js/faker';
 
export class MainSeeder implements Seeder {
  public async run(
    dataSource: DataSource,
    factoryManager: SeederFactoryManager,
  ): Promise<any> {
    const postsRepository = dataSource.getRepository(Post);
 
    const userFactory = factoryManager.get(User);
    const postsFactory = factoryManager.get(Post);
 
    const users = await userFactory.saveMany(10);
 
    const posts = await Promise.all(
      Array(17)
        .fill("")
        .map(async () => {
          const made = await postsFactory.make({
            author: faker.helpers.arrayElement(users),
          });
          return made;
        }),
    );
    await postsRepository.save(posts);
  }
}
// @/src/db/seeding/seeds/initialSeed.ts
import { DataSource } from "typeorm";
import { Seeder, SeederFactoryManager } from "typeorm-extension";
import { User } from "../../entities/user";
import { Post } from "../../entities/post";
import { faker } from '@faker-js/faker';
 
export class MainSeeder implements Seeder {
  public async run(
    dataSource: DataSource,
    factoryManager: SeederFactoryManager,
  ): Promise<any> {
    const postsRepository = dataSource.getRepository(Post);
 
    const userFactory = factoryManager.get(User);
    const postsFactory = factoryManager.get(Post);
 
    const users = await userFactory.saveMany(10);
 
    const posts = await Promise.all(
      Array(17)
        .fill("")
        .map(async () => {
          const made = await postsFactory.make({
            author: faker.helpers.arrayElement(users),
          });
          return made;
        }),
    );
    await postsRepository.save(posts);
  }
}

Seeding the Database

Now, let's seed the database. First, create users and specify how many you want to insert:

// @/src/seed.ts
import "reflect-metadata";
import { DataSource, DataSourceOptions } from "typeorm";
import { runSeeders, SeederOptions } from "typeorm-extension";
import { User } from "./db/entities/user";
import { Post } from "./db/entities/post";
import { UsersFactory } from "./db/seeding/factories/user.factory";
import { PostsFactory } from "./db/seeding/factories/post.factory";
import { MainSeeder } from "./db/seeding/seeds/initialSeed";
 
const options: DataSourceOptions & SeederOptions = {
  type: "sqlite", // Use SQLite instead of MySQL
  database: "src/db/dev.db", // SQLite database file path
 
  entities: [User, Post],
 
  // Additional config options brought by typeorm-extension
  factories: [UsersFactory, PostsFactory],
  seeds: [MainSeeder],
};
 
const dataSource = new DataSource(options);
 
dataSource.initialize().then(async () => {
  await dataSource.synchronize(true);
  await runSeeders(dataSource);
  process.exit();
});
 
// @/src/seed.ts
import "reflect-metadata";
import { DataSource, DataSourceOptions } from "typeorm";
import { runSeeders, SeederOptions } from "typeorm-extension";
import { User } from "./db/entities/user";
import { Post } from "./db/entities/post";
import { UsersFactory } from "./db/seeding/factories/user.factory";
import { PostsFactory } from "./db/seeding/factories/post.factory";
import { MainSeeder } from "./db/seeding/seeds/initialSeed";
 
const options: DataSourceOptions & SeederOptions = {
  type: "sqlite", // Use SQLite instead of MySQL
  database: "src/db/dev.db", // SQLite database file path
 
  entities: [User, Post],
 
  // Additional config options brought by typeorm-extension
  factories: [UsersFactory, PostsFactory],
  seeds: [MainSeeder],
};
 
const dataSource = new DataSource(options);
 
dataSource.initialize().then(async () => {
  await dataSource.synchronize(true);
  await runSeeders(dataSource);
  process.exit();
});
 

Seeding Your Database

Finally, add a script to your package.json to run the seeding process:

{
  "scripts": {
    "seed": "ts-node src/seeds.ts"
  }
}
{
  "scripts": {
    "seed": "ts-node src/seeds.ts"
  }
}

Make sure your API is running, and execute the following command to seed your database:

npm run seed
npm run seed

For a working example of how to seed your database using TypeORM Seeding, you can refer to this GitHub repository. The repository provides a practical implementation of the concepts discussed in this article.

And that's it! Your database is now populated with random data. This is a powerful way to test your application and ensure it's ready for production. Happy coding!



Testingfly

Testingfly is my spot for sharing insights and experiences, with a primary focus on tools and technologies related to test automation and governance.

Comments

Want to give your thoughts or chat about more ideas? Feel free to leave a comment here.

Instead of authenticating the giscus application, you can also comment directly on GitHub.

Related Articles

Testing iFrames using Playwright

Automated testing has become an integral part of web application development. However, testing in Safari, Apple's web browser, presents unique challenges due to the browser's strict Same-Origin Policy (SOP), especially when dealing with iframes. In this article, we'll explore known issues related to Safari's SOP, discuss workarounds, and demonstrate how Playwright, a popular automation testing framework, supports automated testing in this context.

Overview of SiteCore for Beginners

Sitecore is a digital experience platform that combines content management, marketing automation, and eCommerce. It's an enterprise-level content management system (CMS) built on ASP.NET. Sitecore allows businesses to create, manage, and publish content across all channels using simple tools.