TypeORM how to seed database

Typeorm

Typeorm Problem Overview


I am running my Node JS backend using typeorm ORM.

Coming from Entity Framework, it was very easy to seed the db with a few lines such as

Database.SetInitializer(new DbInitializer()); 

Where the DbInitializer class would contain all the seeding info.

Is there a similar approach to seed the database in TypeOrm? If not, what is the recommended way of doing it?

  1. Create a new migration with the data insertion statements?
  2. Create a task where you instantiate and save entities?

Typeorm Solutions


Solution 1 - Typeorm

Unfortunately, there is no officially released solution from TypeORM (at the time this answer was being published).

But there is a nice workaround we can use:

  1. create another connection inside ormconfig.js file and specify another folder for "migrations" - in fact our seeds
  2. generate and run your seeds with -c <connection name>. That's it!

Sample ormconfig.js:

module.exports = [  {    ...,    migrations: [      'src/migrations/*.ts'    ],
    cli: {
      migrationsDir: 'src/migrations',
    }
  },
  {
    name: 'seed',
    ...,
    migrations: [
      'src/seeds/*.ts'
    ],
    cli: {
      migrationsDir: 'src/seeds',
    }
  }
]

Sample package.json:

{
  ...
  scripts: {
    "seed:generate": "ts-node typeorm migration:generate -c seed -n ",
    "seed:run": "ts-node typeorm migration:run -c seed",
    "seed:revert": "ts-node typeorm migration:revert -c seed",
  },
  ...
}

Solution 2 - Typeorm

I would love to see such functionality as well (and we're not alone), but at the moment, there's no official feature for seeding.

in lack of such a built-in feature, I think the next best thing would be to create a migration script named 0-Seed (so it precedes any other migration scripts you might have) and have the seed data populated there.

@bitwit has created a snippet that may come in handy for you; it's a function that reads the data from yaml files, which you can incorporate in the seed migration script.

after some research, however, I found another interesting approach: bind an after_create event to the table, and initialize the data in the listener.
I haven't implemented this, so I'm not sure it can be done directly with TypeORM.

Solution 3 - Typeorm

For those who are using TypeORM with Nest.js, here is a solution to perform your seeding programatically, from within your code.

Rough idea:

  • We create a dedicated "seeding module" containing a "seeding middleware" that is responsible for conducting the seeding and ensuring that all seeding is done before any request is answered.
  • For any request that arrives, the seeding middleware intercepts it and postpones it until it is confirmed that seeding is done.
  • If the db has been seeded, the "seeding middleware" passes the request to the next middleware.
  • To speed things up, the "seeding middleware" keeps a "seeding complete" flag as state in memory to avoid any further db-checks after the seeding has occurred.

Implementation:

For this to work, first create a module that registers a middleware that listens to all incoming requests:

// file: src/seeding/SeedingModule.ts

@Module({})
export class SeedingModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(SeedingMiddleware)
      .forRoutes('*')
  }
}

Now create the middleware:

// file: src/seeding/SeedingMiddleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import { EntityManager } from 'typeorm';
import { SeedingLogEntry } from './entities/SeedingLogEntry.entity';

@Injectable()
export class SeedingMiddleware implements NestMiddleware {

  // to avoid roundtrips to db we store the info about whether
  // the seeding has been completed as boolean flag in the middleware
  // we use a promise to avoid concurrency cases. Concurrency cases may
  // occur if other requests also trigger a seeding while it has already
  // been started by the first request. The promise can be used by other
  // requests to wait for the seeding to finish.
  private isSeedingComplete: Promise<boolean>;

  constructor(
    private readonly entityManager: EntityManager,
  ) {}

  async use(req: Request, res: Response, next: Function) {

    if (await this.isSeedingComplete) {
      // seeding has already taken place,
      // we can short-circuit to the next middleware
      return next();
    }

    this.isSeedingComplete = (async () => {
      // for example you start with an initial seeding entry called 'initial-seeding'
      // on 2019-06-27. if 'initial-seeding' already exists in db, then this
      // part is skipped
      if (!await this.entityManager.findOne(SeedingLogEntry, { id: 'initial-seeding' })) {
        await this.entityManager.transaction(async transactionalEntityManager => {
          await transactionalEntityManager.save(User, initialUsers);
          await transactionalEntityManager.save(Role, initialRoles);
          // persist in db that 'initial-seeding' is complete
          await transactionalEntityManager.save(new SeedingLogEntry('initial-seeding'));
        });
      }

      // now a month later on 2019-07-25 you add another seeding
      // entry called 'another-seeding-round' since you want to initialize
      // entities that you just created a month later
      // since 'initial-seeding' already exists it is skipped but 'another-seeding-round'
      // will be executed now.
      if (!await this.entityManager.findOne(SeedingLogEntry, { id: 'another-seeding-round' })) {
        await this.entityManager.transaction(async transactionalEntityManager => {
          await transactionalEntityManager.save(MyNewEntity, initalSeedingForNewEntity);
          // persist in db that 'another-seeding-round' is complete
          await transactionalEntityManager.save(new SeedingLogEntry('another-seeding-round'));
        });
      }

      return true;
    })();

    await this.isSeedingComplete;

    next();
  }
}

Finally here is the entity that we use to record in our db that a seeding of a certain type has occured. Make sure to register it as entity in your TypeOrmModule.forRoot call.

// file: src/seeding/entities/Seeding.entity.ts

import { Entity, PrimaryColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Seeding {

  @PrimaryColumn()
  public id: string;

  @CreateDateColumn()
  creationDate: Date;

  constructor(id?: string) {
    this.id = id;
  }
}

An alternative seeding solution using lifecycle events:

with Nest.js, you can also implement the OnApplicationBootstrap interface (see lifecycle events) instead of going for a middleware-based solution to handle your seedings. The onApplicationBootstrap method will "called once the application has fully started and is bootstrapped". This approach, however, in contrast to a middleware-solution, will not allow you to seed your db in a multi-tenant environment where db-schemas for different tenants will be created at runtime and seeding needs to be conducted several times at runtime for different tenants after they are created.

Solution 4 - Typeorm

Looks like a module is being built for this, typeorm-seeding. While using a initial migration for seeding also works its not very useful for testing where a freshly seeded DB may be needed for tests to pass. Once you start creating more migrations you can't drop, sync and run migrations without errors. This could be solved by being able to run migration:run for a single migration file but with the CLI you currently can't. My solution was a light weight script that accesses the QueryRunner object through a typeorm connection:

// testSeed.ts

import { ConnectionOptions, createConnection, QueryRunner } from "typeorm";

import { config } from "../config";

import { DevSeed } from "./DevSeed";

createConnection(config.typeOrmConfig as ConnectionOptions).then(async connection => {
    let queryRunner = connection.createQueryRunner("master");
    
    // runs all seed SQL commands in this function.
    await DevSeed(queryRunner);

    await queryRunner.release();
    return connection.close();
});

Then run node ./dist/path/to/testSeed.js

Solution 5 - Typeorm

In Nest.js, this is what B12Toaster's alternative solution using OnApplicationBootstrap could look like.

src/seeding.service.ts

    import { Injectable, Logger } from '@nestjs/common';
    import { EntityManager } from 'typeorm';

    import { UserEntity} from 'src/entities/user.entity';
    import { RoleEntity } from 'src/entities/role.entity';

    import { userSeeds } from 'src/seeds/user.seeds';
    import { roleSeeds } from 'src/seeds/role.seeds';

    @Injectable()
    export class SeedingService {
      constructor(
        private readonly entityManager: EntityManager,
      ) {}

      async seed(): Promise<void> {

        // Replace with your own seeds
        await Promise.all([
          this.entityManager.save(UserEntity, userSeeds),
          this.entityManager.save(RoleEntity, roleSeeds),
        ]);

      }
    }

src/app.module.ts

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

    @Module({
      imports: [
        TypeOrmModule.forRootAsync({
          useFactory: async () =>
            Object.assign(await getConnectionOptions(), {
              autoLoadEntities: true,
            }),
        }),
        TypeOrmModule.forFeature([
          CompanyOrmEntity,
          ProductOrmEntity,
        ]),
      ],
      providers: [
        SeedingService,
        ...
      ],
      ...
    })
    export class AppModule implements OnApplicationBootstrap {
      constructor(
        private readonly seedingService: SeedingService,
      ) {}

      async onApplicationBootstrap(): Promise<void> {
        await this.seedingService.seed();
      }
    }

Solution 6 - Typeorm

Also for NestJS you can use the nestjs-console package to execute tasks. This way you'll have access to entities, services, repositories, etc. I like this better than the middleware solution proposed by @B12Toaster because you don't need to maintain it as production code.

Create a seed command as shown below, then simply: yarn console seed.

There's a working example here (runs in the CI): https://github.com/thisismydesign/nestjs-starter/tree/ee7abf6d481b1420708e87dea3cb99ca110cc168

Along these lines:

src/console.ts

import { BootstrapConsole } from 'nestjs-console';
import { AppModule } from 'src/server/app/app.module';

const bootstrap = new BootstrapConsole({
  module: AppModule,
  useDecorators: true,
});
bootstrap.init().then(async (app) => {
  try {
    await app.init();
    await bootstrap.boot();
    app.close();

    process.exit(0);
  } catch (e) {
    app.close();

    process.exit(1);
  }
});

src/console/seed.service.ts

import { Inject } from '@nestjs/common';
import { Console, Command } from 'nestjs-console';
import { UsersService } from 'src/users/users.service';

@Console()
export class SeedService {
  constructor(
    @Inject(UsersService) private usersService: UsersService,
  ) {}

  @Command({
    command: 'seed',
    description: 'Seed DB',
  })
  async seed(): Promise<void> {
    await this.seedUsers();
  }

  async seedUsers() {
    await this.usersService.create({ name: 'Joe' });
  }
}

package.json

{
  "scripts": {
    "console": "ts-node -r tsconfig-paths/register src/console.ts",

Solution 7 - Typeorm

I have modified @B12Toaster's answer (For seeding to the database in NestJs) to be able to take an array of objects to seed. His answer helped considerably and I was also looking for a way to make it take many DB objects at once. Here's the little modification made to the seedingMiddleware.ts

// file: src/seeding/SeedingMiddleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import { TxnCategory } from 'src/txn-categories/entities/txn-category.entity';
import { init_categories } from 'src/txn-categories/entities/txn_cat-seed-data';
import { init_services } from 'src/txn-services/entities/txn-serv-seed-data';
import { TxnService } from 'src/txn-services/entities/txn-service.entity';
import { EntityManager } from 'typeorm';
import { Seeding } from './entities/seeding.entity';

@Injectable()
export class SeedingMiddleware implements NestMiddleware {
  // to avoid roundtrips to db we store the info about whether
  // the seeding has been completed as boolean flag in the middleware
  // we use a promise to avoid concurrency cases. Concurrency cases may
  // occur if other requests also trigger a seeding while it has already
  // been started by the first request. The promise can be used by other
  // requests to wait for the seeding to finish.
  private isSeedingComplete: Promise<boolean>;

  constructor(private readonly entityManager: EntityManager) {}

  async use(req: Request, res: Response, next: any) {
    if (await this.isSeedingComplete) {
      // seeding has already taken place,
      // we can short-circuit to the next middleware
      return next();
    }

    this.isSeedingComplete = (async () => {
      // for example you start with an initial seeding entry called 'initial-seeding'
      // if 'init-txn-cats' and 'init-txn-serv' already exists in db, then this
      // part is skipped
  
      // MODIFIED
      if (
        !(await this.entityManager.findOne(Seeding, {
          id: 'init-txn-cats',
        }))
      ) {
        await this.entityManager.transaction(
          async (transactionalEntityManager) => {
            for (let i = 0; i < init_categories.length; i++) {
              await transactionalEntityManager.save(
                TxnCategory,
                init_categories[i],
              );
            }
            await transactionalEntityManager.save(new Seeding('init-txn-cats'));
          },
        );
      }

      // MODIFIED
      if (
        !(await this.entityManager.findOne(Seeding, {
          id: 'init-txn-serv',
        }))
      ) {
        await this.entityManager.transaction(
          async (transactionalEntityManager) => {
            for (let i = 0; i < init_services.length; i++) {
              await transactionalEntityManager.save(
                TxnService,
                init_services[i],
              );
            }
            await transactionalEntityManager.save(new Seeding('init-txn-serv'));
          },
        );
      }

      return true;
    })();

    await this.isSeedingComplete;
    next();
  }
}

Then the array of DB objects referenced would be like so:

// file: src/txn-categories/entities/txn_cat-seed-data.ts

export const init_categories = [
  {
    id: 1,
    category_name: 'name 1',
    category_code: 'cat_code_1',
    enabled: true,
  },
  {
    id: 2,
    category_name: 'name 2',
    category_code: 'cat_code_2',
    enabled: true,
  },
  {
    id: 3,
    category_name: 'name 3',
    category_code: 'cat_code_3',
    enabled: true,
  },

// etc
];

Same format for the src/txn-services/entities/txn-serv-seed-data.ts file.

Every other thing in B12Toaster's answer remains the same hence you'll still have your module and entity files as below:

SeedingModule:

// file: src/seeding/SeedingModule.ts

@Module({})
export class SeedingModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(SeedingMiddleware)
      .forRoutes('*')
  }
}

SeedingEntity:

// file: src/seeding/entities/Seeding.entity.ts

import { Entity, PrimaryColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Seeding {

  @PrimaryColumn()
  public id: string;

  @CreateDateColumn()
  creationDate: Date;

  constructor(id?: string) {
    this.id = id;
  }
}

Cheers!

Solution 8 - Typeorm

so heres how I am seeding data from an sql file with insert statement. Heres my whole migration file after adding the seed


import { MigrationInterface, QueryRunner } from 'typeorm';
import * as path from 'path';
import * as fs from 'fs';

let insertPermissionQueries = fs
	.readFileSync(path.resolve(__dirname, '../../scripts/sql/insert.sql'))
	.toString()
	.replace(/(\r\n|\n|\r)/gm, ' ') // remove newlines
	.replace(/\s+/g, ' '); // excess white space

export class init1591103087130 implements MigrationInterface {
	name = 'init1591103087130';

	public async up(queryRunner: QueryRunner): Promise<void> {
		await queryRunner.query(
			`CREATE TABLE "public"."RoleTemp" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" text, "created_on" TIMESTAMP DEFAULT now(), "is_active" boolean DEFAULT true, "role_type" text, "created_by" uuid NOT NULL, "status" text, "alias" text, "operation" text, "rejection_reason" text, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer, CONSTRAINT "UQ_835baad60041a3413f9ef95bc07" UNIQUE ("idx"), CONSTRAINT "PK_a76dd0012be252eefbdd4a2a589" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE UNIQUE INDEX "RoleTemp_idx_key" ON "public"."RoleTemp" ("idx") `,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."PermissionRoleTemp" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "permission_base_name" text, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer NOT NULL, "permission_id" integer NOT NULL, CONSTRAINT "PK_c1f2648a18ac911e096f08c187d" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."Permission" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "base_name" text NOT NULL, "url" text NOT NULL, "method" text NOT NULL, "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "permission_type" text, "alias" text NOT NULL, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "PK_28657fa560adca66b359c18b952" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."PermissionRole" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "permission_base_name" text NOT NULL, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer NOT NULL, "permission_id" integer NOT NULL, CONSTRAINT "PK_b5e2271c229f65f17ee93677a0f" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."UserRole" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer NOT NULL, "company_user_id" integer NOT NULL, CONSTRAINT "PK_431fc1ec3d46ac513ef3701604e" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."UsersTemp" ("idx" uuid DEFAULT uuid_generate_v1(), "username" text, "first_name" text, "middle_name" text, "last_name" text, "password" text, "email" text, "address" text, "phone_number" text, "phone_ext" text, "company_idx" uuid, "is_superadmin" boolean NOT NULL DEFAULT false, "operation" text, "created_by" text, "status" text, "rejection_reason" text, "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer, "user_id" integer, CONSTRAINT "PK_9d3fbcec3cc0b054324f93da038" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."Role" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" text NOT NULL, "alias" text NOT NULL, "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "role_type" text, "created_by" uuid NOT NULL, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "UQ_c9a53325a7642edb5f9bd44f5aa" UNIQUE ("idx"), CONSTRAINT "PK_422113329ddec949e76c7943c56" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE UNIQUE INDEX "Role_idx_key" ON "public"."Role" ("idx") `,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."Users" ("idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "username" text NOT NULL, "first_name" text NOT NULL, "middle_name" text, "last_name" text NOT NULL, "password" text NOT NULL, "email" text, "address" text, "phone_number" text, "phone_ext" text, "company_idx" uuid, "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "is_superadmin" boolean NOT NULL DEFAULT false, "id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "role_id" integer NOT NULL, CONSTRAINT "PK_ac3c96e3c912cbda773b7c7edc9" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`CREATE TABLE "public"."CompanyUser" ("id" SERIAL NOT NULL, "is_obsolete" boolean NOT NULL DEFAULT false, "modified_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "idx" uuid NOT NULL DEFAULT uuid_generate_v4(), "company_idx" uuid, "created_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "is_active" boolean NOT NULL DEFAULT true, "user_id" integer, CONSTRAINT "PK_4a915d69bf079a8e5dd10784cc3" PRIMARY KEY ("id"))`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."RoleTemp" ADD CONSTRAINT "FK_d304588d17c9349ca6e7ebee5d3" FOREIGN KEY ("role_id") REFERENCES "public"."Role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRoleTemp" ADD CONSTRAINT "FK_7e7cdde853500f56b3db43fc258" FOREIGN KEY ("role_id") REFERENCES "public"."RoleTemp"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRoleTemp" ADD CONSTRAINT "FK_0068d3de1c59050561d35f17544" FOREIGN KEY ("permission_id") REFERENCES "public"."Permission"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRole" ADD CONSTRAINT "FK_5b57492441a568bc7562fbbaa5b" FOREIGN KEY ("role_id") REFERENCES "public"."Role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRole" ADD CONSTRAINT "FK_1951a810af06342fcd4530ec61c" FOREIGN KEY ("permission_id") REFERENCES "public"."Permission"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UserRole" ADD CONSTRAINT "FK_fb09d73b0dd011be81a272e1efa" FOREIGN KEY ("role_id") REFERENCES "public"."Role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UserRole" ADD CONSTRAINT "FK_b221977a41587e58d7c58e16db0" FOREIGN KEY ("company_user_id") REFERENCES "public"."CompanyUser"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UsersTemp" ADD CONSTRAINT "FK_6d74dfaddaa94e1bba0c8c12a2f" FOREIGN KEY ("role_id") REFERENCES "public"."Role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UsersTemp" ADD CONSTRAINT "FK_e5b2930fe35042dab17945bb131" FOREIGN KEY ("user_id") REFERENCES "public"."Users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."Users" ADD CONSTRAINT "FK_34be125e29cee0e71d58456aed7" FOREIGN KEY ("role_id") REFERENCES "public"."Role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."CompanyUser" ADD CONSTRAINT "FK_1354e3e408b5ffdebe476a6fbd2" FOREIGN KEY ("user_id") REFERENCES "public"."Users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
		);
		await queryRunner.query(insertPermissionQueries);
	}

	public async down(queryRunner: QueryRunner): Promise<void> {
		await queryRunner.query(
			`ALTER TABLE "public"."CompanyUser" DROP CONSTRAINT "FK_1354e3e408b5ffdebe476a6fbd2"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."Users" DROP CONSTRAINT "FK_34be125e29cee0e71d58456aed7"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UsersTemp" DROP CONSTRAINT "FK_e5b2930fe35042dab17945bb131"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UsersTemp" DROP CONSTRAINT "FK_6d74dfaddaa94e1bba0c8c12a2f"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UserRole" DROP CONSTRAINT "FK_b221977a41587e58d7c58e16db0"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."UserRole" DROP CONSTRAINT "FK_fb09d73b0dd011be81a272e1efa"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRole" DROP CONSTRAINT "FK_1951a810af06342fcd4530ec61c"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRole" DROP CONSTRAINT "FK_5b57492441a568bc7562fbbaa5b"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRoleTemp" DROP CONSTRAINT "FK_0068d3de1c59050561d35f17544"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."PermissionRoleTemp" DROP CONSTRAINT "FK_7e7cdde853500f56b3db43fc258"`,
		);
		await queryRunner.query(
			`ALTER TABLE "public"."RoleTemp" DROP CONSTRAINT "FK_d304588d17c9349ca6e7ebee5d3"`,
		);
		await queryRunner.query(`DROP TABLE "public"."CompanyUser"`);
		await queryRunner.query(`DROP TABLE "public"."Users"`);
		await queryRunner.query(`DROP INDEX "public"."Role_idx_key"`);
		await queryRunner.query(`DROP TABLE "public"."Role"`);
		await queryRunner.query(`DROP TABLE "public"."UsersTemp"`);
		await queryRunner.query(`DROP TABLE "public"."UserRole"`);
		await queryRunner.query(`DROP TABLE "public"."PermissionRole"`);
		await queryRunner.query(`DROP TABLE "public"."Permission"`);
		await queryRunner.query(`DROP TABLE "public"."PermissionRoleTemp"`);
		await queryRunner.query(`DROP INDEX "public"."RoleTemp_idx_key"`);
		await queryRunner.query(`DROP TABLE "public"."RoleTemp"`);
	}
}



Solution 9 - Typeorm

I used a simpler method with migrations here is my code i believe it should be simpler so run this in your migrations

import { MigrationInterface, QueryRunner } from 'typeorm';
const tableName = 'foo';
const columnName = 'foo_column';
const features = ['foo_content_1', 'foo_content_2'];

export class seedIntoPermissionsTable1638518166717 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await Promise.all(features.map((feature) => queryRunner.query(`INSERT INTO ${tableName} (${columnName}) VALUES ('${feature}')`)));
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await Promise.all(features.map((feature) => queryRunner.query(`DELETE FROM ${tableName} WHERE ${columnName}='${feature}';`)));
  }
}

This is what i tend to use for my seeders.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAaron UllalView Question on Stackoverflow
Solution 1 - Typeormoleh.meleshkoView Answer on Stackoverflow
Solution 2 - TypeormEliran MalkaView Answer on Stackoverflow
Solution 3 - TypeormFelix K.View Answer on Stackoverflow
Solution 4 - Typeormwizzfizz94View Answer on Stackoverflow
Solution 5 - TypeormElias StrehleView Answer on Stackoverflow
Solution 6 - TypeormthisismydesignView Answer on Stackoverflow
Solution 7 - TypeormMoses EbenezerView Answer on Stackoverflow
Solution 8 - TypeormRubin bhandariView Answer on Stackoverflow
Solution 9 - TypeormDaniel AdegokeView Answer on Stackoverflow