From e5748aa6f33fe60dc2256f6a359ea078cf56043d Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sat, 10 Mar 2018 11:41:02 +0100 Subject: [PATCH 01/14] rewrite seed functionality --- package-scripts.js | 2 +- src/database/factories/PetFactory.ts | 6 +- src/database/factories/UserFactory.ts | 7 +- src/database/seeds/CreateBruce.ts | 31 +++- src/database/seeds/CreatePets.ts | 30 +-- src/database/seeds/CreateUsers.ts | 18 +- src/lib/seed/EntityFactory.ts | 93 ++++++++++ src/lib/seed/cli.ts | 98 ++++++++++ src/lib/{seeds => seed}/connection.ts | 0 src/lib/seed/importer.ts | 48 +++++ src/lib/seed/index.ts | 68 +++++++ src/lib/seed/make.ts | 31 ++++ src/lib/seed/types.ts | 21 +++ src/lib/seed/utils.ts | 7 + src/lib/seeds/BluePrint.ts | 11 -- src/lib/seeds/EntityFactory.ts | 91 --------- src/lib/seeds/EntityFactoryInterface.ts | 23 --- src/lib/seeds/Factory.ts | 58 ------ src/lib/seeds/FactoryInterface.ts | 33 ---- src/lib/seeds/SeedsInterface.ts | 15 -- src/lib/seeds/cli.ts | 87 --------- src/lib/seeds/index.ts | 24 --- src/lib/seeds/utils.ts | 13 -- test/e2e/api/users.test.ts | 31 ++-- test/e2e/utils/server.ts | 12 ++ yarn.lock | 233 +++++++++++++----------- 26 files changed, 578 insertions(+), 513 deletions(-) create mode 100644 src/lib/seed/EntityFactory.ts create mode 100644 src/lib/seed/cli.ts rename src/lib/{seeds => seed}/connection.ts (100%) create mode 100644 src/lib/seed/importer.ts create mode 100644 src/lib/seed/index.ts create mode 100644 src/lib/seed/make.ts create mode 100644 src/lib/seed/types.ts create mode 100644 src/lib/seed/utils.ts delete mode 100644 src/lib/seeds/BluePrint.ts delete mode 100644 src/lib/seeds/EntityFactory.ts delete mode 100644 src/lib/seeds/EntityFactoryInterface.ts delete mode 100644 src/lib/seeds/Factory.ts delete mode 100644 src/lib/seeds/FactoryInterface.ts delete mode 100644 src/lib/seeds/SeedsInterface.ts delete mode 100644 src/lib/seeds/cli.ts delete mode 100644 src/lib/seeds/index.ts delete mode 100644 src/lib/seeds/utils.ts create mode 100644 test/e2e/utils/server.ts diff --git a/package-scripts.js b/package-scripts.js index 46872f86..2e36080d 100644 --- a/package-scripts.js +++ b/package-scripts.js @@ -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' }, diff --git a/src/database/factories/PetFactory.ts b/src/database/factories/PetFactory.ts index 7679d099..b917e050 100644 --- a/src/database/factories/PetFactory.ts +++ b/src/database/factories/PetFactory.ts @@ -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); diff --git a/src/database/factories/UserFactory.ts b/src/database/factories/UserFactory.ts index bdd8aa42..e8dd0add 100644 --- a/src/database/factories/UserFactory.ts +++ b/src/database/factories/UserFactory.ts @@ -1,11 +1,10 @@ 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 }) => { + console.log('UserFactory', settings.role); const gender = faker.random.number(1); const firstName = faker.name.firstName(gender); const lastName = faker.name.lastName(gender); diff --git a/src/database/seeds/CreateBruce.ts b/src/database/seeds/CreateBruce.ts index 5a42afa5..4a3439d0 100644 --- a/src/database/seeds/CreateBruce.ts +++ b/src/database/seeds/CreateBruce.ts @@ -1,10 +1,33 @@ +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 { + console.log('CreateBruce'); + + // const userFactory = factory(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 { - const connection = await factory.getConnection(); + // const connection = await factory.getConnection(); const em = connection.createEntityManager(); const user = new User(); diff --git a/src/database/seeds/CreatePets.ts b/src/database/seeds/CreatePets.ts index 69071654..823b87ab 100644 --- a/src/database/seeds/CreatePets.ts +++ b/src/database/seeds/CreatePets.ts @@ -1,19 +1,23 @@ -import { Pet } from '../../../src/api/models/Pet'; -import { User } from '../../../src/api/models/User'; -import { FactoryInterface, SeedsInterface, times } from '../../lib/seeds'; +import { Connection } from 'typeorm'; -export class CreatePets implements SeedsInterface { +import { Factory, Seed } from '../../lib/seed/types'; - public async seed(factory: FactoryInterface): Promise { - const connection = await factory.getConnection(); - const em = connection.createEntityManager(); +// import { Pet } from '../../../src/api/models/Pet'; +// import { User } from '../../../src/api/models/User'; +export class CreatePets implements Seed { - await times(10, async (n) => { - const pet = await factory.get(Pet).create(); - const user = await factory.get(User).make(); - user.pets = [pet]; - await em.save(user); - }); + public async seed(factory: Factory, connection: Connection): Promise { + console.log('CreatePets'); + + // const connection = await factory.getConnection(); + // const em = connection.createEntityManager(); + + // await times(10, async (n) => { + // const pet = await factory.get(Pet).create(); + // const user = await factory.get(User).make(); + // user.pets = [pet]; + // await em.save(user); + // }); } } diff --git a/src/database/seeds/CreateUsers.ts b/src/database/seeds/CreateUsers.ts index 0d292e95..a50097b1 100644 --- a/src/database/seeds/CreateUsers.ts +++ b/src/database/seeds/CreateUsers.ts @@ -1,12 +1,16 @@ -import { User } from '../../../src/api/models/User'; -import { FactoryInterface, SeedsInterface } from '../../lib/seeds'; +import { Connection } from 'typeorm/connection/Connection'; -export class CreateUsers implements SeedsInterface { +import { Factory, Seed } from '../../lib/seed/types'; - public async seed(factory: FactoryInterface): Promise { - await factory - .get(User) - .createMany(10); +// import { User } from '../../../src/api/models/User'; +export class CreateUsers implements Seed { + + public async seed(factory: Factory, connection: Connection): Promise { + console.log('CreateUsers'); + + // await factory + // .get(User) + // .createMany(10); } } diff --git a/src/lib/seed/EntityFactory.ts b/src/lib/seed/EntityFactory.ts new file mode 100644 index 00000000..9afb234b --- /dev/null +++ b/src/lib/seed/EntityFactory.ts @@ -0,0 +1,93 @@ +import * as Faker from 'faker'; +import { Connection } from 'typeorm/connection/Connection'; + +import { FactoryFunction } from './types'; +import { isPromiseLike } from './utils'; + +export class EntityFactory { + + private mapFunction: (entity: Entity) => Promise; + + constructor( + public name: string, + public entity: Entity, + private factory: FactoryFunction, + private settings?: Settings + ) { } + + // ------------------------------------------------------------------------- + // Public API + // ------------------------------------------------------------------------- + + public map(mapFunction: (entity: Entity) => Promise): EntityFactory { + this.mapFunction = mapFunction; + return this; + } + + public async make(): Promise { + if (this.factory) { + let entity = await this.resolveEntity(this.factory(Faker, this.settings)); + if (this.mapFunction) { + entity = await this.mapFunction(entity); + } + return entity; + } + throw new Error('Could not found entity'); + } + + public async seed(): Promise { + const connection: Connection = (global as any).seeder.connection; + if (connection) { + const em = connection.createEntityManager(); + try { + const entity = await this.make(); + return await em.save(this.entity, entity); + } catch (error) { + throw new Error('Could not save entity'); + } + } else { + throw new Error('No db connection is given'); + } + } + + public async makeMany(amount: number): Promise { + const list = []; + for (let index = 0; index < amount; index++) { + list[index] = await this.make(); + } + return list; + } + + public async seedMany(amount: number): Promise { + const list = []; + for (let index = 0; index < amount; index++) { + list[index] = await this.seed(); + } + return list; + } + + // ------------------------------------------------------------------------- + // Prrivat Helpers + // ------------------------------------------------------------------------- + + private async resolveEntity(entity: Entity): Promise { + for (const attribute in entity) { + if (entity.hasOwnProperty(attribute)) { + if (isPromiseLike(entity[attribute])) { + entity[attribute] = await entity[attribute]; + } + + if (typeof entity[attribute] === 'object') { + const subEntityFactory = entity[attribute]; + try { + entity[attribute] = await (subEntityFactory as any).make(); + } catch (e) { + throw new Error(`Could not make ${(subEntityFactory as any).name}`); + } + } + } + } + return entity; + } + +} diff --git a/src/lib/seed/cli.ts b/src/lib/seed/cli.ts new file mode 100644 index 00000000..d5961de9 --- /dev/null +++ b/src/lib/seed/cli.ts @@ -0,0 +1,98 @@ +import * as Chalk from 'chalk'; +import * as commander from 'commander'; +import * as path from 'path'; + +import { loadEntityFactories } from './'; +import { getConnection } from './connection'; +import { loadSeeds } from './importer'; +import { runSeeder, setConnection } from './index'; +import { SeedConstructor } from './types'; + +// Cli helper +commander + .version('0.0.0') + .description('Run database seeds of your project') + .option('-L, --logging', 'enable sql query logging') + .option('--factories ', 'add filepath for your factories') + .option('--seeds ', 'add filepath for your seeds') + .option('--list ', 'list seeds to seed', (val) => val.split(',')) + .option('--config ', 'add filepath to your database config (must be a json)') + .parse(process.argv); + +// Get cli parameter for a different factory path +const factoryPath = (commander.factories) + ? commander.factories + : 'src/database/'; + +// Get cli parameter for a different seeds path +const seedsPath = (commander.seeds) + ? commander.seeds + : 'src/database/seeds/'; + +// Get a list of seeds +const listOfSeeds = (commander.list) + ? commander.list.map(l => l.trim()).filter(l => l.length > 0) + : []; + +// Search for seeds and factories +const run = async () => { + const log = console.log; + const chalk = Chalk.default; + + let factoryFiles; + let seedFiles; + try { + factoryFiles = await loadEntityFactories(factoryPath); + seedFiles = await loadSeeds(seedsPath); + } catch (error) { + return handleError(error); + } + + // Filter seeds + if (listOfSeeds.length > 0) { + seedFiles = seedFiles.filter(sf => listOfSeeds.indexOf(path.basename(sf).replace('.ts', '')) >= 0); + } + + // Status logging to print out the amount of factories and seeds. + log(chalk.bold('seeds')); + log('šŸ”Ž ', chalk.gray.underline(`found:`), + chalk.blue.bold(`${factoryFiles.length} factories`, chalk.gray('&'), chalk.blue.bold(`${seedFiles.length} seeds`))); + + // Get database connection and pass it to the seeder + let connection; + try { + connection = await getConnection(); + setConnection(connection); + } catch (error) { + return handleError(error); + } + + // Show seeds in the console + for (const seedFile of seedFiles) { + try { + let className = seedFile.split('/')[seedFile.split('/').length - 1]; + className = className.replace('.ts', '').replace('.js', ''); + className = className.split('-')[className.split('-').length - 1]; + log('\n' + chalk.gray.underline(`executing seed: `), chalk.green.bold(`${className}`)); + const seedFileObject: any = require(seedFile); + await runSeed(seedFileObject[className]); + } catch (error) { + console.error('Could not run seed ', error); + process.exit(1); + } + } + + log('\nšŸ‘ ', chalk.gray.underline(`finished seeding`)); + process.exit(0); +}; + +const handleError = (error) => { + console.error(error); + process.exit(1); +}; + +const runSeed = async (seedClass: SeedConstructor): Promise => { + await runSeeder(seedClass); +}; + +run(); diff --git a/src/lib/seeds/connection.ts b/src/lib/seed/connection.ts similarity index 100% rename from src/lib/seeds/connection.ts rename to src/lib/seed/connection.ts diff --git a/src/lib/seed/importer.ts b/src/lib/seed/importer.ts new file mode 100644 index 00000000..a1f186d4 --- /dev/null +++ b/src/lib/seed/importer.ts @@ -0,0 +1,48 @@ +import * as glob from 'glob'; +import * as path from 'path'; + +// ------------------------------------------------------------------------- +// Util functions +// ------------------------------------------------------------------------- + +const importFactories = (files: string[]) => files.forEach(require); + +const loadFiles = + (filePattern: string) => + (pathToFolder: string) => + (successFn: (files: string[]) => void) => + (failedFn: (error: any) => void) => { + glob(path.join(process.cwd(), pathToFolder, filePattern), (error: any, files: string[]) => { + if (error) { + return failedFn(error); + } + successFn(files); + }); + // error + // ? failedFn(error) + // : successFn(files)); + }; + +const loadFactoryFiles = loadFiles('**/*Factory{.js,.ts}'); + +// ------------------------------------------------------------------------- +// Facade functions +// ------------------------------------------------------------------------- + +export const loadEntityFactories = (pathToFolder: string): Promise => { + return new Promise((resolve, reject) => { + loadFactoryFiles(pathToFolder)(files => { + importFactories(files); + resolve(files); + })(reject); + }); +}; + +export const loadSeeds = (pathToFolder: string): Promise => { + return new Promise((resolve, reject) => { + loadFiles('**/*{.js,.ts}')(pathToFolder)(files => { + // TODO: load seeds + resolve(files); + })(reject); + }); +}; diff --git a/src/lib/seed/index.ts b/src/lib/seed/index.ts new file mode 100644 index 00000000..8aa45f88 --- /dev/null +++ b/src/lib/seed/index.ts @@ -0,0 +1,68 @@ +import 'reflect-metadata'; +import { Connection, ObjectType } from 'typeorm'; + +import { EntityFactory } from './EntityFactory'; +import { EntityFactoryDefinition, FactoryFunction, SeedConstructor } from './types'; +import { getNameOfClass } from './utils'; + +// ------------------------------------------------------------------------- +// Handy Exports +// ------------------------------------------------------------------------- + +export * from './importer'; + +// ------------------------------------------------------------------------- +// Types & Variables +// ------------------------------------------------------------------------- + +(global as any).seeder = { + connection: undefined, + entityFactories: new Map>(), +}; + +// ------------------------------------------------------------------------- +// Util functions +// ------------------------------------------------------------------------- + +// ------------------------------------------------------------------------- +// Facade functions +// ------------------------------------------------------------------------- + +export const setConnection = (connection: Connection) => (global as any).seeder.connection = connection; + +export const getConnection = () => (global as any).seeder.connection; + +export const define = (entity: ObjectType, factoryFn: FactoryFunction) => { + (global as any).seeder.entityFactories.set(getNameOfClass(entity), { entity, factory: factoryFn }); +}; + +export const factory = (entity: any) => (settings?: Settings) => { + const name = getNameOfClass(entity); + const entityFactoryObject = (global as any).seeder.entityFactories.get(name); + return new EntityFactory( + name, + entity, + entityFactoryObject.factory, + settings + ); +}; + +export const seed = async (entityFactory: EntityFactory): Promise => { + const connection: Connection = (global as any).seeder.connection; + if (connection) { + const em = connection.createEntityManager(); + try { + const entity = await entityFactory.make(); + return await em.save(entityFactory.entity, entity); + } catch (error) { + throw new Error('Could not save entity'); + } + } else { + throw new Error('No db connection is given'); + } +}; + +export const runSeeder = async (seederConstructor: SeedConstructor): Promise => { + const seeder = new seederConstructor(); + return seeder.seed(factory, getConnection()); +}; diff --git a/src/lib/seed/make.ts b/src/lib/seed/make.ts new file mode 100644 index 00000000..9f66e96f --- /dev/null +++ b/src/lib/seed/make.ts @@ -0,0 +1,31 @@ +import * as Faker from 'faker'; + +import { EntityFactoryDefinition } from './types'; +import { isPromiseLike } from './utils'; + +const resolveEntity = async (entity: E): Promise => { + for (const attribute in entity) { + if (entity.hasOwnProperty(attribute)) { + if (isPromiseLike(entity[attribute])) { + entity[attribute] = await entity[attribute]; + } + + if (typeof entity[attribute] === 'object') { + const subEntityFactory = entity[attribute]; + try { + entity[attribute] = await (subEntityFactory as any).make(); + } catch (e) { + throw new Error(`Could not make ${(subEntityFactory as any).name}`); + } + } + } + } + return entity; +}; + +export const make = (entityFactoryDefinition: EntityFactoryDefinition) => (settings?: Settings) => () => { + if (entityFactoryDefinition) { + return resolveEntity(entityFactoryDefinition.factory(Faker, settings)); + } + throw new Error('Could not found entity'); +}; diff --git a/src/lib/seed/types.ts b/src/lib/seed/types.ts new file mode 100644 index 00000000..93768e7d --- /dev/null +++ b/src/lib/seed/types.ts @@ -0,0 +1,21 @@ +import * as Faker from 'faker'; +import { Connection, ObjectType } from 'typeorm'; + +import { EntityFactory } from './EntityFactory'; + +export type FactoryFunction = (faker: typeof Faker, settings?: Settings) => Entity; + +export type Factory = (entity: Entity) => (settings?: Settings) => EntityFactory; + +export interface EntityFactoryDefinition { + entity: ObjectType; + factory: FactoryFunction; +} + +export interface Seed { + seed(factory: Factory, connection: Connection): Promise; +} + +export interface SeedConstructor { + new(): Seed; +} diff --git a/src/lib/seed/utils.ts b/src/lib/seed/utils.ts new file mode 100644 index 00000000..c5908d22 --- /dev/null +++ b/src/lib/seed/utils.ts @@ -0,0 +1,7 @@ +// ------------------------------------------------------------------------- +// Util functions +// ------------------------------------------------------------------------- + +export const getNameOfClass = (c: any): string => new c().constructor.name; + +export const isPromiseLike = (o: any): boolean => !!o && (typeof o === 'object' || typeof o === 'function') && typeof o.then === 'function'; diff --git a/src/lib/seeds/BluePrint.ts b/src/lib/seeds/BluePrint.ts deleted file mode 100644 index 4fc496b5..00000000 --- a/src/lib/seeds/BluePrint.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as Faker from 'faker'; -import { ObjectType } from 'typeorm'; - -/** - * BluePrint has the factory function for the given EntityClass - */ -export class BluePrint { - constructor( - public EntityClass: ObjectType, - public create: (faker: typeof Faker, args: any[]) => Entity) { } -} diff --git a/src/lib/seeds/EntityFactory.ts b/src/lib/seeds/EntityFactory.ts deleted file mode 100644 index 66a852b2..00000000 --- a/src/lib/seeds/EntityFactory.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as Faker from 'faker'; -import { Connection } from 'typeorm/connection/Connection'; - -import { BluePrint } from './BluePrint'; -import { EntityFactoryInterface } from './EntityFactoryInterface'; - -export class EntityFactory implements EntityFactoryInterface { - - private identifier = 'id'; - private eachFn: (obj: any, faker: typeof Faker) => Promise; - - constructor( - private faker: typeof Faker, - private connection: Connection, - private blueprint: BluePrint, - private args: any[]) { } - - public each(iterator: (entity: Entity, faker: typeof Faker) => Promise): EntityFactory { - this.eachFn = iterator; - return this; - } - - public async make(): Promise { - return await this.makeEntity(this.blueprint.create(this.faker, this.args)); - } - - public async makeMany(amount: number): Promise { - const results: Entity[] = []; - for (let i = 0; i < amount; i++) { - const entity = await this.makeEntity(this.blueprint.create(this.faker, this.args)); - if (entity) { - results.push(entity); - } - } - return results; - } - - public async create(): Promise { - const entity = await this.build(); - if (typeof this.eachFn === 'function') { - await this.eachFn(entity, this.faker); - } - return entity; - } - - public async createMany(amount: number): Promise { - const results: Entity[] = []; - for (let i = 0; i < amount; i++) { - const entity = await this.create(); - if (entity) { - results.push(entity); - } - } - return results; - } - - private async build(): Promise { - if (this.connection) { - const entity = await this.make(); - const em = this.connection.createEntityManager(); - try { - return await em.save(this.blueprint.EntityClass, entity); - } catch (error) { - console.error('saving entity failed', error); - return; - } - } - return; - } - - private async makeEntity(entity: Entity): Promise { - for (const attribute in entity) { - if (entity.hasOwnProperty(attribute)) { - if (this.isPromiseLike(entity[attribute])) { - entity[attribute] = await entity[attribute]; - } - - if (typeof entity[attribute] === 'object' && entity[attribute] instanceof EntityFactory) { - const subEntityFactory = entity[attribute]; - const subEntity = await (subEntityFactory as any).build(); - entity[attribute] = subEntity[this.identifier]; - } - } - } - return entity; - } - - private isPromiseLike(object: any): boolean { - return !!object && (typeof object === 'object' || typeof object === 'function') && typeof object.then === 'function'; - } -} diff --git a/src/lib/seeds/EntityFactoryInterface.ts b/src/lib/seeds/EntityFactoryInterface.ts deleted file mode 100644 index 61d9954c..00000000 --- a/src/lib/seeds/EntityFactoryInterface.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as Faker from 'faker'; - -/** - * EntityFactoryInterface is the one we use in our seed files. - * This will be returne of the main factory's get method. - */ -export interface EntityFactoryInterface { - /** - * Creates a entity with faked data, but not persisted to the database. - */ - make(): Promise; - makeMany(amount: number): Promise; - /** - * Creates a new faked entity in the database. - */ - create(): Promise; - createMany(amount: number): Promise; - /** - * This is called after creating a enity to the database. Use this to - * create other seeds but combined with this enitiy. - */ - each(iterator: (entity: Entity, faker: typeof Faker) => Promise): EntityFactoryInterface; -} diff --git a/src/lib/seeds/Factory.ts b/src/lib/seeds/Factory.ts deleted file mode 100644 index 2e4d8144..00000000 --- a/src/lib/seeds/Factory.ts +++ /dev/null @@ -1,58 +0,0 @@ -import * as Faker from 'faker'; -import { ObjectType } from 'typeorm'; -import { Connection } from 'typeorm/connection/Connection'; - -import { BluePrint } from './BluePrint'; -import { EntityFactory } from './EntityFactory'; -import { FactoryInterface } from './FactoryInterface'; -import { SeedsConstructorInterface } from './SeedsInterface'; - -export class Factory implements FactoryInterface { - - public static getInstance(): Factory { - if (!Factory.instance) { - Factory.instance = new Factory(Faker); - } - return Factory.instance; - } - - private static instance: Factory; - - private connection: Connection; - private blueprints: { [key: string]: BluePrint }; - - constructor(private faker: typeof Faker) { - this.blueprints = {}; - } - - public getConnection(): Connection { - return this.connection; - } - - public setConnection(connection: Connection): void { - this.connection = connection; - } - - public async runSeed(seedClass: SeedsConstructorInterface): Promise { - const seeder = new seedClass(); - return await seeder.seed(this); - } - - public define(entityClass: ObjectType, callback: (faker: typeof Faker, args: any[]) => Entity): void { - this.blueprints[this.getNameOfEntity(entityClass)] = new BluePrint(entityClass, callback); - } - - public get(entityClass: ObjectType, ...args: any[]): EntityFactory { - return new EntityFactory( - this.faker, - this.connection, - this.blueprints[this.getNameOfEntity(entityClass)], - args - ); - } - - private getNameOfEntity(EntityClass: any): string { - return new EntityClass().constructor.name; - } - -} diff --git a/src/lib/seeds/FactoryInterface.ts b/src/lib/seeds/FactoryInterface.ts deleted file mode 100644 index 435677c1..00000000 --- a/src/lib/seeds/FactoryInterface.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as Faker from 'faker'; -import { SeedsConstructorInterface } from 'src/lib/seeds'; -import { ObjectType } from 'typeorm'; -import { Connection } from 'typeorm/connection/Connection'; - -import { EntityFactoryInterface } from './EntityFactoryInterface'; - -/** - * This interface is used to define new entity faker factories or to get such a - * entity faker factory to start seeding. - */ -export interface FactoryInterface { - /** - * Returns a typeorm database connection. - */ - getConnection(): Connection; - /** - * Sets the typeorm database connection. - */ - setConnection(connection: Connection): void; - /** - * Runs the given seed class - */ - runSeed(seedClass: SeedsConstructorInterface): Promise; - /** - * Returns an EntityFactoryInterface - */ - get(entityClass: ObjectType, value?: any): EntityFactoryInterface; - /** - * Define an entity faker - */ - define(entityClass: ObjectType, fakerFunction: (faker: typeof Faker, value?: any) => Entity): void; -} diff --git a/src/lib/seeds/SeedsInterface.ts b/src/lib/seeds/SeedsInterface.ts deleted file mode 100644 index b5efa458..00000000 --- a/src/lib/seeds/SeedsInterface.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Factory } from './Factory'; - -/** - * Seeds should implement this interface and all its methods. - */ -export interface SeedsInterface { - /** - * Seed data into the databas. - */ - seed(factory: Factory): Promise; -} - -export interface SeedsConstructorInterface { - new(): SeedsInterface; -} diff --git a/src/lib/seeds/cli.ts b/src/lib/seeds/cli.ts deleted file mode 100644 index 44a71015..00000000 --- a/src/lib/seeds/cli.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as Chalk from 'chalk'; -import * as commander from 'commander'; -import * as glob from 'glob'; -import * as path from 'path'; -import 'reflect-metadata'; -import { Connection } from 'typeorm'; - -import { getConnection } from './connection'; -import { Factory } from './Factory'; - -// Get executiuon path to look from there for seeds and factories -const runDir = process.cwd(); - -// Cli helper -commander - .version('0.0.0') - .description('Run database seeds of your project') - .option('-L, --logging', 'enable sql query logging') - .option('--factories ', 'add filepath for your factories') - .option('--seeds ', 'add filepath for your seeds') - .option('--config ', 'add filepath to your database config (must be a json)') - .parse(process.argv); - -// Get cli parameter for a different factory path -const factoryPath = (commander.factories) - ? commander.factories - : 'src/database/'; - -// Get cli parameter for a different seeds path -const seedsPath = (commander.seeds) - ? commander.seeds - : 'src/database/seeds/'; - -// Search for seeds and factories -glob(path.join(runDir, factoryPath, '**/*Factory{.js,.ts}'), (errFactories: any, factories: string[]) => { - glob(path.join(runDir, seedsPath, '*{.js,.ts}'), (errSeeds: any, seeds: string[]) => { - const log = console.log; - const chalk = Chalk.default; - - // Status logging to print out the amount of factories and seeds. - log(chalk.bold('seeds')); - log('šŸ”Ž ', chalk.gray.underline(`found:`), - chalk.blue.bold(`${factories.length} factories`, chalk.gray('&'), chalk.blue.bold(`${seeds.length} seeds`))); - - // Initialize all factories - for (const factory of factories) { - require(factory); - } - - // Get typeorm database connection and pass them to the factory instance - getConnection().then((connection: Connection) => { - const factory = Factory.getInstance(); - factory.setConnection(connection); - - // Initialize and seed all seeds. - const queue: Array> = []; - for (const seed of seeds) { - try { - const seedFile: any = require(seed); - let className = seed.split('/')[seed.split('/').length - 1]; - className = className.replace('.ts', '').replace('.js', ''); - className = className.split('-')[className.split('-').length - 1]; - log('\n' + chalk.gray.underline(`executing seed: `), chalk.green.bold(`${className}`)); - queue.push((new seedFile[className]()).seed(factory)); - } catch (error) { - console.error('Could not run seed ' + seed, error); - } - } - - // Promise to catch the end for termination and logging - Promise - .all(queue) - .then(() => { - log('\nšŸ‘ ', chalk.gray.underline(`finished seeding`)); - process.exit(0); - }) - .catch((error) => { - console.error('Could not run seed ' + error); - process.exit(1); - }); - - }).catch((error) => { - console.error('Could not connection to database ' + error); - process.exit(1); - }); - }); -}); diff --git a/src/lib/seeds/index.ts b/src/lib/seeds/index.ts deleted file mode 100644 index 97fa23d1..00000000 --- a/src/lib/seeds/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import 'reflect-metadata'; -import { Connection } from 'typeorm'; - -import { Factory } from './Factory'; - -// ------------------------------------------------------------------------- -// Handy Exports -// ------------------------------------------------------------------------- - -export * from './FactoryInterface'; -export * from './EntityFactoryInterface'; -export * from './SeedsInterface'; -export * from './Factory'; -export * from './utils'; - -// ------------------------------------------------------------------------- -// Facade functions -// ------------------------------------------------------------------------- - -export const getFactory = (connection: Connection) => { - const factory = Factory.getInstance(); - factory.setConnection(connection); - return factory; -}; diff --git a/src/lib/seeds/utils.ts b/src/lib/seeds/utils.ts deleted file mode 100644 index 5106607e..00000000 --- a/src/lib/seeds/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Times repeats a function n times - * @param n amount of loops - * @param iteratee this function gets n-times called - */ -export const times = async (n: number, iteratee: (index: number) => Promise): Promise => { - const rs = [] as TResult[]; - for (let i = 0; i < n; i++) { - const r = await iteratee(i); - rs.push(r); - } - return rs; -}; diff --git a/test/e2e/api/users.test.ts b/test/e2e/api/users.test.ts index 115b56a3..1290b549 100644 --- a/test/e2e/api/users.test.ts +++ b/test/e2e/api/users.test.ts @@ -3,34 +3,35 @@ import * as request from 'supertest'; import { User } from '../../../src/api/models/User'; import { CreateBruce } from '../../../src/database/seeds/CreateBruce'; -import { Factory } from '../../../src/lib/seeds/Factory'; -import { getFactory } from '../../../src/lib/seeds/index'; -import { closeDatabase, migrateDatabase } from '../../utils/database'; +import { runSeeder } from '../../../src/lib/seed'; +import { closeDatabase } from '../../utils/database'; import { fakeAuthenticationForUser } from '../utils/auth'; -import { bootstrapApp, BootstrapSettings } from '../utils/bootstrap'; +import { BootstrapSettings } from '../utils/bootstrap'; +import { prepareServer } from '../utils/server'; describe('/api/users', () => { + let bruce: User; + let settings: BootstrapSettings; + // ------------------------------------------------------------------------- // Setup up // ------------------------------------------------------------------------- - let settings: BootstrapSettings; - let factory: Factory; - let bruce: User; - let authServer: nock.Scope; - beforeAll(async () => settings = await bootstrapApp()); - beforeAll(async () => migrateDatabase(settings.connection)); - beforeAll(async () => factory = getFactory(settings.connection)); - beforeAll(async () => bruce = await factory.runSeed(CreateBruce)); - beforeAll(async () => authServer = fakeAuthenticationForUser(bruce, true)); + beforeAll(async () => { + settings = await prepareServer({ migrate: true }); + bruce = await runSeeder(CreateBruce); + fakeAuthenticationForUser(bruce, true); + }); // ------------------------------------------------------------------------- // Tear down // ------------------------------------------------------------------------- - afterAll(() => nock.cleanAll()); - afterAll(async () => closeDatabase(settings.connection)); + afterAll(async () => { + nock.cleanAll(); + await closeDatabase(settings.connection); + }); // ------------------------------------------------------------------------- // Test cases diff --git a/test/e2e/utils/server.ts b/test/e2e/utils/server.ts new file mode 100644 index 00000000..2150ebcb --- /dev/null +++ b/test/e2e/utils/server.ts @@ -0,0 +1,12 @@ +import { setConnection } from '../../../src/lib/seed'; +import { migrateDatabase } from '../../utils/database'; +import { bootstrapApp } from './bootstrap'; + +export const prepareServer = async (options?: { migrate: boolean }) => { + const settings = await bootstrapApp(); + if (options && options.migrate) { + await migrateDatabase(settings.connection); + } + setConnection(settings.connection); + return settings; +}; diff --git a/yarn.lock b/yarn.lock index 2271b4b5..d761d047 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,8 +101,8 @@ "@types/node" "*" "@types/node@*": - version "9.4.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.6.tgz#d8176d864ee48753d053783e4e463aec86b8d82e" + version "9.4.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.7.tgz#57d81cd98719df2c9de118f2d5f3b1120dcd7275" "@types/reflect-metadata@0.0.5": version "0.0.5" @@ -252,12 +252,18 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0, ansi-styles@^3.2.0: +ansi-styles@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" dependencies: color-convert "^1.9.0" +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -302,8 +308,8 @@ are-we-there-yet@~1.1.2: readable-stream "^2.0.6" argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" @@ -557,7 +563,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: +babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -866,12 +872,12 @@ chalk@^1.1.1, chalk@^1.1.3: supports-color "^2.0.0" chalk@^2.0.1, chalk@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" + version "2.3.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: - ansi-styles "^3.2.0" + ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" - supports-color "^5.2.0" + supports-color "^5.3.0" check-error@^1.0.1: version "1.0.2" @@ -914,9 +920,9 @@ ci-info@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" -class-transformer@~0.1.6: - version "0.1.8" - resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.1.8.tgz#be04dd2afb7b301e4c8c79c5349fedaac3d5a7e1" +class-transformer@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.1.9.tgz#29977c528233ca014e6fd9523327ebd31d11ca54" class-utils@^0.3.5: version "0.3.6" @@ -927,12 +933,18 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -class-validator@^0.7.0, class-validator@^0.7.3: +class-validator@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.7.3.tgz#3c2821b8cf35fd8d5f4fcb8063bc57fb50049e7e" dependencies: validator "^7.0.0" +class-validator@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.8.1.tgz#f5efd5c613927e3c2f68692e8f14d53a2644fb2f" + dependencies: + validator "9.2.0" + cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" @@ -1015,18 +1027,18 @@ commander@2.6.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" commander@^2.11.0: - version "2.14.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + version "2.15.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.0.tgz#ad2a23a1c3b036e392469b8012cec6b33b4c1322" commander@^2.12.1: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" common-tags@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" + version "1.7.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771" dependencies: - babel-runtime "^6.18.0" + babel-runtime "^6.26.0" component-bind@1.0.0: version "1.0.0" @@ -1141,7 +1153,11 @@ copyfiles@^1.2.0: noms "0.0.0" through2 "^2.0.1" -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.4.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + +core-js@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" @@ -1216,8 +1232,8 @@ cross-env@^3.1.4: is-windows "^1.0.0" cross-env@^5.1.1: - version "5.1.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.3.tgz#f8ae18faac87692b0a8b4d2f7000d4ec3a85dfd7" + version "5.1.4" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.4.tgz#f61c14291f7cc653bb86457002ea80a04699d022" dependencies: cross-spawn "^5.1.0" is-windows "^1.0.0" @@ -2142,8 +2158,8 @@ helmet-csp@2.7.0: platform "1.3.5" helmet@^3.9.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.11.0.tgz#5eacccc0b5b61d786e29aa3fc5650abf73e1824f" + version "3.12.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.12.0.tgz#2098e35cf4e51c64c2f1d38670b7d382a377d92c" dependencies: dns-prefetch-control "0.1.0" dont-sniff-mimetype "1.0.0" @@ -2156,7 +2172,7 @@ helmet@^3.9.0: ienoopen "1.0.0" nocache "2.0.0" referrer-policy "1.1.0" - x-xss-protection "1.0.0" + x-xss-protection "1.1.0" hide-powered-by@1.0.0: version "1.0.0" @@ -2188,8 +2204,8 @@ homedir-polyfill@^1.0.1: parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + version "2.6.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" hpkp@2.0.0: version "2.0.0" @@ -2502,11 +2518,7 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" -is-windows@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" - -is-windows@^1.0.2: +is-windows@^1.0.0, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -2836,13 +2848,20 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.7.0, js-yaml@^3.8.4, js-yaml@^3.9.0: +js-yaml@^3.7.0: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.8.4, js-yaml@^3.9.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -2995,26 +3014,10 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash.endswith@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09" - -lodash.isfunction@^3.0.8: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - lodash.reduce@4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" -lodash.startswith@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.startswith/-/lodash.startswith-4.2.1.tgz#c598c4adce188a27e53145731cdc6c0e7177600c" - lodash@^4.14.0, lodash@^4.5.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3045,8 +3048,8 @@ lowercase-keys@^1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + version "4.1.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -3354,8 +3357,8 @@ nocache@2.0.0: resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" nock@^9.1.4: - version "9.2.1" - resolved "https://registry.yarnpkg.com/nock/-/nock-9.2.1.tgz#7e73561277c3e8f2287e385d3d04c7223a54faea" + version "9.2.3" + resolved "https://registry.yarnpkg.com/nock/-/nock-9.2.3.tgz#39738087d6a0497d3a165fb352612b38a2f9b92f" dependencies: chai "^4.1.2" debug "^3.1.0" @@ -3397,17 +3400,18 @@ node-pre-gyp@^0.6.39, node-pre-gyp@~0.6.38: tar-pack "^3.4.0" nodemon@^1.12.1: - version "1.15.1" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.15.1.tgz#54daa72443d8d5a548f130866b92e65cded0ed58" + version "1.17.1" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.17.1.tgz#cdb4bc53d7a86d6162143a1a44d7adf927d8652f" dependencies: chokidar "^2.0.2" debug "^3.1.0" ignore-by-default "^1.0.1" minimatch "^3.0.4" pstree.remy "^1.1.0" - semver "^5.4.1" + semver "^5.5.0" + supports-color "^5.2.0" touch "^3.1.0" - undefsafe "^2.0.1" + undefsafe "^2.0.2" update-notifier "^2.3.0" noms@0.0.0: @@ -3476,8 +3480,8 @@ nps-utils@^1.5.0: rimraf "^2.6.1" nps@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/nps/-/nps-5.7.1.tgz#12cbfc635a6535ccb4f6eb516e6011f3af6bef42" + version "5.8.1" + resolved "https://registry.yarnpkg.com/nps/-/nps-5.8.1.tgz#180ca887a3bf8abdb860fb972d135310260580bb" dependencies: arrify "^1.0.1" chalk "^2.0.1" @@ -3969,8 +3973,8 @@ readable-stream@2.3.3, readable-stream@^2.0.5, readable-stream@^2.1.5: util-deprecate "~1.0.1" readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071" + version "2.3.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -3999,8 +4003,8 @@ readdirp@^2.0.0: set-immediate-shim "^1.0.1" readline-sync@^1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.7.tgz#001bfdd4c06110c3c084c63bf7c6a56022213f30" + version "1.4.9" + resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.9.tgz#3eda8e65f23cd2a17e61301b1f0003396af5ecda" redent@^1.0.0: version "1.0.0" @@ -4013,7 +4017,7 @@ referrer-policy@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" -reflect-metadata@^0.1.10: +reflect-metadata@^0.1.10, reflect-metadata@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" @@ -4158,14 +4162,14 @@ rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: glob "^7.0.5" routing-controllers@^0.7.6: - version "0.7.6" - resolved "https://registry.yarnpkg.com/routing-controllers/-/routing-controllers-0.7.6.tgz#f025b6b1f011fb5973e94db4ffde86da8d48091e" + version "0.7.7" + resolved "https://registry.yarnpkg.com/routing-controllers/-/routing-controllers-0.7.7.tgz#55b3dd3e676ade2527e522aad2834ac891cce0ee" dependencies: - class-transformer "~0.1.6" - class-validator "^0.7.0" + class-transformer "^0.1.9" + class-validator "^0.8.1" cookie "^0.3.1" glob "^7.0.5" - reflect-metadata "^0.1.10" + reflect-metadata "^0.1.12" template-url "^1.0.0" rx@2.3.24: @@ -4206,7 +4210,7 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" -"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -4446,22 +4450,30 @@ spawn-command-with-kill@^1.0.0: spawn-command "^0.0.2-1" spawn-command@^0.0.2-1: - version "0.0.2" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + version "0.0.2-1" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" dependencies: - spdx-license-ids "^1.0.2" + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -4659,9 +4671,9 @@ supports-color@^4.0.0: dependencies: has-flag "^2.0.0" -supports-color@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a" +supports-color@^5.2.0, supports-color@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" dependencies: has-flag "^3.0.0" @@ -4796,12 +4808,18 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3: +tough-cookie@^2.3.2, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" +tough-cookie@~2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -4898,14 +4916,10 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@^4.0.0: +type-detect@^4.0.0, type-detect@^4.0.3: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" -type-detect@^4.0.3: - version "4.0.5" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.5.tgz#d70e5bc81db6de2a381bcaca0c6e0cbdc7635de2" - type-is@^1.6.15, type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" @@ -4922,8 +4936,8 @@ typeorm-typedi-extensions@^0.1.1: resolved "https://registry.yarnpkg.com/typeorm-typedi-extensions/-/typeorm-typedi-extensions-0.1.1.tgz#e99a66dcf501fbd5837cf2f7a3dc75e13de89734" typeorm@^0.1.3: - version "0.1.12" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.1.12.tgz#adcd45f302d21ab4d5b02671bfa8c07cea044af7" + version "0.1.16" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.1.16.tgz#52a9251f4394c07ce1f4e14d2c8b6cfca89535fc" dependencies: app-root-path "^2.0.1" chalk "^2.0.1" @@ -4963,7 +4977,7 @@ ultron@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864" -undefsafe@^2.0.1: +undefsafe@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" dependencies: @@ -5004,13 +5018,8 @@ unzip-response@^2.0.1: resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" upath@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.2.tgz#80aaae5395abc5fd402933ae2f58694f0860204c" - dependencies: - lodash.endswith "^4.2.1" - lodash.isfunction "^3.0.8" - lodash.isstring "^4.0.1" - lodash.startswith "^4.2.1" + version "1.0.4" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" update-notifier@^2.3.0: version "2.3.0" @@ -5077,11 +5086,15 @@ v8flags@^3.0.0: homedir-polyfill "^1.0.1" validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validator@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-9.2.0.tgz#ad216eed5f37cac31a6fe00ceab1f6b88bded03e" validator@^7.0.0: version "7.2.0" @@ -5216,9 +5229,9 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" -x-xss-protection@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.0.0.tgz#898afb93869b24661cf9c52f9ee8db8ed0764dd9" +x-xss-protection@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.1.0.tgz#4f1898c332deb1e7f2be1280efb3e2c53d69c1a7" xdg-basedir@^3.0.0: version "3.0.0" @@ -5236,8 +5249,8 @@ xml2js@^0.4.17: xmlbuilder "~9.0.1" xmlbuilder@~9.0.1: - version "9.0.4" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" xmlhttprequest-ssl@~1.5.4: version "1.5.4" From 43847b027be1e2a64a8bb9a3e2c21386bf4b9142 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sun, 11 Mar 2018 17:50:04 +0100 Subject: [PATCH 02/14] refactor the new seed --- src/database/seeds/CreatePets.ts | 20 +++++++------- src/database/seeds/CreateUsers.ts | 7 +++-- src/lib/seed/EntityFactory.ts | 13 +++++++++ src/lib/seed/cli.ts | 9 ++----- src/lib/seed/importer.ts | 17 +++--------- src/lib/seed/index.ts | 45 ++++++++++++++++--------------- src/lib/seed/make.ts | 31 --------------------- src/lib/seed/types.ts | 25 +++++++++++++---- src/lib/seed/utils.ts | 22 ++++++++++++--- 9 files changed, 93 insertions(+), 96 deletions(-) delete mode 100644 src/lib/seed/make.ts diff --git a/src/database/seeds/CreatePets.ts b/src/database/seeds/CreatePets.ts index 823b87ab..c066a4e1 100644 --- a/src/database/seeds/CreatePets.ts +++ b/src/database/seeds/CreatePets.ts @@ -1,23 +1,23 @@ import { Connection } from 'typeorm'; -import { Factory, Seed } from '../../lib/seed/types'; +import { Pet } from '../../../src/api/models/Pet'; +import { User } from '../../../src/api/models/User'; +import { Factory, Seed, times } from '../../lib/seed'; -// import { Pet } from '../../../src/api/models/Pet'; -// import { User } from '../../../src/api/models/User'; export class CreatePets implements Seed { public async seed(factory: Factory, connection: Connection): Promise { console.log('CreatePets'); // const connection = await factory.getConnection(); - // const em = connection.createEntityManager(); + const em = connection.createEntityManager(); - // await times(10, async (n) => { - // const pet = await factory.get(Pet).create(); - // const user = await factory.get(User).make(); - // user.pets = [pet]; - // await em.save(user); - // }); + await times(10, async (n) => { + const pet = await factory(Pet as any)().seed(); + const user = await factory(User as any)().make(); + user.pets = [pet]; + await em.save(user); + }); } } diff --git a/src/database/seeds/CreateUsers.ts b/src/database/seeds/CreateUsers.ts index a50097b1..62747b1b 100644 --- a/src/database/seeds/CreateUsers.ts +++ b/src/database/seeds/CreateUsers.ts @@ -1,16 +1,15 @@ import { Connection } from 'typeorm/connection/Connection'; +import { User } from '../../../src/api/models/User'; import { Factory, Seed } from '../../lib/seed/types'; -// import { User } from '../../../src/api/models/User'; export class CreateUsers implements Seed { public async seed(factory: Factory, connection: Connection): Promise { console.log('CreateUsers'); - // await factory - // .get(User) - // .createMany(10); + await factory(User)() + .seedMany(10); } } diff --git a/src/lib/seed/EntityFactory.ts b/src/lib/seed/EntityFactory.ts index 9afb234b..facd5bc4 100644 --- a/src/lib/seed/EntityFactory.ts +++ b/src/lib/seed/EntityFactory.ts @@ -4,6 +4,9 @@ import { Connection } from 'typeorm/connection/Connection'; import { FactoryFunction } from './types'; import { isPromiseLike } from './utils'; +/** + * EntityFactory ... + */ export class EntityFactory { private mapFunction: (entity: Entity) => Promise; @@ -19,11 +22,18 @@ export class EntityFactory { // Public API // ------------------------------------------------------------------------- + /** + * This fucntion is used to alter the generated values of entity, before it + * is persist into the database + */ public map(mapFunction: (entity: Entity) => Promise): EntityFactory { this.mapFunction = mapFunction; return this; } + /** + * Make generate a new entity, but does not persist it + */ public async make(): Promise { if (this.factory) { let entity = await this.resolveEntity(this.factory(Faker, this.settings)); @@ -35,6 +45,9 @@ export class EntityFactory { throw new Error('Could not found entity'); } + /** + * Seed persist and generates a given entity + */ public async seed(): Promise { const connection: Connection = (global as any).seeder.connection; if (connection) { diff --git a/src/lib/seed/cli.ts b/src/lib/seed/cli.ts index d5961de9..2c58a812 100644 --- a/src/lib/seed/cli.ts +++ b/src/lib/seed/cli.ts @@ -5,12 +5,11 @@ import * as path from 'path'; import { loadEntityFactories } from './'; import { getConnection } from './connection'; import { loadSeeds } from './importer'; -import { runSeeder, setConnection } from './index'; -import { SeedConstructor } from './types'; +import { runSeed, setConnection } from './index'; // Cli helper commander - .version('0.0.0') + .version('1.0.0') .description('Run database seeds of your project') .option('-L, --logging', 'enable sql query logging') .option('--factories ', 'add filepath for your factories') @@ -91,8 +90,4 @@ const handleError = (error) => { process.exit(1); }; -const runSeed = async (seedClass: SeedConstructor): Promise => { - await runSeeder(seedClass); -}; - run(); diff --git a/src/lib/seed/importer.ts b/src/lib/seed/importer.ts index a1f186d4..8d188785 100644 --- a/src/lib/seed/importer.ts +++ b/src/lib/seed/importer.ts @@ -12,15 +12,9 @@ const loadFiles = (pathToFolder: string) => (successFn: (files: string[]) => void) => (failedFn: (error: any) => void) => { - glob(path.join(process.cwd(), pathToFolder, filePattern), (error: any, files: string[]) => { - if (error) { - return failedFn(error); - } - successFn(files); - }); - // error - // ? failedFn(error) - // : successFn(files)); + glob(path.join(process.cwd(), pathToFolder, filePattern), (error: any, files: string[]) => error + ? failedFn(error) + : successFn(files)); }; const loadFactoryFiles = loadFiles('**/*Factory{.js,.ts}'); @@ -40,9 +34,6 @@ export const loadEntityFactories = (pathToFolder: string): Promise => export const loadSeeds = (pathToFolder: string): Promise => { return new Promise((resolve, reject) => { - loadFiles('**/*{.js,.ts}')(pathToFolder)(files => { - // TODO: load seeds - resolve(files); - })(reject); + loadFiles('**/*{.js,.ts}')(pathToFolder)(resolve)(reject); }); }; diff --git a/src/lib/seed/index.ts b/src/lib/seed/index.ts index 8aa45f88..61f3b4e7 100644 --- a/src/lib/seed/index.ts +++ b/src/lib/seed/index.ts @@ -2,7 +2,9 @@ import 'reflect-metadata'; import { Connection, ObjectType } from 'typeorm'; import { EntityFactory } from './EntityFactory'; -import { EntityFactoryDefinition, FactoryFunction, SeedConstructor } from './types'; +import { + EntityConstructor, EntityFactoryDefinition, FactoryFunction, SeedConstructor +} from './types'; import { getNameOfClass } from './utils'; // ------------------------------------------------------------------------- @@ -10,6 +12,8 @@ import { getNameOfClass } from './utils'; // ------------------------------------------------------------------------- export * from './importer'; +export { Factory, Seed } from './types'; +export { times } from './utils'; // ------------------------------------------------------------------------- // Types & Variables @@ -20,23 +24,32 @@ export * from './importer'; entityFactories: new Map>(), }; -// ------------------------------------------------------------------------- -// Util functions -// ------------------------------------------------------------------------- - // ------------------------------------------------------------------------- // Facade functions // ------------------------------------------------------------------------- +/** + * Adds the typorm connection to the seed options + */ export const setConnection = (connection: Connection) => (global as any).seeder.connection = connection; +/** + * Returns the typorm connection from our seed options + */ export const getConnection = () => (global as any).seeder.connection; +/** + * Defines a new entity factory + */ export const define = (entity: ObjectType, factoryFn: FactoryFunction) => { (global as any).seeder.entityFactories.set(getNameOfClass(entity), { entity, factory: factoryFn }); }; -export const factory = (entity: any) => (settings?: Settings) => { + +/** + * Gets a defined entity factory and pass the settigns along to the entity factory function + */ +export const factory = (entity: EntityConstructor) => (settings?: Settings) => { const name = getNameOfClass(entity); const entityFactoryObject = (global as any).seeder.entityFactories.get(name); return new EntityFactory( @@ -47,22 +60,10 @@ export const factory = (entity: any) => (settings?: Settings) ); }; -export const seed = async (entityFactory: EntityFactory): Promise => { - const connection: Connection = (global as any).seeder.connection; - if (connection) { - const em = connection.createEntityManager(); - try { - const entity = await entityFactory.make(); - return await em.save(entityFactory.entity, entity); - } catch (error) { - throw new Error('Could not save entity'); - } - } else { - throw new Error('No db connection is given'); - } -}; - -export const runSeeder = async (seederConstructor: SeedConstructor): Promise => { +/** + * Runs a seed class + */ +export const runSeed = async (seederConstructor: SeedConstructor): Promise => { const seeder = new seederConstructor(); return seeder.seed(factory, getConnection()); }; diff --git a/src/lib/seed/make.ts b/src/lib/seed/make.ts deleted file mode 100644 index 9f66e96f..00000000 --- a/src/lib/seed/make.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as Faker from 'faker'; - -import { EntityFactoryDefinition } from './types'; -import { isPromiseLike } from './utils'; - -const resolveEntity = async (entity: E): Promise => { - for (const attribute in entity) { - if (entity.hasOwnProperty(attribute)) { - if (isPromiseLike(entity[attribute])) { - entity[attribute] = await entity[attribute]; - } - - if (typeof entity[attribute] === 'object') { - const subEntityFactory = entity[attribute]; - try { - entity[attribute] = await (subEntityFactory as any).make(); - } catch (e) { - throw new Error(`Could not make ${(subEntityFactory as any).name}`); - } - } - } - } - return entity; -}; - -export const make = (entityFactoryDefinition: EntityFactoryDefinition) => (settings?: Settings) => () => { - if (entityFactoryDefinition) { - return resolveEntity(entityFactoryDefinition.factory(Faker, settings)); - } - throw new Error('Could not found entity'); -}; diff --git a/src/lib/seed/types.ts b/src/lib/seed/types.ts index 93768e7d..c931bbe4 100644 --- a/src/lib/seed/types.ts +++ b/src/lib/seed/types.ts @@ -3,19 +3,34 @@ import { Connection, ObjectType } from 'typeorm'; import { EntityFactory } from './EntityFactory'; +/** + * FactoryFunction is the fucntion, which generate a new filled entity + */ export type FactoryFunction = (faker: typeof Faker, settings?: Settings) => Entity; +/** + * Factory gets the EntityFactory to the given Entity and pass the settings along + */ export type Factory = (entity: Entity) => (settings?: Settings) => EntityFactory; -export interface EntityFactoryDefinition { - entity: ObjectType; - factory: FactoryFunction; -} - +/** + * Seed are the class to create some data. Those seed are run by the cli. + */ export interface Seed { seed(factory: Factory, connection: Connection): Promise; } +/** + * Constructor of the seed class + */ export interface SeedConstructor { new(): Seed; } + +/** + * Value of our EntityFactory state + */ +export interface EntityFactoryDefinition { + entity: ObjectType; + factory: FactoryFunction; +} diff --git a/src/lib/seed/utils.ts b/src/lib/seed/utils.ts index c5908d22..88b05037 100644 --- a/src/lib/seed/utils.ts +++ b/src/lib/seed/utils.ts @@ -1,7 +1,21 @@ -// ------------------------------------------------------------------------- -// Util functions -// ------------------------------------------------------------------------- - +/** + * Returns the name of a class + */ export const getNameOfClass = (c: any): string => new c().constructor.name; +/** + * Checks if the given argument is a promise + */ export const isPromiseLike = (o: any): boolean => !!o && (typeof o === 'object' || typeof o === 'function') && typeof o.then === 'function'; + +/** + * Times repeats a function n times + */ +export const times = async (n: number, iteratee: (index: number) => Promise): Promise => { + const rs = [] as TResult[]; + for (let i = 0; i < n; i++) { + const r = await iteratee(i); + rs.push(r); + } + return rs; +}; From e74adc9c4a464acdfb2be8c9759257f802d3c8df Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sun, 11 Mar 2018 18:58:43 +0100 Subject: [PATCH 03/14] house cleaning --- src/database/factories/UserFactory.ts | 1 - src/database/seeds/CreateBruce.ts | 2 -- src/database/seeds/CreatePets.ts | 3 --- src/database/seeds/CreateUsers.ts | 5 +---- src/lib/seed/index.ts | 7 ++----- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/database/factories/UserFactory.ts b/src/database/factories/UserFactory.ts index e8dd0add..810ae7a5 100644 --- a/src/database/factories/UserFactory.ts +++ b/src/database/factories/UserFactory.ts @@ -4,7 +4,6 @@ import { User } from '../../../src/api/models/User'; import { define } from '../../lib/seed'; define(User, (faker: typeof Faker, settings: { role: string }) => { - console.log('UserFactory', settings.role); const gender = faker.random.number(1); const firstName = faker.name.firstName(gender); const lastName = faker.name.lastName(gender); diff --git a/src/database/seeds/CreateBruce.ts b/src/database/seeds/CreateBruce.ts index 4a3439d0..0d88108d 100644 --- a/src/database/seeds/CreateBruce.ts +++ b/src/database/seeds/CreateBruce.ts @@ -6,8 +6,6 @@ import { Factory, Seed } from '../../lib/seed/types'; export class CreateBruce implements Seed { public async seed(factory: Factory, connection: Connection): Promise { - console.log('CreateBruce'); - // const userFactory = factory(User as any); // const adminUserFactory = userFactory({ role: 'admin' }); diff --git a/src/database/seeds/CreatePets.ts b/src/database/seeds/CreatePets.ts index c066a4e1..3b68f5aa 100644 --- a/src/database/seeds/CreatePets.ts +++ b/src/database/seeds/CreatePets.ts @@ -7,9 +7,6 @@ import { Factory, Seed, times } from '../../lib/seed'; export class CreatePets implements Seed { public async seed(factory: Factory, connection: Connection): Promise { - console.log('CreatePets'); - - // const connection = await factory.getConnection(); const em = connection.createEntityManager(); await times(10, async (n) => { diff --git a/src/database/seeds/CreateUsers.ts b/src/database/seeds/CreateUsers.ts index 62747b1b..6f6f5871 100644 --- a/src/database/seeds/CreateUsers.ts +++ b/src/database/seeds/CreateUsers.ts @@ -6,10 +6,7 @@ import { Factory, Seed } from '../../lib/seed/types'; export class CreateUsers implements Seed { public async seed(factory: Factory, connection: Connection): Promise { - console.log('CreateUsers'); - - await factory(User)() - .seedMany(10); + await factory(User)().seedMany(10); } } diff --git a/src/lib/seed/index.ts b/src/lib/seed/index.ts index 61f3b4e7..ead51f6e 100644 --- a/src/lib/seed/index.ts +++ b/src/lib/seed/index.ts @@ -2,9 +2,7 @@ import 'reflect-metadata'; import { Connection, ObjectType } from 'typeorm'; import { EntityFactory } from './EntityFactory'; -import { - EntityConstructor, EntityFactoryDefinition, FactoryFunction, SeedConstructor -} from './types'; +import { EntityFactoryDefinition, FactoryFunction, SeedConstructor } from './types'; import { getNameOfClass } from './utils'; // ------------------------------------------------------------------------- @@ -45,11 +43,10 @@ export const define = (entity: ObjectType, factoryFn: (global as any).seeder.entityFactories.set(getNameOfClass(entity), { entity, factory: factoryFn }); }; - /** * Gets a defined entity factory and pass the settigns along to the entity factory function */ -export const factory = (entity: EntityConstructor) => (settings?: Settings) => { +export const factory = (entity: Entity) => (settings?: Settings) => { const name = getNameOfClass(entity); const entityFactoryObject = (global as any).seeder.entityFactories.get(name); return new EntityFactory( From 0bf3110bf90f3a67ba04fab3bb176b6a3870d0cc Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sun, 11 Mar 2018 18:58:54 +0100 Subject: [PATCH 04/14] Adjust the documentation --- README.md | 78 ++++++++++++++++++++++--------------------------------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 3537b8c7..666db13b 100644 --- a/README.md +++ b/README.md @@ -256,14 +256,15 @@ 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. +How does it work? Just, create a factory for your entities 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`. +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); @@ -273,40 +274,25 @@ 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. - -```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 { + public async seed(factory: FactoryInterface, connection: Connection): Promise { 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(); + const pet = await factory(Pet)().create(); // This only returns a entity with fake data - const user = await factory.get(User).make(); + const user = await factory(User)({ roles: ['admin'] }).make(); user.pets = [pet]; await em.save(user); }); @@ -315,51 +301,49 @@ export class CreatePets implements SeedsInterface { } ``` -### 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. +Or you could do the relation in the entity factory like this. ```typescript -export class CreateUsers implements SeedsInterface { - - public async seed(factory: FactoryInterface): Promise { - await factory - .get(User) - .createMany(10); - } +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; +}); ``` -With the second parameter in the `.get(, )` you are able to create different variations of entities. +### 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 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 { - await factory - .get(User, 'admin') - .create(); + public async seed(factory: Factory, connection: Connection): Promise { + await factory(User)({ roles: [] }).createMany(10); } } ``` -Here an example with nested factories. +Here an example with nested factories. You can use the `.map()` function to alter +the generated value before they get persisted. ```typescript ... -await factory.get(User) - .each(async (user: User) => { - - const pets: Pet[] = await factory.get(Pet) - .createMany(2); - +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); - }) - .create(5); + .createMany(5); ... ``` From f5ac88da33bf700c995fc822afb0b51c7f5f980f Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sun, 11 Mar 2018 19:12:51 +0100 Subject: [PATCH 05/14] fix types --- src/database/seeds/CreatePets.ts | 4 ++-- src/lib/seed/EntityFactory.ts | 6 +++--- src/lib/seed/index.ts | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/database/seeds/CreatePets.ts b/src/database/seeds/CreatePets.ts index 3b68f5aa..76ef89fc 100644 --- a/src/database/seeds/CreatePets.ts +++ b/src/database/seeds/CreatePets.ts @@ -10,8 +10,8 @@ export class CreatePets implements Seed { const em = connection.createEntityManager(); await times(10, async (n) => { - const pet = await factory(Pet as any)().seed(); - const user = await factory(User as any)().make(); + const pet = await factory(Pet)().seed(); + const user = await factory(User)().make(); user.pets = [pet]; await em.save(user); }); diff --git a/src/lib/seed/EntityFactory.ts b/src/lib/seed/EntityFactory.ts index facd5bc4..784161fe 100644 --- a/src/lib/seed/EntityFactory.ts +++ b/src/lib/seed/EntityFactory.ts @@ -1,5 +1,5 @@ import * as Faker from 'faker'; -import { Connection } from 'typeorm/connection/Connection'; +import { Connection, ObjectType } from 'typeorm'; import { FactoryFunction } from './types'; import { isPromiseLike } from './utils'; @@ -13,7 +13,7 @@ export class EntityFactory { constructor( public name: string, - public entity: Entity, + public entity: ObjectType, private factory: FactoryFunction, private settings?: Settings ) { } @@ -54,7 +54,7 @@ export class EntityFactory { const em = connection.createEntityManager(); try { const entity = await this.make(); - return await em.save(this.entity, entity); + return await em.save(entity); } catch (error) { throw new Error('Could not save entity'); } diff --git a/src/lib/seed/index.ts b/src/lib/seed/index.ts index ead51f6e..2d057a77 100644 --- a/src/lib/seed/index.ts +++ b/src/lib/seed/index.ts @@ -1,6 +1,7 @@ import 'reflect-metadata'; import { Connection, ObjectType } from 'typeorm'; +import { Factory } from '../seeds/Factory'; import { EntityFactory } from './EntityFactory'; import { EntityFactoryDefinition, FactoryFunction, SeedConstructor } from './types'; import { getNameOfClass } from './utils'; @@ -46,7 +47,7 @@ export const define = (entity: ObjectType, factoryFn: /** * Gets a defined entity factory and pass the settigns along to the entity factory function */ -export const factory = (entity: Entity) => (settings?: Settings) => { +export const factory: Factory = (entity: ObjectType) => (settings?: Settings) => { const name = getNameOfClass(entity); const entityFactoryObject = (global as any).seeder.entityFactories.get(name); return new EntityFactory( From cf7c7cbc258ebba18087cf837f74a9df056e934d Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Sun, 11 Mar 2018 19:13:05 +0100 Subject: [PATCH 06/14] formatting readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 666db13b..1a2d1131 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,6 @@ define(Pet, (faker: typeof Faker, settings: undefined) => { 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 you are able to create different variations of entities. - ```typescript export class CreateUsers implements Seed { From 79da010d49594974ed58141a51faaa4428e0b497 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Mon, 12 Mar 2018 08:22:59 +0100 Subject: [PATCH 07/14] Fix type issue --- src/lib/seed/EntityFactory.ts | 3 --- src/lib/seed/index.ts | 3 +-- src/lib/seed/types.ts | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib/seed/EntityFactory.ts b/src/lib/seed/EntityFactory.ts index 784161fe..168dcbb6 100644 --- a/src/lib/seed/EntityFactory.ts +++ b/src/lib/seed/EntityFactory.ts @@ -4,9 +4,6 @@ import { Connection, ObjectType } from 'typeorm'; import { FactoryFunction } from './types'; import { isPromiseLike } from './utils'; -/** - * EntityFactory ... - */ export class EntityFactory { private mapFunction: (entity: Entity) => Promise; diff --git a/src/lib/seed/index.ts b/src/lib/seed/index.ts index 2d057a77..e3ef9049 100644 --- a/src/lib/seed/index.ts +++ b/src/lib/seed/index.ts @@ -1,9 +1,8 @@ import 'reflect-metadata'; import { Connection, ObjectType } from 'typeorm'; -import { Factory } from '../seeds/Factory'; import { EntityFactory } from './EntityFactory'; -import { EntityFactoryDefinition, FactoryFunction, SeedConstructor } from './types'; +import { EntityFactoryDefinition, Factory, FactoryFunction, SeedConstructor } from './types'; import { getNameOfClass } from './utils'; // ------------------------------------------------------------------------- diff --git a/src/lib/seed/types.ts b/src/lib/seed/types.ts index c931bbe4..b081ee09 100644 --- a/src/lib/seed/types.ts +++ b/src/lib/seed/types.ts @@ -11,7 +11,7 @@ export type FactoryFunction = (faker: typeof Faker, settings?: /** * Factory gets the EntityFactory to the given Entity and pass the settings along */ -export type Factory = (entity: Entity) => (settings?: Settings) => EntityFactory; +export type Factory = (entity: ObjectType) => (settings?: Settings) => EntityFactory; /** * Seed are the class to create some data. Those seed are run by the cli. From 8167b7a305292d6c130763ab418fa65fae6be6d4 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Mon, 12 Mar 2018 08:36:50 +0100 Subject: [PATCH 08/14] Describe cli commands for the seeding --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 1a2d1131..4296d628 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,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 --list CreateBruce,CreatePets"` | List seeds to run | +| `npm start "db.seed -L` | Log database queries to the terminal | +| `npm start "db.seed --factories` | Add a different path to your factories (Default: `src/database/`) | +| `npm start "db.seed --seeds` | Add a different path to your seeds (Default: `src/database/seeds/`) | +| `npm start "db.seed --config` | Path to your ormconfig.json file | + ## Run in Docker container ### Install Docker From 21e4c5b18dab60843522ccc6231db8d64bf22839 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Mon, 12 Mar 2018 08:49:42 +0100 Subject: [PATCH 09/14] Improve ormconfig loader --- src/lib/seed/connection.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/lib/seed/connection.ts b/src/lib/seed/connection.ts index 1d6f031e..5d7481c1 100644 --- a/src/lib/seed/connection.ts +++ b/src/lib/seed/connection.ts @@ -15,19 +15,10 @@ const indexOfConfigPath = args.indexOf(configParam) + 1; * Returns a TypeORM database connection for our entity-manager */ export const getConnection = async (): Promise => { - const ormconfig = (hasConfigPath) ? require(`${args[indexOfConfigPath]}`) : require(`${runDir}/ormconfig.json`); + ormconfig.logging = logging; - return await createConnection({ - type: (ormconfig as any).type as any, - host: (ormconfig as any).host, - port: (ormconfig as any).port, - username: (ormconfig as any).username, - password: (ormconfig as any).password, - database: (ormconfig as any).database, - entities: (ormconfig as any).entities, - logging, - }); + return createConnection(ormconfig); }; From 4fba18e06eab3a9f43a9d69fed85e5cb7dcded32 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Mon, 12 Mar 2018 08:55:28 +0100 Subject: [PATCH 10/14] Adjust tslint to frontend boilerplate --- tslint.json | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 525f68e8..aae115af 100644 --- a/tslint.json +++ b/tslint.json @@ -20,7 +20,6 @@ "ordered-imports": false, "object-literal-sort-keys": false, "arrow-parens": false, - "no-string-literal": false, "member-ordering": [ true, { @@ -72,6 +71,58 @@ }, "singleline": "never" } + ], + "align": [ + true, + "parameters" + ], + "class-name": true, + "curly": true, + "eofline": true, + "jsdoc-format": true, + "member-access": true, + "no-arg": true, + "no-construct": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-internal-module": true, + "no-string-literal": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-finally", + "check-whitespace" + ], + "semicolon": true, + "switch-default": true, + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" ] } } From 50671e63ac4a09ea752f1d35f9ed1ef51dd62892 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Mon, 12 Mar 2018 08:56:10 +0100 Subject: [PATCH 11/14] Update deps --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index d761d047..3a661e7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3480,8 +3480,8 @@ nps-utils@^1.5.0: rimraf "^2.6.1" nps@^5.7.1: - version "5.8.1" - resolved "https://registry.yarnpkg.com/nps/-/nps-5.8.1.tgz#180ca887a3bf8abdb860fb972d135310260580bb" + version "5.8.2" + resolved "https://registry.yarnpkg.com/nps/-/nps-5.8.2.tgz#17fc2e86f5f5577c54c49423996a63ef9299a889" dependencies: arrify "^1.0.1" chalk "^2.0.1" @@ -5173,8 +5173,8 @@ window-size@0.1.0: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" winston@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee" + version "2.4.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.1.tgz#a3a9265105564263c6785b4583b8c8aca26fded6" dependencies: async "~1.0.0" colors "1.0.x" From 5f58109a461255c547153d09f21b0c5fe24171cc Mon Sep 17 00:00:00 2001 From: David Weber Date: Tue, 13 Mar 2018 17:16:52 +0100 Subject: [PATCH 12/14] Update readme --- README.md | 66 ++++++++++++++++++----------------- src/lib/seed/EntityFactory.ts | 6 ++-- src/lib/seed/cli.ts | 8 ++--- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 4296d628..c034a5bb 100644 --- a/README.md +++ b/README.md @@ -255,12 +255,14 @@ 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 seed 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 @@ -279,29 +281,7 @@ define(User, (faker: typeof Faker, settings: { roles: string[] }) => { }); ``` -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 { - 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); - }); - } - -} -``` - -Or you could do the relation in the entity factory like this. +Handle relation in the entity factory like this. ```typescript define(Pet, (faker: typeof Faker, settings: undefined) => { @@ -319,7 +299,7 @@ define(Pet, (faker: typeof Faker, settings: undefined) => { ### 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 you are able to create different variations of entities. +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 { @@ -346,6 +326,28 @@ 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 { + 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); + }); + } + +} +``` + ### 3. Run the seeder The last step is the easiest, just hit the following command in your terminal, but be sure you are in the projects root folder. @@ -359,11 +361,11 @@ npm start db.seed | Command | Description | | --------------------------------------------------- | ----------- | | `npm start "db.seed"` | Run all seeds | -| `npm start "db.seed --list CreateBruce,CreatePets"` | List seeds to run | -| `npm start "db.seed -L` | Log database queries to the terminal | -| `npm start "db.seed --factories` | Add a different path to your factories (Default: `src/database/`) | -| `npm start "db.seed --seeds` | Add a different path to your seeds (Default: `src/database/seeds/`) | -| `npm start "db.seed --config` | Path to your ormconfig.json file | +| `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 "` | Add a different path to your factories (Default: `src/database/`) | +| `npm start "db.seed --seeds "` | Add a different path to your seeds (Default: `src/database/seeds/`) | +| `npm start "db.seed --config "` | Path to your ormconfig.json file | ## Run in Docker container diff --git a/src/lib/seed/EntityFactory.ts b/src/lib/seed/EntityFactory.ts index 168dcbb6..b9931878 100644 --- a/src/lib/seed/EntityFactory.ts +++ b/src/lib/seed/EntityFactory.ts @@ -20,7 +20,7 @@ export class EntityFactory { // ------------------------------------------------------------------------- /** - * This fucntion is used to alter the generated values of entity, before it + * This function is used to alter the generated values of entity, before it * is persist into the database */ public map(mapFunction: (entity: Entity) => Promise): EntityFactory { @@ -29,7 +29,7 @@ export class EntityFactory { } /** - * Make generate a new entity, but does not persist it + * Make a new entity, but does not persist it */ public async make(): Promise { if (this.factory) { @@ -43,7 +43,7 @@ export class EntityFactory { } /** - * Seed persist and generates a given entity + * Seed makes a new entity and does persist it */ public async seed(): Promise { const connection: Connection = (global as any).seeder.connection; diff --git a/src/lib/seed/cli.ts b/src/lib/seed/cli.ts index 2c58a812..20b52fae 100644 --- a/src/lib/seed/cli.ts +++ b/src/lib/seed/cli.ts @@ -14,8 +14,8 @@ commander .option('-L, --logging', 'enable sql query logging') .option('--factories ', 'add filepath for your factories') .option('--seeds ', 'add filepath for your seeds') - .option('--list ', 'list seeds to seed', (val) => val.split(',')) - .option('--config ', 'add filepath to your database config (must be a json)') + .option('--run ', 'run specific seeds (file names without extension)', (val) => val.split(',')) + .option('--config ', 'path to your ormconfig.json file (must be a json)') .parse(process.argv); // Get cli parameter for a different factory path @@ -29,8 +29,8 @@ const seedsPath = (commander.seeds) : 'src/database/seeds/'; // Get a list of seeds -const listOfSeeds = (commander.list) - ? commander.list.map(l => l.trim()).filter(l => l.length > 0) +const listOfSeeds = (commander.run) + ? commander.run.map(l => l.trim()).filter(l => l.length > 0) : []; // Search for seeds and factories From ae07db41dc103e2362c55a1fda730d91c24ce564 Mon Sep 17 00:00:00 2001 From: hirsch88 Date: Wed, 14 Mar 2018 07:47:34 +0100 Subject: [PATCH 13/14] improve util times --- src/lib/seed/utils.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/lib/seed/utils.ts b/src/lib/seed/utils.ts index 88b05037..98bcb7e4 100644 --- a/src/lib/seed/utils.ts +++ b/src/lib/seed/utils.ts @@ -11,11 +11,5 @@ export const isPromiseLike = (o: any): boolean => !!o && (typeof o === 'object' /** * Times repeats a function n times */ -export const times = async (n: number, iteratee: (index: number) => Promise): Promise => { - const rs = [] as TResult[]; - for (let i = 0; i < n; i++) { - const r = await iteratee(i); - rs.push(r); - } - return rs; -}; +export const times = async (n: number, iteratee: (index: number) => Promise): Promise => + Promise.all(new Array(n).map(async (v, i) => await iteratee(i))); From cc48b89a220be418e96ecf03e8015cc1fd20e363 Mon Sep 17 00:00:00 2001 From: David Weber Date: Wed, 14 Mar 2018 07:53:22 +0100 Subject: [PATCH 14/14] Fix middleware --- src/api/middlewares/ErrorHandlerMiddleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/middlewares/ErrorHandlerMiddleware.ts b/src/api/middlewares/ErrorHandlerMiddleware.ts index cc3181b2..a1aa3e9d 100644 --- a/src/api/middlewares/ErrorHandlerMiddleware.ts +++ b/src/api/middlewares/ErrorHandlerMiddleware.ts @@ -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) {