diff --git a/README.md b/README.md index 091cee14..8c9b83f2 100755 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ - [Introduction](#-introduction) - [Installation](#-installation) - [Basic Seeder](#-basic-seeder) -- [Factory API](#-factory-api) +- [Using Entity Factory](#-using-entity-factory) +- [Seeding Data in Testing](#-seeding-data-in-testing) - [Changelog](#-changelog) - [License](#-license) @@ -38,7 +39,7 @@ 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. +How does it work? Just create a entity factory for your entities (models) and a seed script. ### Enity @@ -74,9 +75,9 @@ export class Pet { ### Factory -The purpose of a factory is to create new fake entites with generate data. +Then for each entity define a factory. The purpose of a factory is to create new entites with generate data. -> Factories can also be used to generate test data for some unit, integration or e2e tests. +> Note: Factories can also be used to generate data for testing. ```typescript // user.factory.ts @@ -106,13 +107,16 @@ define(Pet, (faker: typeof Faker) => { ### Seeder -The seeder can be called by the configured cli command `seed:run`. In this case it generates 10 pets with a owner (User). + +And last but not least, create a seeder. The seeder can be called by the configured cli command `seed:run`. In this case it generates 10 pets with a owner (User). + +> Note: `seed:run` must be configured first. Go to [CLI Configuration](#cli-configuration). ```typescript // create-pets.seed.ts export default class CreatePets implements Seeder { public async run(factory: Factory, connection: Connection): Promise { - await factory(Pet)().seedMany(10) + await factory(Pet)().createMany(10) } } ``` @@ -121,7 +125,7 @@ export default class CreatePets implements Seeder { Before using this TypeORM extension please read the [TypeORM Getting Started](https://typeorm.io/#/) documentation. This explains how to setup a TypeORM project. -You can install our extension with `npm` or `yarn`. +After that install the extension with `npm` or `yarn`. ```bash npm i typeorm-seeding @@ -129,7 +133,7 @@ npm i typeorm-seeding yarn add typeorm-seeding ``` -Optional, for `Faker` types +Optional, install the type definitions of the `Faker` library. ```bash npm install -D @types/faker @@ -139,7 +143,7 @@ npm install -D @types/faker To configure the path to your seeds and factories change the TypeORM config file(ormconfig.js or ormconfig.json). -> Default is `src/database/{seeds,factories}/**/*{.ts,.js}` +> The default paths are `src/database/{seeds,factories}/**/*{.ts,.js}` **ormconfig.js** @@ -160,7 +164,7 @@ TYPEORM_SEEDING_SEEDS=src/seeds/**/*{.ts,.js} ### CLI Configuration -Add the following scripts to your `package.json` file. +Add the following scripts to your `package.json` file to configure the seed cli commands. ``` "scripts": { @@ -170,7 +174,9 @@ Add the following scripts to your `package.json` file. } ``` -> Now you are able to execute your seeds with this command `npm run seed:run`. +To execute the seed run `npm run seed:run` in the terminal. + +> Note: More CLI optios are [here](#cli-options) Add the following TypeORM cli commands to the package.json to drop and sync the database. @@ -187,14 +193,16 @@ Add the following TypeORM cli commands to the package.json to drop and sync the | Option | Default | Description | | ---------------------- | --------------- | --------------------------------------------------------------------------- | -| `--seed` or `-s` | null | Option to specify a specific seeder class to run individually. | +| `--seed` or `-s` | null | Option to specify a seeder class to run individually. | | `--connection` or `-c` | null | Name of the typeorm connection. Required if there are multiple connections. | | `--configName` or `-n` | `ormconfig.js` | Name to the typeorm config file. | | `--root` or `-r` | `process.cwd()` | Path to the typeorm config file. | ## ❯ Basic Seeder -The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically. +A seeder class only contains one method by default `run`. Within this method, you may insert data into your database. For manually insertion use the [Query Builder](https://typeorm.io/#/select-query-builder) or use the [Entity Factory](#-using-entity-factory) + +> Note. The seeder files will be executed alphabetically. ```typescript import { Factory, Seeder } from 'typeorm-seeding' @@ -216,15 +224,17 @@ export default class CreateUsers implements Seeder { } ``` -## ❯ Factory API +## ❯ Using Entity Factory + +Of course, manually specifying the attributes for each entity seed is cumbersome. Instead, you can use entity factories to conveniently generate large amounts of database records. -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/user.factory.ts`. +For all entities we want to create, 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/user.factory.ts`. -| Types | Description | -| --------------- | ----------------------------------------------------------------------------- | -| `Enity` | TypeORM Enity like the user or the pet in the samples. | -| `Context` | Argument to pass some static data into the factory function. | -| `EntityFactory` | This object is used to make new filled entities or seed it into the database. | +| Types | Description | +| --------------- | ------------------------------------------------------------------------------- | +| `Enity` | TypeORM Enity like the user or the pet in the samples. | +| `Context` | Argument to pass some static data into the factory function. | +| `EntityFactory` | This object is used to make new filled entities or create it into the database. | ### `define` @@ -268,16 +278,16 @@ map(mapFunction: (entity: Entity) => Promise): EntityFactory { - const pets: Pet[] = await factory(Pet)().seedMany(2) + const pets: Pet[] = await factory(Pet)().createMany(2) const petIds = pets.map((pet: Pet) => pet.Id) await user.pets().attach(petIds) }) - .seedMany(5) + .createMany(5) ``` #### `make` & `makeMany` -Make and makeMany executes the factory functions and return a new instance of the given enity. The instance is filled with the generated values from the factory function. +Make and makeMany executes the factory functions and return a new instance of the given enity. The instance is filled with the generated values from the factory function, but not saved in the database. **overrideParams** - Override some of the attributes of the enity. @@ -294,23 +304,93 @@ await factory(User)().make({ email: 'other@mail.com' }) await factory(User)().makeMany(10, { email: 'other@mail.com' }) ``` -#### `seed` & `seedMany` +#### `create` & `createMany` -seed and seedMany is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database. +the create and createMany method is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database. **overrideParams** - Override some of the attributes of the enity. ```typescript -seed(overrideParams: EntityProperty = {}): Promise +create(overrideParams: EntityProperty = {}): Promise ``` ```typescript -await factory(User)().seed() -await factory(User)().seedMany(10) +await factory(User)().create() +await factory(User)().createMany(10) // override the email -await factory(User)().seed({ email: 'other@mail.com' }) -await factory(User)().seedMany(10, { email: 'other@mail.com' }) +await factory(User)().create({ email: 'other@mail.com' }) +await factory(User)().createMany(10, { email: 'other@mail.com' }) +``` + +## ❯ Seeding Data in Testing + +The entity factories can also be used in testing. To do so call the `useSeeding` function, which loads all the defined entity factories. + +> Note: Normally Jest parallelizes test runs, which all conect to the same database. This could lead to strange sideeffects. So use the `--runInBand` flag to disable parallelizes runs. + +```typescript +describe("UserService", () => { + beforeAll(async (done) => { + await useRefreshDatabase() + await useSeeding() + + const user = await factory(User)().make() + const createdUser = await factory(User)().create() + + await runSeeder(CreateUserSeed) + done() + }) + + afterAll(async (done) => { + await tearDownDatabase() + done() + }) + + test('Should ...', () => { ... }) +}) +``` + +### `useSeeding` + +Loads the defined entity factories. + +```typescript +useSeeding(options: ConfigureOption = {}): Promise +``` + +### `runSeeder` + +Runs the given seeder class. + +```typescript +useSeeding(seed: SeederConstructor): Promise +``` + +### `useRefreshDatabase` + +Connects to the database, drops it and recreates the schema. + +```typescript +useRefreshDatabase(options: ConfigureOption = {}): Promise +``` + +### `tearDownDatabase` + +Closes the open database connection. + +```typescript +tearDownDatabase(): Promise +``` + +### `ConfigureOption` + +```typescript +interface ConfigureOption { + root?: string // path to the orm config file. Default = process.cwd() + configName?: string // name of the config file. eg. ormconfig.js + connection?: string // name of the database connection. +} ``` ## ❯ Changelog diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..91a2d2c0 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; \ No newline at end of file diff --git a/logo.png b/logo.png index b1321113..d238d30d 100644 Binary files a/logo.png and b/logo.png differ diff --git a/ormconfig.js b/ormconfig.js index 5a73c0db..e80507db 100644 --- a/ormconfig.js +++ b/ormconfig.js @@ -1,5 +1,3 @@ -const path = require('path') - module.exports = [ { name: 'sample', diff --git a/package.json b/package.json index d266e726..eafda2a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typeorm-seeding", - "version": "1.4.3", + "version": "1.4.4", "description": "🌱 A delightful way to seed test data into your database.", "license": "MIT", "author": "Gery Hirschfeld (https://github.com/hirsch88)", @@ -17,7 +17,7 @@ "prebuild": "rimraf dist", "format": "prettier --write \"src/**/*.ts\"", "lint": "eslint \"src/**/*.ts\" --fix", - "build": "tsc --project ./tsconfig.build.json", + "build": "npm run prebuild && tsc --project ./tsconfig.build.json", "watch": "rollup -cw", "test": "jest", "test:watch": "jest --watch", @@ -67,19 +67,5 @@ }, "resolutions": { "mem": ">=4.0.0" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "src", - "testRegex": ".test.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "coverageDirectory": "../coverage", - "testEnvironment": "node" } } diff --git a/sample/seeds/create-pets.seed.ts b/sample/seeds/create-pets.seed.ts index 34e83e5e..1cd7b023 100644 --- a/sample/seeds/create-pets.seed.ts +++ b/sample/seeds/create-pets.seed.ts @@ -4,6 +4,6 @@ import { Pet } from '../entities/Pet.entity' export default class CreatePets implements Seeder { public async run(factory: Factory, connection: Connection): Promise { - await factory(Pet)().seed() + await factory(Pet)().create() } } diff --git a/sample/seeds/create-users.seed.ts b/sample/seeds/create-users.seed.ts index b7697bb6..1de35214 100644 --- a/sample/seeds/create-users.seed.ts +++ b/sample/seeds/create-users.seed.ts @@ -3,6 +3,6 @@ import { User } from '../entities/User.entity' export default class CreateUsers implements Seeder { public async run(factory: Factory): Promise { - await factory(User)({ roles: [] }).seedMany(10) + await factory(User)({ roles: [] }).createMany(10) } } diff --git a/src/commands/config.command.ts b/src/commands/config.command.ts index c34163de..2f8d6bd7 100644 --- a/src/commands/config.command.ts +++ b/src/commands/config.command.ts @@ -1,7 +1,7 @@ import * as yargs from 'yargs' import * as chalk from 'chalk' -import { getConnectionOption } from '../typeorm-seeding' import { printError } from '../utils/log.util' +import { configureConnection, getConnectionOptions } from '../connection' export class ConfigCommand implements yargs.CommandModule { command = 'config' @@ -29,15 +29,14 @@ export class ConfigCommand implements yargs.CommandModule { async handler(args: yargs.Arguments) { const log = console.log const pkg = require('../../package.json') - log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`)) + log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`)) try { - const option = await getConnectionOption( - { - root: args.root as string, - configName: args.configName as string, - }, - args.connection as string, - ) + configureConnection({ + root: args.root as string, + configName: args.configName as string, + connection: args.connection as string, + }) + const option = await getConnectionOptions() log(option) } catch (error) { printError('Could not find the orm config file', error) diff --git a/src/commands/seed.command.ts b/src/commands/seed.command.ts index b24dd6e9..a2669942 100644 --- a/src/commands/seed.command.ts +++ b/src/commands/seed.command.ts @@ -1,11 +1,10 @@ import * as yargs from 'yargs' import * as ora from 'ora' import * as chalk from 'chalk' -import { createConnection } from 'typeorm' -import { setConnection, runSeeder, getConnectionOption, getConnection } from '../typeorm-seeding' import { importSeed } from '../importer' import { loadFiles, importFiles } from '../utils/file.util' -import { ConnectionOptions } from '../connection' +import { runSeeder } from '../typeorm-seeding' +import { configureConnection, getConnectionOptions, ConnectionOptions, createConnection } from '../connection' export class SeedCommand implements yargs.CommandModule { command = 'seed' @@ -35,23 +34,21 @@ export class SeedCommand implements yargs.CommandModule { } async handler(args: yargs.Arguments) { - // Disable logging for the seeders, but keep it alive for our cli const log = console.log - const pkg = require('../../package.json') - log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`)) + log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`)) const spinner = ora('Loading ormconfig').start() + const configureOption = { + root: args.root as string, + configName: args.configName as string, + connection: args.connection as string, + } // Get TypeORM config file let option: ConnectionOptions try { - option = await getConnectionOption( - { - root: args.root as string, - configName: args.configName as string, - }, - args.connection as string, - ) + configureConnection(configureOption) + option = await getConnectionOptions() spinner.succeed('ORM Config loaded') } catch (error) { panic(spinner, error, 'Could not load the config file!') @@ -59,9 +56,9 @@ export class SeedCommand implements yargs.CommandModule { // Find all factories and seed with help of the config spinner.start('Import Factories') - const factoryFiles = loadFiles(option.factories || ['src/database/factories/**/*{.js,.ts}']) + const factoryFiles = loadFiles(option.factories) try { - importFiles(factoryFiles) + await importFiles(factoryFiles) spinner.succeed('Factories are imported') } catch (error) { panic(spinner, error, 'Could not import factories!') @@ -69,12 +66,13 @@ export class SeedCommand implements yargs.CommandModule { // Show seeds in the console spinner.start('Importing Seeders') - const seedFiles = loadFiles(option.seeds || ['src/database/seeds/**/*{.js,.ts}']) + const seedFiles = loadFiles(option.seeds) let seedFileObjects: any[] = [] try { - seedFileObjects = seedFiles - .map((seedFile) => importSeed(seedFile)) - .filter((seedFileObject) => args.seed === undefined || args.seed === seedFileObject.name) + seedFileObjects = await Promise.all(seedFiles.map((seedFile) => importSeed(seedFile))) + seedFileObjects = seedFileObjects.filter( + (seedFileObject) => args.seed === undefined || args.seed === seedFileObject.name, + ) spinner.succeed('Seeders are imported') } catch (error) { panic(spinner, error, 'Could not import seeders!') @@ -83,8 +81,7 @@ export class SeedCommand implements yargs.CommandModule { // Get database connection and pass it to the seeder spinner.start('Connecting to the database') try { - const connection = await createConnection(option) - setConnection(connection) + await createConnection() spinner.succeed('Database connected') } catch (error) { panic(spinner, error, 'Database connection failed! Check your typeORM config file.') diff --git a/src/connection.ts b/src/connection.ts index 33d3e201..85a68c7c 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -1,8 +1,8 @@ import { - Connection, ConnectionOptionsReader, - createConnection as createTypeORMConnection, + Connection as TypeORMConnection, ConnectionOptions as TypeORMConnectionOptions, + createConnection as TypeORMCreateConnection, } from 'typeorm' import { printError } from './utils/log.util' @@ -11,54 +11,80 @@ interface SeedingOptions { seeds: string[] } -export interface ConnectionOptionArguments { - root: string - configName: string +export declare type ConnectionOptions = TypeORMConnectionOptions & SeedingOptions + +export interface ConfigureOption { + root?: string + configName?: string + connection?: string } -export declare type ConnectionOptions = TypeORMConnectionOptions & SeedingOptions +const KEY = 'TypeORM_Seeding_Connection' -const attachSeedingOptions = (option: ConnectionOptions): ConnectionOptions => { - if (!option.factories) { - const envFactoriesPath = process.env.TYPEORM_SEEDING_FACTORIES - if (envFactoriesPath) { - option.factories = [envFactoriesPath] - } else { - option.factories = ['src/database/factories/**/*{.ts,.js}'] - } - } - if (!option.seeds) { - const envSeedsPath = process.env.TYPEORM_SEEDING_SEEDS - if (envSeedsPath) { - option.seeds = [envSeedsPath] - } else { - option.seeds = ['src/database/seeds/**/*{.ts,.js}'] - } +const defaultConfigureOption: ConfigureOption = { + root: process.cwd(), + configName: '', + connection: '', +} + +if ((global as any)[KEY] === undefined) { + ;(global as any)[KEY] = { + configureOption: defaultConfigureOption, + ormConfig: undefined, + connection: undefined, } - return option } -export const getConnectionOption = async ( - option: ConnectionOptionArguments, - connection: string, -): Promise => { - const reader = new ConnectionOptionsReader(option) - const options = (await reader.all()) as any[] - if (options.length === 1) { - return attachSeedingOptions(options[0]) +export const configureConnection = (option: ConfigureOption = {}) => { + ;(global as any)[KEY].configureOption = { + ...defaultConfigureOption, + ...option, } - if (connection !== undefined && connection !== '') { - const filteredOptions = options.filter((o) => o.name === connection) - if (filteredOptions.length === 1) { - return attachSeedingOptions(options[0]) - } else { - printError('Could not find any connection with the name=', connection) +} + +export const getConnectionOptions = async (): Promise => { + const ormConfig = (global as any)[KEY].ormConfig + if (ormConfig === undefined) { + const configureOption = (global as any)[KEY].configureOption + const connection = configureOption.connection + const reader = new ConnectionOptionsReader({ + root: configureOption.root, + configName: configureOption.configName, + }) + let options = (await reader.all()) as any[] + if (connection !== undefined && connection !== '') { + const filteredOptions = options.filter((o) => o.name === connection) + if (filteredOptions.length === 1) { + options = filteredOptions + } } + if (options.length === 1) { + const option = options[0] + if (!option.factories) { + option.factories = [process.env.TYPEORM_SEEDING_FACTORIES || 'src/database/factories/**/*{.ts,.js}'] + } + if (!option.seeds) { + option.seeds = [process.env.TYPEORM_SEEDING_SEEDS || 'src/database/seeds/**/*{.ts,.js}'] + } + ;(global as any)[KEY].ormConfig = option + return option + } + printError('There are multiple connections please provide a connection name') } - printError('There are multiple connections please provide a connection name') + return ormConfig } -export const createConnection = async (option: ConnectionOptionArguments, name: string): Promise => { - const connectionOption = await getConnectionOption(option, name) - return createTypeORMConnection(connectionOption) +export const createConnection = async (option?: TypeORMConnectionOptions): Promise => { + let connection = (global as any)[KEY].connection + let ormConfig = (global as any)[KEY].ormConfig + + if (option !== undefined) { + ormConfig = option + } + + if (connection === undefined) { + connection = await TypeORMCreateConnection(ormConfig) + ;(global as any)[KEY].connection = connection + } + return connection } diff --git a/src/entity-factory.ts b/src/entity-factory.ts index dffe4990..2badd1d3 100644 --- a/src/entity-factory.ts +++ b/src/entity-factory.ts @@ -1,8 +1,9 @@ import * as Faker from 'faker' -import { Connection, ObjectType } from 'typeorm' +import { ObjectType } from 'typeorm' import { FactoryFunction, EntityProperty } from './types' import { isPromiseLike } from './utils/factory.util' -import { printError } from './utils/log.util' +import { printError, printWarning } from './utils/log.util' +import { getConnectionOptions, createConnection } from './connection' export class EntityFactory { private mapFunction: (entity: Entity) => Promise @@ -35,11 +36,12 @@ export class EntityFactory { } /** - * Seed makes a new entity and does persist it + * Create makes a new entity and does persist it */ - public async seed(overrideParams: EntityProperty = {}): Promise { - const connection: Connection = (global as any).seeder.connection - if (connection) { + public async create(overrideParams: EntityProperty = {}): Promise { + const option = await getConnectionOptions() + const connection = await createConnection(option) + if (connection && connection.isConnected) { const em = connection.createEntityManager() try { const entity = await this.makeEnity(overrideParams, true) @@ -64,14 +66,24 @@ export class EntityFactory { return list } - public async seedMany(amount: number, overrideParams: EntityProperty = {}): Promise { + public async createMany(amount: number, overrideParams: EntityProperty = {}): Promise { const list = [] for (let index = 0; index < amount; index++) { - list[index] = await this.seed(overrideParams) + list[index] = await this.create(overrideParams) } return list } + public async seed(overrideParams: EntityProperty = {}): Promise { + printWarning('The seed() method is deprecated please use the create() method instead') + return this.create(overrideParams) + } + + public async seedMany(amount: number, overrideParams: EntityProperty = {}): Promise { + printWarning('The seedMany() method is deprecated please use the createMany() method instead') + return this.createMany(amount, overrideParams) + } + // ------------------------------------------------------------------------- // Prrivat Helpers // ------------------------------------------------------------------------- @@ -108,7 +120,7 @@ export class EntityFactory { const subEntityFactory = entity[attribute] try { if (isSeeding) { - entity[attribute] = await (subEntityFactory as any).seed() + entity[attribute] = await (subEntityFactory as any).create() } else { entity[attribute] = await (subEntityFactory as any).make() } diff --git a/src/importer.ts b/src/importer.ts index 4c19b3a7..56c6cc9d 100644 --- a/src/importer.ts +++ b/src/importer.ts @@ -1,7 +1,7 @@ import { SeederConstructor, Seeder } from './types' -export const importSeed = (filePath: string): SeederConstructor => { - const seedFileObject: { [key: string]: SeederConstructor } = require(filePath) +export const importSeed = async (filePath: string): Promise => { + const seedFileObject: { [key: string]: SeederConstructor } = await import(filePath) const keys = Object.keys(seedFileObject) return seedFileObject[keys[0]] } diff --git a/src/typeorm-seeding.ts b/src/typeorm-seeding.ts index 66e95cb6..b7d3f65c 100644 --- a/src/typeorm-seeding.ts +++ b/src/typeorm-seeding.ts @@ -1,9 +1,11 @@ import 'reflect-metadata' -import { Connection, ObjectType } from 'typeorm' +import { ObjectType, getConnection, Connection } from 'typeorm' import { EntityFactory } from './entity-factory' import { EntityFactoryDefinition, Factory, FactoryFunction, SeederConstructor, Seeder } from './types' import { getNameOfEntity } from './utils/factory.util' +import { loadFiles, importFiles } from './utils/file.util' +import { ConfigureOption, configureConnection, getConnectionOptions, createConnection } from './connection' // ------------------------------------------------------------------------- // Handy Exports @@ -18,7 +20,6 @@ export { times } from './helpers' // Types & Variables // ------------------------------------------------------------------------- ;(global as any).seeder = { - connection: undefined, entityFactories: new Map>(), } @@ -26,10 +27,6 @@ export { times } from './helpers' // 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(getNameOfEntity(entity), { entity, @@ -43,7 +40,34 @@ export const factory: Factory = (entity: ObjectType) => return new EntityFactory(name, entity, entityFactoryObject.factory, context) } -export const runSeeder = async (clazz: SeederConstructor): Promise => { +export const runSeeder = async (clazz: SeederConstructor): Promise => { const seeder: Seeder = new clazz() - return seeder.run(factory, getConnection()) + const connection = await createConnection() + return seeder.run(factory, connection) +} + +// ------------------------------------------------------------------------- +// Facade functions for testing +// ------------------------------------------------------------------------- +export const useRefreshDatabase = async (options: ConfigureOption = {}): Promise => { + configureConnection(options) + const option = await getConnectionOptions() + const connection = await createConnection(option) + if (connection.isConnected) { + await connection.dropDatabase() + await connection.synchronize() + } + return connection +} + +export const tearDownDatabase = async (): Promise => { + const connection = await createConnection() + return connection && connection.isConnected ? connection.close() : undefined +} + +export const useSeeding = async (options: ConfigureOption = {}): Promise => { + configureConnection(options) + const option = await getConnectionOptions() + const factoryFiles = loadFiles(option.factories) + await importFiles(factoryFiles) } diff --git a/src/utils/file.util.ts b/src/utils/file.util.ts index 13a180a2..25dc9150 100644 --- a/src/utils/file.util.ts +++ b/src/utils/file.util.ts @@ -1,7 +1,9 @@ import * as glob from 'glob' import * as path from 'path' -export const importFiles = (filePaths: string[]) => filePaths.forEach(require) +export const importFiles = async (filePaths: string[]) => { + await Promise.all(filePaths.map((filePath) => import(filePath))) +} export const loadFiles = (filePattern: string[]): string[] => { return filePattern diff --git a/src/utils/log.util.ts b/src/utils/log.util.ts index 0849dbf4..b4413b21 100644 --- a/src/utils/log.util.ts +++ b/src/utils/log.util.ts @@ -9,3 +9,13 @@ export const printError = (message: string, error?: any) => { console.error(error) } } + +/** + * Prints the warning to the console + */ +export const printWarning = (message: string, error?: any) => { + console.log('\n🚨 ', chalk.yellow(message)) + if (error) { + console.error(error) + } +}