Skip to content

Commit 5232f8f

Browse files
author
hirsch88
committed
Adjust seed logic to typeorm
1 parent 8da2fcb commit 5232f8f

16 files changed

+228
-81
lines changed

README.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ All script are defined in the package.json file, but the most important ones are
142142

143143
### Database Migration
144144

145-
- Run `./node_modules/.bin/typeorm create -n <migration-file-name>` to create a new migration file.
145+
- Run `typeorm migrations:create -n <migration-file-name>` to create a new migration file.
146+
- Try `typeorm -h` to see more useful cli commands like generating migration out of your models.
146147
- To migrate your database run `npm start db.migrate`.
147148
- To revert your latest migration run `npm start db.revert`.
148149
- Drops the complete database schema `npm start db.drop`.
@@ -267,19 +268,44 @@ factory.define(User, (faker: typeof Faker) => {
267268
});
268269
```
269270
270-
This is a nested example for a factory to get the foreign key of the other entity.
271+
This can be used to pass some dynamic value into the factory.
271272
272273
```typescript
273274
factory.define(Pet, (faker: typeof Faker, args: any[]) => {
274275
const type = args[0];
275276
return {
276277
name: faker.name.firstName(),
277-
type: type || 'dog',
278-
userId: factory.get(User).returning('id')
278+
type: type || 'dog'
279279
};
280280
});
281281
```
282282
283+
To deal with relations you can use the entity manager like this.
284+
285+
```typescript
286+
import { SeedsInterface, FactoryInterface, times } from '../../lib/seeds';
287+
import { Pet } from '../../../src/api/models/Pet';
288+
import { User } from '../../../src/api/models/User';
289+
290+
export class CreatePets implements SeedsInterface {
291+
292+
public async seed(factory: FactoryInterface): Promise<any> {
293+
const connection = await factory.getConnection();
294+
const em = connection.createEntityManager();
295+
296+
await times(10, async (n) => {
297+
// This creates a pet in the database
298+
const pet = await factory.get(Pet).create();
299+
// This only returns a entity with fake data
300+
const user = await factory.get(User).make();
301+
user.pets = [pet];
302+
await em.save(user);
303+
});
304+
}
305+
306+
}
307+
```
308+
283309
### 2. Create a seed file
284310
285311
The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as Faker from 'faker';
2+
import { Factory } from '../../lib/seeds';
3+
import { Pet } from '../../../src/api/models/Pet';
4+
// import { User } from '../../../src/api/models/User';
5+
6+
const factory = Factory.getInstance();
7+
8+
9+
/**
10+
* Pet factory
11+
*/
12+
factory.define(Pet, (faker: typeof Faker) => {
13+
const gender = faker.random.number(1);
14+
const name = faker.name.firstName(gender);
15+
16+
const pet = new Pet();
17+
pet.name = name;
18+
pet.age = faker.random.number();
19+
return pet;
20+
});

src/database/migrations/1511105183653-CreateUserTable.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ export class CreateUserTable1511105183653 implements MigrationInterface {
88
\`id\` varchar(255) NOT NULL PRIMARY KEY,
99
\`first_name\` varchar(255) NOT NULL,
1010
\`last_name\` varchar(255) NOT NULL,
11-
\`email\` varchar(255) NOT NULL) ENGINE=InnoDB`
11+
\`email\` varchar(255) NOT NULL) ENGINE=InnoDB;`
1212
);
1313
}
1414

1515
public async down(queryRunner: QueryRunner): Promise<any> {
16-
await queryRunner.query(`DROP TABLE \`user\``);
16+
await queryRunner.query(`DROP TABLE \`user\`;`);
1717
}
1818

1919
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class CreatePetTable1512663524808 implements MigrationInterface {
4+
5+
public async up(queryRunner: QueryRunner): Promise<any> {
6+
await queryRunner.query(`
7+
CREATE TABLE \`pet\` (
8+
\`id\` varchar(255) NOT NULL PRIMARY KEY,
9+
\`name\` varchar(255) NOT NULL,
10+
\`age\` int(11) NOT NULL,
11+
\`userId\` varchar(255)) ENGINE=InnoDB;`
12+
);
13+
}
14+
15+
public async down(queryRunner: QueryRunner): Promise<any> {
16+
await queryRunner.query(`DROP TABLE \`pet\`;`);
17+
}
18+
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class AddUserRelationToPetTable1512663990063 implements MigrationInterface {
4+
5+
public async up(queryRunner: QueryRunner): Promise<any> {
6+
await queryRunner.query(`
7+
ALTER TABLE \`pet\`
8+
ADD CONSTRAINT \`fk_user_pet\`
9+
FOREIGN KEY (\`userId\`)
10+
REFERENCES \`user\`(\`id\`);`
11+
);
12+
}
13+
14+
public async down(queryRunner: QueryRunner): Promise<any> {
15+
await queryRunner.query(`
16+
ALTER TABLE \`pet\`
17+
DROP FOREIGN KEY \`fk_user_pet\`;`
18+
);
19+
}
20+
21+
}
22+

src/database/seeds/0000-CreateUsers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class CreateUsers implements SeedsInterface {
77
public async seed(factory: FactoryInterface): Promise<any> {
88
await factory
99
.get(User)
10-
.create(1);
10+
.create();
1111
}
1212

1313
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { SeedsInterface, FactoryInterface, times } from '../../lib/seeds';
2+
import { Pet } from '../../../src/api/models/Pet';
3+
import { User } from '../../../src/api/models/User';
4+
5+
6+
export class CreatePets implements SeedsInterface {
7+
8+
public async seed(factory: FactoryInterface): Promise<any> {
9+
const connection = await factory.getConnection();
10+
const em = connection.createEntityManager();
11+
12+
await times(10, async (n) => {
13+
const pet = await factory.get(Pet).create();
14+
const user = await factory.get(User).make();
15+
user.pets = [pet];
16+
await em.save(user);
17+
});
18+
}
19+
20+
}

src/lib/seeds/BluePrint.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ import { ObjectType } from 'typeorm';
88
export class BluePrint<Entity> {
99
constructor(
1010
public EntityClass: ObjectType<Entity>,
11-
public callback: (faker: typeof Faker, args: any[]) => any) { }
11+
public create: (faker: typeof Faker, args: any[]) => Entity) { }
1212
}

src/lib/seeds/EntityFactory.ts

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,51 @@
11
import * as Faker from 'faker';
2-
import { Connection } from 'typeorm';
2+
import { Connection } from 'typeorm/connection/Connection';
33
import { EntityFactoryInterface } from './EntityFactoryInterface';
44
import { BluePrint } from './BluePrint';
5-
import { getConnection } from './connection';
65

76

87
export class EntityFactory<Entity> implements EntityFactoryInterface<Entity> {
98

10-
private connection: Connection | undefined;
119
private identifier = 'id';
1210
private eachFn: (obj: any, faker: typeof Faker) => Promise<any>;
1311

1412
constructor(
1513
private faker: typeof Faker,
14+
private connection: Connection,
1615
private blueprint: BluePrint<Entity>,
1716
private args: any[]) { }
1817

19-
public returning(identifier: string): EntityFactory<Entity> {
20-
this.identifier = identifier;
21-
return this;
22-
}
23-
2418
public each(iterator: (entity: Entity, faker: typeof Faker) => Promise<any>): EntityFactory<Entity> {
2519
this.eachFn = iterator;
2620
return this;
2721
}
2822

29-
public async create(amount: number = 1): Promise<Entity | Entity[] | undefined> {
30-
this.connection = await getConnection();
31-
if (this.connection) {
32-
const results: Entity[] = [];
33-
for (let i = 0; i < amount; i++) {
34-
const entity = await this.build();
23+
public async make(): Promise<Entity> {
24+
return await this.makeEntity(this.blueprint.create(this.faker, this.args));
25+
}
26+
27+
public async create(): Promise<Entity> {
28+
const entity = await this.build();
29+
if (typeof this.eachFn === 'function') {
30+
await this.eachFn(entity, this.faker);
31+
}
32+
return entity;
33+
}
34+
35+
public async createMany(amount: number): Promise<Entity[]> {
36+
const results: Entity[] = [];
37+
for (let i = 0; i < amount; i++) {
38+
const entity = await this.create();
39+
if (entity) {
3540
results.push(entity);
36-
if (typeof this.eachFn === 'function') {
37-
await this.eachFn(entity, this.faker);
38-
}
39-
}
40-
await this.connection.close();
41-
if (amount === 1) {
42-
return results[0];
4341
}
44-
return results;
4542
}
46-
return;
43+
return results;
4744
}
4845

4946
private async build(): Promise<any> {
5047
if (this.connection) {
51-
const entity = await this.makeEntity(this.blueprint.callback(this.faker, this.args));
48+
const entity = await this.make();
5249
const em = this.connection.createEntityManager();
5350
try {
5451
return await em.save(this.blueprint.EntityClass, entity);

src/lib/seeds/EntityFactoryInterface.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import * as Faker from 'faker';
22

3+
34
/**
45
* EntityFactoryInterface is the one we use in our seed files.
56
* This will be returne of the main factory's get method.
67
*/
78
export interface EntityFactoryInterface<Entity> {
89
/**
9-
* Creates an amount (default 1) of the defined entity.
10+
* Creates a entity with faked data, but not persisted to the database.
1011
*/
11-
create(amount: number): Promise<Entity | Entity[] | undefined>;
12+
make(): Promise<Entity>;
1213
/**
13-
* Returns the identifier of the created entity.
14+
* Creates a new faked entity in the database.
15+
*/
16+
create(): Promise<Entity>;
17+
/**
18+
* Creates an amount (default 1) of the defined entity.
1419
*/
15-
returning(identifier: string): EntityFactoryInterface<Entity>;
20+
createMany(amount: number): Promise<Entity[] | undefined>;
1621
/**
1722
* This is called after creating a enity to the database. Use this to
1823
* create other seeds but combined with this enitiy.

0 commit comments

Comments
 (0)