Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 59 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,18 @@ export class UserService {

## Seeding

Isn't exhausting to create some sample data into your fresh migrated database, well this time is over!
How does it work? Just, create a factory for your entities and a seeds script.
Isn't it exhausting to create some sample data for your database, well this time is over!

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

### 1. Create a factory for your entity

For all the entities we want to seed, we need to define a factory. To do so we give you the awesome [faker](https://github.com/marak/Faker.js/) library as a parameter into your factory. Then create your "fake" entity as you would normally do and return it. Those factory files should be in the `src/database/factories` folder and suffixed with `Factory`. Example `src/database/factories/UserFactory.ts`.
For all entities we want to seed, we need to define a factory. To do so we give you the awesome [faker](https://github.com/marak/Faker.js/) 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/UserFactory.ts`.

Settings can be used to pass some static value into the factory.

```typescript
factory.define(User, (faker: typeof Faker) => {
define(User, (faker: typeof Faker, settings: { roles: string[] }) => {
const gender = faker.random.number(1);
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName(gender);
Expand All @@ -273,94 +276,76 @@ factory.define(User, (faker: typeof Faker) => {
user.firstName = firstName;
user.lastName = lastName;
user.email = email;
user.roles = settings.roles;
return user;
});
```

This can be used to pass some dynamic value into the factory.
Handle relation in the entity factory like this.

```typescript
factory.define(Pet, (faker: typeof Faker, args: any[]) => {
const type = args[0];
return {
name: faker.name.firstName(),
type: type || 'dog'
};
});
```

To deal with relations you can use the entity manager like this.

```typescript
import { SeedsInterface, FactoryInterface, times } from '../../lib/seeds';
import { Pet } from '../../../src/api/models/Pet';
import { User } from '../../../src/api/models/User';

export class CreatePets implements SeedsInterface {

public async seed(factory: FactoryInterface): Promise<any> {
const connection = await factory.getConnection();
const em = connection.createEntityManager();

await times(10, async (n) => {
// This creates a pet in the database
const pet = await factory.get(Pet).create();
// This only returns a entity with fake data
const user = await factory.get(User).make();
user.pets = [pet];
await em.save(user);
});
}
define(Pet, (faker: typeof Faker, settings: undefined) => {
const gender = faker.random.number(1);
const name = faker.name.firstName(gender);

}
const pet = new Pet();
pet.name = name;
pet.age = faker.random.number();
pet.user = factory(User)({ roles: ['admin'] })
return pet;
});
```

### 2. Create a seed file

The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.
With the second function, accepting your settings defined in the factories, you are able to create different variations of entities.

```typescript
export class CreateUsers implements SeedsInterface {
export class CreateUsers implements Seed {

public async seed(factory: FactoryInterface): Promise<any> {
await factory
.get(User)
.createMany(10);
public async seed(factory: Factory, connection: Connection): Promise<any> {
await factory(User)({ roles: [] }).createMany(10);
}

}
```

With the second parameter in the `.get(<Entity>, <args>)` you are able to create different variations of entities.
Here an example with nested factories. You can use the `.map()` function to alter
the generated value before they get persisted.

```typescript
export class CreateUsers implements SeedsInterface {

public async seed(factory: FactoryInterface): Promise<any> {
await factory
.get(User, 'admin')
.create();
}

}
...
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);
...
```

Here an example with nested factories.
To deal with relations you can use the entity manager like this.

```typescript
...
await factory.get(User)
.each(async (user: User) => {
export class CreatePets implements SeedsInterface {

const pets: Pet[] = await factory.get(Pet)
.createMany(2);
public async seed(factory: FactoryInterface, connection: Connection): Promise<any> {
const connection = await factory.getConnection();
const em = connection.createEntityManager();

const petIds = pets.map((pet: Pet) => pet.Id);
await user.pets().attach(petIds);
await times(10, async (n) => {
// This creates a pet in the database
const pet = await factory(Pet)().create();
// This only returns a entity with fake data
const user = await factory(User)({ roles: ['admin'] }).make();
user.pets = [pet];
await em.save(user);
});
}

})
.create(5);
...
}
```

### 3. Run the seeder
Expand All @@ -371,6 +356,17 @@ The last step is the easiest, just hit the following command in your terminal, b
npm start db.seed
```

#### CLI Interface

| Command | Description |
| --------------------------------------------------- | ----------- |
| `npm start "db.seed"` | Run all seeds |
| `npm start "db.seed --run CreateBruce,CreatePets"` | Run specific seeds (file names without extension) |
| `npm start "db.seed -L"` | Log database queries to the terminal |
| `npm start "db.seed --factories <path>"` | Add a different path to your factories (Default: `src/database/`) |
| `npm start "db.seed --seeds <path>"` | Add a different path to your seeds (Default: `src/database/seeds/`) |
| `npm start "db.seed --config <file>"` | Path to your ormconfig.json file |

## Run in Docker container

### Install Docker
Expand Down
2 changes: 1 addition & 1 deletion package-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ module.exports = {
script: series(
'nps banner.seed',
'nps config',
runFast('./src/lib/seeds/cli.ts')
runFast('./src/lib/seed/cli.ts')
),
description: 'Seeds generated records into the database'
},
Expand Down
2 changes: 1 addition & 1 deletion src/api/middlewares/ErrorHandlerMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class ErrorHandlerMiddleware implements ExpressErrorMiddlewareInterface {
res.json({
name: error.name,
message: error.message,
errors: error['errors'] || [],
errors: error[`errors`] || [],
});

if (this.isProduction) {
Expand Down
6 changes: 2 additions & 4 deletions src/database/factories/PetFactory.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as Faker from 'faker';

import { Pet } from '../../../src/api/models/Pet';
import { Factory } from '../../lib/seeds';
import { define } from '../../lib/seed';

const factory = Factory.getInstance();

factory.define(Pet, (faker: typeof Faker) => {
define(Pet, (faker: typeof Faker) => {
const gender = faker.random.number(1);
const name = faker.name.firstName(gender);

Expand Down
6 changes: 2 additions & 4 deletions src/database/factories/UserFactory.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as Faker from 'faker';

import { User } from '../../../src/api/models/User';
import { Factory } from '../../lib/seeds';
import { define } from '../../lib/seed';

const factory = Factory.getInstance();

factory.define(User, (faker: typeof Faker) => {
define(User, (faker: typeof Faker, settings: { role: string }) => {
const gender = faker.random.number(1);
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName(gender);
Expand Down
29 changes: 25 additions & 4 deletions src/database/seeds/CreateBruce.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import { Connection } from 'typeorm';

import { User } from '../../../src/api/models/User';
import { FactoryInterface, SeedsInterface } from '../../lib/seeds';
import { Factory, Seed } from '../../lib/seed/types';

export class CreateBruce implements Seed {

public async seed(factory: Factory, connection: Connection): Promise<User> {
// const userFactory = factory<User, { role: string }>(User as any);
// const adminUserFactory = userFactory({ role: 'admin' });

// const bruce = await adminUserFactory.make();
// console.log(bruce);

// const bruce2 = await adminUserFactory.seed();
// console.log(bruce2);

// const bruce3 = await adminUserFactory
// .map(async (e: User) => {
// e.firstName = 'Bruce';
// return e;
// })
// .seed();
// console.log(bruce3);

export class CreateBruce implements SeedsInterface {
// return bruce;

public async seed(factory: FactoryInterface): Promise<User> {
const connection = await factory.getConnection();
// const connection = await factory.getConnection();
const em = connection.createEntityManager();

const user = new User();
Expand Down
13 changes: 7 additions & 6 deletions src/database/seeds/CreatePets.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Connection } from 'typeorm';

import { Pet } from '../../../src/api/models/Pet';
import { User } from '../../../src/api/models/User';
import { FactoryInterface, SeedsInterface, times } from '../../lib/seeds';
import { Factory, Seed, times } from '../../lib/seed';

export class CreatePets implements SeedsInterface {
export class CreatePets implements Seed {

public async seed(factory: FactoryInterface): Promise<any> {
const connection = await factory.getConnection();
public async seed(factory: Factory, connection: Connection): Promise<any> {
const em = connection.createEntityManager();

await times(10, async (n) => {
const pet = await factory.get(Pet).create();
const user = await factory.get(User).make();
const pet = await factory(Pet)().seed();
const user = await factory(User)().make();
user.pets = [pet];
await em.save(user);
});
Expand Down
12 changes: 6 additions & 6 deletions src/database/seeds/CreateUsers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Connection } from 'typeorm/connection/Connection';

import { User } from '../../../src/api/models/User';
import { FactoryInterface, SeedsInterface } from '../../lib/seeds';
import { Factory, Seed } from '../../lib/seed/types';

export class CreateUsers implements SeedsInterface {
export class CreateUsers implements Seed {

public async seed(factory: FactoryInterface): Promise<any> {
await factory
.get(User)
.createMany(10);
public async seed(factory: Factory, connection: Connection): Promise<any> {
await factory(User)().seedMany(10);
}

}
Loading