npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rabeloscoder/typeorm-seeding

v1.0.2

Published

🌱 A delightful way to seed test data into your database.

Downloads

3

Readme

❯ Table of contents

❯ Disclaimer

This package is a fork of typeorm-seeding with 2 mainly added features:

1- all seeds are logged in the database in the table typeorm_seeds just like the migrations table, in order to control what seeders should run 2- added a new command rc-typeorm-seeding create -f file-name to create a timestamped seeder file, for example 1667669365371-file-name.ts to control what seeders should run first according to the time they created at

❯ Introduction

Isn't it exhausting to create some sample data for your database, well this time is over!

How does it work? Just create a entity factory for your entities (models) and a seed script.

Entity

First create your TypeORM entities.

// user.entity.ts
@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid') id: string
  @Column({ nullable: true }) name: string
  @Column({ type: 'varchar', length: 100, nullable: false }) password: string
  @OneToMany((type) => Pet, (pet) => pet.user) pets: Pet[]

  @BeforeInsert()
  async setPassword(password: string) {
    const salt = await bcrypt.genSalt()
    this.password = await bcrypt.hash(password || this.password, salt)
  }
}

// pet.entity.ts
@Entity()
export class Pet {
  @PrimaryGeneratedColumn('uuid') id: string
  @Column() name: string
  @Column() age: number
  @ManyToOne((type) => User, (user) => user.pets)
  @JoinColumn({ name: 'user_id' })
  user: User
}

Factory

Then for each entity define a factory. The purpose of a factory is to create new entites with generate data.

Note: Factories can also be used to generate data for testing.

// user.factory.ts
define(User, (faker: Faker) => {
  const gender = faker.datatype.number(1)
  const firstName = faker.name.firstName(gender)
  const lastName = faker.name.lastName(gender)

  const user = new User()
  user.name = `${firstName} ${lastName}`
  user.password = faker.random.word()
  return user
})

// pet.factory.ts
define(Pet, (faker: Faker) => {
  const gender = faker.datatype.number(1)
  const name = faker.name.firstName(gender)

  const pet = new Pet()
  pet.name = name
  pet.age = faker.datatype.number()
  pet.user = factory(User)() as any
  return pet
})

Seeder

And last but not least, create a seeder. The seeder can be called by the configured cli command seed:run. In this case it generates 10 pets with a owner (User).

Note: seed:run must be configured first. Go to CLI Configuration.

// 1667669365371-create-pets.seed.ts
export default class CreatePets1667669365371 implements Seeder {
  public async run(factory: Factory, connection: DataSource): Promise<any> {
    await factory(Pet)().createMany(10)
  }
}

❯ Installation

Before using this TypeORM extension please read the TypeORM Getting Started documentation. This explains how to setup a TypeORM project.

After that install the extension with npm or yarn.

npm i @rabeloscoder/typeorm-seeding
# or
yarn add @rabeloscoder/typeorm-seeding

Configuration

To configure the path to your seeds and factories change the TypeORM config file (ormconfig.js or ormconfig.json).

The default paths are src/database/{seeds,factories}/**/*{.ts,.js}

ormconfig.ts

...
import type { ConnectionOptions } from '@rabeloscoder/typeorm-seeding';
...

export const dataSource = new DataSource({
  ...
  seeds: ['src/database/seeds/*{.ts,.js}'],
  migrations: ['src/database/migrations/*{.ts,.js}'],
  cli: {
    seedsDir: 'src/database/seeds',
  },
  ...
} as unknown as ConnectionOptions)

.env

TYPEORM_SEEDING_FACTORIES=src/factories/**/*{.ts,.js}
TYPEORM_SEEDING_SEEDS=src/seeds/**/*{.ts,.js}

CLI Configuration

Available Binaries

For better compatibily there are multiple compiled options for the cli binary to cover most of the use cases:

  • rc-typeorm-seeding regular commonjs
  • rc-typeorm-seeding-ts-node-commonjs using ts-node loader
  • rc-typeorm-seeding-ts-node-esm using ts-node/esm loader

Usage Guide

Add the following scripts to your package.json file to configure the seed cli commands.

"scripts": {
  "seed:config": "rc-typeorm-seeding config",
  "seed:run": "rc-typeorm-seeding seed",
  "seed:create": "rc-typeorm-seeding create"
  ...
}

To execute the seed run npm run seed:run in the terminal.

Note 1: More CLI options are here

Add the following TypeORM cli commands to the package.json to drop and sync the database.

"scripts": {
  ...
  "schema:drop": "ts-node ./node_modules/typeorm/cli.js schema:drop",
  "schema:sync": "ts-node ./node_modules/typeorm/cli.js schema:sync",
  ...
}

CLI Options

| Option | Default | Description | | ---------------------- | --------------- | --------------------------------------------------------------------------- | | --seed or -s | null | Option to specify a seeder class to run individually. | | --dataSource or -d | ormconfig.ts | Name to the typeorm config file. | | --root or -r | process.cwd() | Path to the typeorm config file. | | --fileName or -f | null | Name of the generated seeder name, required on seed:create

❯ Basic Seeder

A seeder class only contains one method by default run. Within this method, you may insert data into your database. For manually insertion use the Query Builder or use the Entity Factory

Note. The seeder files will be executed alphabetically.

import { Factory, Seeder } from '@rabeloscoder/typeorm-seeding'
import { DataSource } from 'typeorm'
import { User } from '../entities'

export default class CreateUsers1668297160475 implements Seeder {
  public async run(factory: Factory, connection: DataSource): Promise<any> {
    await connection
      .createQueryBuilder()
      .insert()
      .into(User)
      .values([
        { firstName: 'Timber', lastName: 'Saw' },
        { firstName: 'Phantom', lastName: 'Lancer' },
      ])
      .execute()
  }
}

❯ Using Entity Factory

Of course, manually specifying the attributes for each entity seed is cumbersome. Instead, you can use entity factories to conveniently generate large amounts of database records.

For all entities we want to create, we need to define a factory. To do so we give you the awesome faker library as a parameter into your factory. Then create your "fake" entity and return it. Those factory files should be in the src/database/factories folder and suffixed with .factory like src/database/factories/user.factory.ts.

| Types | Description | | --------------- | ------------------------------------------------------------------------------- | | Entity | TypeORM Entity like the user or the pet in the samples. | | Context | Argument to pass some static data into the factory function. | | EntityFactory | This object is used to make new filled entities or create it into the database. |

define

The define function creates a new entity factory.

define: <Entity, Context>(entity: Entity, factoryFn: FactoryFunction<Entity, Context>) => void;
import { Faker } from '@faker-js/faker'
import { define } from '@rabeloscoder/typeorm-seeding'
import { User } from '../entities'

define(User, (, context: { roles: string[] }) => { ... })

factory

Factory retrieves the defined factory function and returns the EntityFactory to start creating new enities.

factory: (entity: Entity) => (context?: Context) => EntityFactory<Entity, Context>
factory(Pet)()
factory(Pet)({ name: 'Balou' })

EntityFactory

map

Use the .map() function to alter the generated value before they get persisted.

map(mapFunction: (entity: Entity) => Promise<Entity>): EntityFactory<Entity, Context>
await factory(User)()
  .map(async (user: User) => {
    const pets: Pet[] = await factory(Pet)().createMany(2)
    const petIds = pets.map((pet: Pet) => pet.Id)
    await user.pets().attach(petIds)
  })
  .createMany(5)

make & makeMany

Make and makeMany executes the factory functions and return a new instance of the given entity. The instance is filled with the generated values from the factory function, but not saved in the database.

overrideParams - Override some of the attributes of the entity.

make(overrideParams: EntityProperty<Entity> = {}): Promise<Entity>
await factory(User)().make()
await factory(User)().makeMany(10)

// override the email
await factory(User)().make({ email: '[email protected]' })
await factory(User)().makeMany(10, { email: '[email protected]' })

create & createMany

the create and createMany method is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database.

overrideParams - Override some of the attributes of the entity. saveOptions - Save options from typeorm

create(overrideParams: EntityProperty<Entity> = {}, saveOptions?: SaveOptions): Promise<Entity>
createMany(amount: number, overrideParams: EntityProperty<Entity> = {}, saveOptions?: SaveOptions): Promise<Entity>
await factory(User)().create()
await factory(User)().createMany(10)

// override the email
await factory(User)().create({ email: '[email protected]' })
await factory(User)().createMany(10, { email: '[email protected]' })

// using save options
await factory(User)().create({ email: '[email protected]' }, { listeners: false })
await factory(User)().createMany(10, { email: '[email protected]' }, { listeners: false })

❯ Seeding Data in Testing

The entity factories can also be used in testing. To do so call the useSeeding function, which loads all the defined entity factories.

Choose your test database wisley. We suggest to run your test in a sqlite in memory database.

{
  "type": "sqlite",
  "name": "memory",
  "database": ":memory:"
}

However, if the test database is not in memory, than use the --runInBand flag to disable parallelizes runs.

describe("UserService", () => {
  let connection: Connection

  beforeAll(async (done) => {
    connection = await useRefreshDatabase({ connection: 'memory' })
    await useSeeding()

    const user = await factory(User)().make()
    const createdUser = await factory(User)().create()

    await runSeeder(CreateUserSeed)
    done()
  })

  afterAll(async (done) => {
    await tearDownDatabase()
    done()
  })

  test('Should ...', () => { ... })
})

useSeeding

Loads the defined entity factories.

useSeeding(options: ConfigureOption = {}): Promise<void>

runSeeder

Runs the given seeder class.

runSeeder(seed: SeederConstructor): Promise<void>

useRefreshDatabase

Connects to the database, drops it and recreates the schema.

useRefreshDatabase(options: ConfigureOption = {}): Promise<Connection>

tearDownDatabase

Closes the open database connection.

tearDownDatabase(): Promise<void>

ConfigureOption

interface ConfigureOption {
  root?: string // path to the orm config file. Default = process.cwd()
  configName?: string // name of the config file. eg. ormconfig.js
  connection?: string // name of the database connection.
}

❯ Example Projects

Please fill free to add your open-source project here. This helps others to better understand the seeding technology.

| Project | Description | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | copa-ch/copa-backend | 🚀 Nest application written in TypeScript for the COPA project. This app manages your tournaments and generates the schedules. |

❯ Changelog

Changelog

❯ License

MIT

❯ Contributions

Contributions are welcome. open a PR in https://github.com/rabelos-coder/typeorm-seeding/pulls