Skip to content

Commit

Permalink
Merge branch 'release/1.0.0-rc.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
hirsch committed Jun 2, 2019
2 parents d6530cc + 68f940a commit 2210891
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
"semi": false,
"tabWidth": 2,
"jsxBracketSameLine": true
}
}
143 changes: 85 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@
<a href="https://david-dm.org/w3tecch/typeorm-seeding">
<img src="https://david-dm.org/w3tecch/typeorm-seeding/status.svg?style=flat" alt="dependency" />
</a>
<a href="https://travis-ci.org/w3tecch/typeorm-seeding">
<img src="https://travis-ci.org/w3tecch/typeorm-seeding.svg?branch=master" alt="travis" />
</a>
<a href="https://ci.appveyor.com/project/dweber019/typeorm-seeding/branch/master">
<img src="https://ci.appveyor.com/api/projects/status/f8e7jdm8v58hcwpq/branch/master?svg=true&passingText=Windows%20passing&pendingText=Windows%20pending&failingText=Windows%20failing" alt="appveyor" />
</a>
<a href="https://stackshare.io/hirsch88/typeorm-seeding">
<img src="https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat" alt="StackShare" />
</a>
</p>

<p align="center">
Expand All @@ -29,7 +20,7 @@

![divider](./w3tec-divider.png)

## Why
## Introduction

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

Expand All @@ -51,57 +42,71 @@ yarn add typeorm-seeding

![divider](./w3tec-divider.png)

## ❯ Usage
## ❯ Writing Seeders

The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.

```typescript
export default class CreateUsers implements Seed {
public async seed(factory: Factory, connection: Connection): Promise<any> {
await connection
.createQueryBuilder()
.insert()
.into(User)
.values([
{ firstName: 'Timber', lastName: 'Saw' },
{ firstName: 'Phantom', lastName: 'Lancer' },
])
.execute()
}
}
```

### 1. Create a factory for your entity
### Using Model Factories

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
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);
const email = faker.internet.email(firstName, lastName);

const user = new User();
user.firstName = firstName;
user.lastName = lastName;
user.email = email;
user.roles = settings.roles;
return user;
});
const gender = faker.random.number(1)
const firstName = faker.name.firstName(gender)
const lastName = faker.name.lastName(gender)
const email = faker.internet.email(firstName, lastName)

const user = new User()
user.firstName = firstName
user.lastName = lastName
user.email = email
user.roles = settings.roles
return user
})
```

Handle relation in the entity factory like this.

```typescript
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;
});
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.
In your seed script you can use the factory like this.
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 Seed {

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

export default class CreateUsers implements Seed {
public async seed(factory: Factory, connection: Connection): Promise<any> {
await factory(User)({ roles: [] }).createMany(10)
}
}
```

Expand Down Expand Up @@ -134,25 +139,47 @@ await factory(User)()
To deal with relations you can use the entity manager like this.

```typescript
export class CreatePets implements SeedsInterface {

public async seed(factory: FactoryInterface, connection: Connection): 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(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);
});
}

export default class CreatePets implements SeedsInterface {
public async seed(
factory: FactoryInterface,
connection: Connection,
): 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(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)
})
}
}
```

## ❯ Running Seeders

Once you have written your seeder, you can add this script to your `package.json`.

```
"scripts": {
"seed": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed"
...
}
```

Now you are able to execute your seeds with this command `npm run seed`.

### CLI Options

| Option | Default | Description |
| --- | --- | --- |
| `--config` or `--c` | `ormconfig.js` | Path to the typeorm config file (json or js). |
| `--seeds` or `--s` | `database/seeds` | Directory where seeds are. |
| `--factories` or `--f` | `database/factories` | Directory where enity factories are. |

## ❯ Example

A good example is in the [express-typescript-boilerplate](https://github.com/w3tecch/express-typescript-boilerplate) repository.
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typeorm-seeding",
"version": "1.0.0-beta.7",
"version": "1.0.0-rc.1",
"description": "TypeORM seeding",
"main": "dist/typeorm-seeding.js",
"module": "dist/typeorm-seeding.es.js",
Expand Down Expand Up @@ -31,6 +31,7 @@
"rollup-plugin-cli": "^0.1.5",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-hashbang": "^2.2.2",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^3.4.0",
Expand All @@ -41,7 +42,7 @@
"typescript": "^3.0.3"
},
"dependencies": {
"@types/node": "^10.11.0",
"@types/node": "^12.0.4",
"chalk": "^2.4.2",
"faker": "^4.1.0",
"glob": "^7.1.3",
Expand Down
6 changes: 6 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import globals from 'rollup-plugin-node-globals'
import builtins from 'rollup-plugin-node-builtins'
import pkg from './package.json'
import hashbang from 'rollup-plugin-hashbang'
import json from 'rollup-plugin-json'

export default [
{
Expand Down Expand Up @@ -59,6 +60,11 @@ export default [
...Object.keys(pkg.peerDependencies || {}),
],
plugins: [
json({
exclude: ['node_modules/**'],
preferConst: true,
compact: true,
}),
cli(),
hashbang(),
typescript({
Expand Down
20 changes: 14 additions & 6 deletions src/commands/seed.command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as yargs from 'yargs'
import chalk from 'chalk'
import { printError } from '../utils'
import {
loadConnection,
setConnection,
loadEntityFactories,
loadSeeds,
runSeed,
} from '../typeorm-seeding'
import * as pkg from '../../package.json'

export class SeedCommand implements yargs.CommandModule {
command = 'seed'
Expand Down Expand Up @@ -40,12 +42,12 @@ export class SeedCommand implements yargs.CommandModule {
factoryFiles = await loadEntityFactories(args.factories as string)
seedFiles = await loadSeeds(args.seeds as string)
} catch (error) {
console.error(error)
printError('Could not load factories and seeds!', error)
process.exit(1)
}

// Status logging to print out the amount of factories and seeds.
log(chalk.bold('seeds'))
log(chalk.bold(`typeorm-seeding v${(pkg as any).version}`))
log(
'🔎 ',
chalk.gray.underline(`found:`),
Expand All @@ -61,7 +63,10 @@ export class SeedCommand implements yargs.CommandModule {
const connection = await loadConnection(args.config as string)
setConnection(connection)
} catch (error) {
console.error(error)
printError(
'Database connection failed! Check your typeORM config file.',
error,
)
process.exit(1)
}

Expand All @@ -72,18 +77,21 @@ export class SeedCommand implements yargs.CommandModule {
className = className.replace('.ts', '').replace('.js', '')
className = className.split('-')[className.split('-').length - 1]
log(
'\n' + chalk.gray.underline(`executing seed: `),
chalk.gray.underline(`executing seed:`),
chalk.green.bold(`${className}`),
)
const seedFileObject: any = require(seedFile)
await runSeed(seedFileObject.default)
} catch (error) {
console.error(error)
printError(
'Could not run the seeds! Check if your seed script exports the class as default. Verify that the path to the seeds and factories is correct.',
error,
)
process.exit(1)
}
}

log('\n👍 ', chalk.gray.underline(`finished seeding`))
log('👍 ', chalk.gray.underline(`finished seeding`))
process.exit(0)
}
}
4 changes: 1 addition & 3 deletions src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ export const loadConnection = async (
} else {
try {
ormconfig = await getConnectionOptions()
} catch (e) {
} catch (_) {
ormconfig = require(path.join(process.cwd(), configPath))
}
}

// ormconfig.entities = [];

return createConnection(ormconfig)
}
16 changes: 11 additions & 5 deletions src/entity-factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as Faker from 'faker'
import { Connection, ObjectType } from 'typeorm'
import { FactoryFunction, EntityProperty } from './types'
import { isPromiseLike } from './utils'
import { isPromiseLike, printError } from './utils'

export class EntityFactory<Entity, Settings> {
private mapFunction: (entity: Entity) => Promise<Entity>
Expand Down Expand Up @@ -62,10 +62,14 @@ export class EntityFactory<Entity, Settings> {
const entity = await this.make(overrideParams)
return await em.save<Entity>(entity)
} catch (error) {
throw new Error('Could not save entity')
const message = 'Could not save entity'
printError(message, error)
throw new Error(message)
}
} else {
throw new Error('No db connection is given')
const message = 'No db connection is given'
printError(message)
throw new Error(message)
}
}

Expand Down Expand Up @@ -111,8 +115,10 @@ export class EntityFactory<Entity, Settings> {
if (typeof (subEntityFactory as any).make === 'function') {
entity[attribute] = await (subEntityFactory as any).make()
}
} catch (e) {
throw new Error(`Could not make ${(subEntityFactory as any).name}`)
} catch (error) {
const message = `Could not make ${(subEntityFactory as any).name}`
printError(message, error)
throw new Error(message)
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import chalk from 'chalk'

/**
* Returns the name of a class
*/
Expand Down Expand Up @@ -25,3 +27,13 @@ export const times = async <TResult>(
}
return rs
}

/**
* Prints the error to the console
*/
export const printError = (message: string, error?: any) => {
console.log('\n❌ ', chalk.red(message))
if (error) {
console.error(error)
}
}
2 changes: 1 addition & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"ordered-imports": [false],
"max-line-length": [true, 150],
"member-ordering": [false],
"interface-name": [false],
"arrow-parens": false,
"interface-name": [false],
"object-literal-sort-keys": false
},
"rulesDirectory": []
Expand Down
Loading

0 comments on commit 2210891

Please sign in to comment.