lparolari / typeorm-seeding

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

Home Page:https://www.npmjs.com/package/@jorgebodega/typeorm-seeding

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

logo

TypeORM Seeding

NPM NPM latest version NPM next version Semantic release

Coveralls master branch Coveralls next branch

Checks for master branch Checks for next branch

A delightful way to seed test data into your database.
Inspired by the awesome framework laravel in PHP, MikroORM seeding and the repositories from pleerock

Made with ❤️ by Gery Hirschfeld, Jorge Bodega and contributors


Additional contents

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. Add development flag if you are not using seeders nor factories in production code.

npm i [-D] @jorgebodega/typeorm-seeding
yarn add [-D] @jorgebodega/typeorm-seeding

Configuration

To configure the path to your seeders change the TypeORM config file or use environment variables like TypeORM. If both are used the environment variables will be prioritized.

ormconfig.js

module.exports = {
  ...
  seeders: ['src/seeds/**/*{.ts,.js}'],
  defaultSeeder: RootSeeder,
  ...
}

.env

TYPEORM_SEEDING_SEEDERS=src/seeds/**/*{.ts,.js}
TYPEORM_SEEDING_DEFAULT_SEEDER=RootSeeder

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 and/or seed script.

Entity

@Entity()
class User {
  @PrimaryGeneratedColumn('uuid') id: string

  @Column() name: string

  @Column() lastname: string
}

Factory

class UserFactory extends Factory<User> {
  protected definition(): User {
    const user = new User()

    user.name = 'John'
    user.lastname = 'Doe'

    return user
  }
}

Seeder

export class UserExampleSeeder extends Seeder {
  async run() {
    await new UserFactory().create({
      name: 'Jane',
    })
  }
}

Factory

Factory is how we provide a way to simplify entities creation, implementing a factory creational pattern. It is defined as an abstract class with generic typing, so you have to extend over it.

class UserFactory extends Factory<User> {
  protected definition(): User {
    ...
  }
}

definition

This function is the one that needs to be defined when extending the class. It is called to instantiate the entity and the result will be used on the rest of factory lifecycle.

protected definition(): User {
    const user = new User()

    user.name = 'John'
    user.lastname = 'Doe'

    return user
}

It is possible to create more than one factory related to a single entity, with different definition functions.

map

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

map(mapFunction: (entity: Entity) => void): Factory
new UserFactory().map((user) => {
  user.name = 'Jane'
})

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: Partial<Entity> = {}): Promise<Entity>
makeMany(amount: number, overrideParams: Partial<Entity> = {}): Promise<Entity>
new UserFactory().make()
new UserFactory().makeMany(10)

// override the email
new UserFactory().make({ email: 'other@mail.com' })
new UserFactory().makeMany(10, { email: 'other@mail.com' })

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 using TypeORM entity manager.

  • overrideParams - Override some of the attributes of the entity.
  • saveOptions - Save options from TypeORM
create(overrideParams: Partial<Entity> = {}, saveOptions?: SaveOptions): Promise<Entity>
createMany(amount: number, overrideParams: Partial<Entity> = {}, saveOptions?: SaveOptions): Promise<Entity>
new UserFactory().create()
new UserFactory().createMany(10)

// override the email
new UserFactory().create({ email: 'other@mail.com' })
new UserFactory().createMany(10, { email: 'other@mail.com' })

// using save options
new UserFactory().create({ email: 'other@mail.com' }, { listeners: false })
new UserFactory().createMany(10, { email: 'other@mail.com' }, { listeners: false })

Execution order

As the order of execution can be complex, you can check it here:

  1. Map function: Map function alters the already existing entity.
  2. Override params: Alters the already existing entity.
  3. Promises: If some attribute is a promise, the promise will be resolved before the entity is created.
  4. Factories: If some attribute is a factory, the factory will be executed with make/create like the previous one.

Faker

Faker package was previously a dependency of the project, but now it is optional due to its size. If you want to use faker, you may need to install it and import it.

Instead of the previous example:

define(User, (faker: typeof Faker) => {
  const firstName = faker.name.firstName()
  const lastName = faker.name.lastName()

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

You can do:

import * as faker from 'faker'

class UserFactory extends Factory<User> {
  protected definition(): User {
    const user = new User()

    user.name = faker.name.firstName()
    user.lastname = faker.name.lastName()

    return user
  }
}

Seeder

Seeder class is how we provide a way to insert data into databases, and could be executed by the command line or by helper method. Is an abstract class with one method to be implemented, and a helper function to run some more seeder sequentially.

class UserSeeder extends Seeder {
  async run(connection: Connection) {
    ...
  }
}

run

This function is the one that needs to be defined when extending the class. Could use call to run some other seeders.

run(connection: Connection): Promise<void>
async run(connection: Connection) {
    await new UserFactory().createMany(10)

    await this.call(connection, [PetSeeder])
}

call

This function allow to run some other seeders in a sequential way.

In order to use seeders from cli command, a default seeder class must be provided as root seeder, working as a tree structure.

logo

CLI Configuration

There are two possible commands to execute, one to see the current configuration and one to run a seeder.

Add the following scripts to your package.json file to configure them.

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

config

This command just print the connection configuration.

typeorm-seeding config

Example result

{
  "name": "default",
  "type": "sqlite",
  "database": "/home/jorgebodega/projects/typeorm-seeding/test.db",
  "entities": ["sample/entities/**/*{.ts,.js}"],
  "seeders": ["sample/seeders/**/*{.ts,.js}"],
  "defaultSeeder": "RootSeeder"
}
Options
Option Default Description
--seed or -s null Option to specify a seeder class to run individually. (Only on seed command)
--connection or -c TypeORM default value Name of the TypeORM connection. Required if there are multiple connections.
--configName or -n TypeORM default value Name to the TypeORM config file.
--root or -r TypeORM default value Path to the TypeORM config file.

seed

This command execute a seeder, that could be specified as a parameter.

typeorm-seeding seed
Options
Option Default Description
--seed or -s Default seeder specified config file Option to specify a seeder class to run individually.
--connection or -c TypeORM default value Name of the TypeORM connection. Required if there are multiple connections.
--configName or -n TypeORM default value Name to the TypeORM config file.
--root or -r TypeORM default value Path to the TypeORM config file.

Testing features

We provide some testing features that we already use to test this package, like connection configuration. The entity factories can also be used in testing. To do so call the useFactories or useSeeders function.

useSeeders

Execute one or more seeders.

useSeeders(entrySeeders: ClassConstructor<Seeder> | ClassConstructor<Seeder>[]): Promise<void>
useSeeders(
  entrySeeders: ClassConstructor<Seeder> | ClassConstructor<Seeder>[],
  customOptions: Partial<ConnectionConfiguration>,
): Promise<void>

Factories

If factories are being used to create entities, just remember to clean up fake data after every execution.

About

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

https://www.npmjs.com/package/@jorgebodega/typeorm-seeding

License:MIT License


Languages

Language:TypeScript 96.6%Language:JavaScript 3.4%