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

@jorgebodega/typeorm-factory

v2.1.0

Published

🌱 A delightful way to use factories in your code.

Downloads

13,007

Readme

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

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

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.

Entity

@Entity()
export class Pet {
  @PrimaryGeneratedColumn('increment')
  id!: string

  @Column()
  name!: string

  @ManyToOne(() => User, (user) => user.pets)
  @JoinColumn({ name: 'owner_id' })
  owner!: User
}

Factory

export class PetFactory extends Factory<Pet> {
  protected entity = Pet
  protected dataSource = dataSource
  protected attrs(): FactorizedAttrs<Pet> {
    return {
      name: faker.animal.insect(),
      owner: new LazyInstanceAttribute((instance) => new SingleSubfactory(UserFactory, { pets: [instance] })),
    }
  }
}

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 entity = User
  protected dataSource = dataSource // Imported datasource
  protected attrs(): FactorizedAttrs<User> = {
    ...
  }
}

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

// override the email
new UserFactory().make({ email: '[email protected]' })
new UserFactory().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 using TypeORM entity manager.

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

// override the email
new UserFactory().create({ email: '[email protected]' })
new UserFactory().createMany(10, { email: '[email protected]' })

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

attrs

Attributes objects are superset from the original entity attributes.

protected attrs: FactorizedAttrs<User> = {
  name: faker.person.firstName(),
  lastName: async () => faker.person.lastName(),
  email: new InstanceAttribute((instance) =>
    [instance.name.toLowerCase(), instance.lastName.toLowerCase(), '@email.com'].join(''),
  ),
  country: new Subfactory(CountryFactory),
}

Those factorized attributes resolves to the value of the original attribute, and could be one of the following types:

Simple value

Nothing special, just a value with same type.

protected attrs(): FactorizedAttrs<User> = {
  return {
    name: faker.person.firstName(),
  }
}

Function

Function that could be sync or async, and return a value of the same type.

protected attrs: FactorizedAttrs<User> = {
  return {
    lastName: async () => faker.person.lastName(),
  }
}

InstanceAttribute

Class with a function that receive the current instance and returns a value of the same type. It is ideal for attributes that could depend on some others to be computed.

protected attrs: FactorizedAttrs<User> = {
  return {
    ...,
    email: new EagerInstanceAttribute((instance) =>
      [instance.name.toLowerCase(), instance.lastName.toLowerCase(), '@email.com'].join(''),
    ),
  }
}

In this simple case, if name or lastName override the value in any way, the email attribute will be affected too.

There are two types of InstanceAttribute:

  • EagerInstanceAttribute: Executed after creation of the entity and before persisting it, so database id will be undefined.
  • LazyInstanceAttribute: Executed after creation of the entity and after persisting it.

Just remember that, if you use make or makeMany, the only difference between EagerInstanceAttribute and LazyInstanceAttribute is that LazyInstanceAttribute will be processed the last.

Subfactory

Subfactories are just a wrapper of another factory. This could help to avoid explicit operations that could lead to unexpected results over that factory, like

protected attrs: FactorizedAttrs<User> = {
  country: async () => new CountryFactory().create({
    name: faker.address.country(),
  }),
}

instead of the same with

protected attrs: FactorizedAttrs<User> = {
  country: new SingleSubfactory(CountryFactory, {
    name: faker.address.country(),
  }),
}

Subfactories could be created in two ways, allowing you to specify only the class or passing the instance already created. This could be useful if you have some specific class-related code in your factories:

protected attrs: FactorizedAttrs<User> = {
  country: new SingleSubfactory(CountryFactory, {
    name: faker.address.country(),
  }),
  // or
  country: new SingleSubfactory(new CountryFactory(), {
    name: faker.address.country(),
  }),
}

Subfactory just execute the same kind of operation (make or create) over the factory. There are two types of Subfactory:

  • SingleSubfactory: Execute make or create to return a single element.
  • CollectionSubfactory: Execute makeMany or createMany to return an array of elements.

A CollectionSubfactory is equivalent now to an array of SingleSubfactory, so this two statements produce the same result.

protected attrs: FactorizedAttrs<User> = {
  pets: new CollectionSubfactory(PetFactory, 2, ...)
  // or
  pets: [
    new SingleSubfactory(PetFactory, ...),
    new SingleSubfactory(PetFactory, ...),
  ],
}

Examples

Some basic examples of how to use the library could be found on the examples folder.