UNPKG

@mikro-orm/seeder

Version:

Seeder package for MikroORM.

138 lines (137 loc) 5.73 kB
import { Utils, } from '@mikro-orm/core'; /** Manages discovery and execution of database seeders. */ export class SeedManager { #config; #options; #absolutePath; #initialized = false; #em; constructor(em) { this.#em = em; this.#config = this.#em.config; this.#options = this.#config.get('seeder'); this.#em = this.#em.fork(); this.#config.set('persistOnCreate', true); } async init() { if (this.#initialized) { return; } this.#initialized = true; if (!this.#options.seedersList) { const { fs } = await import('@mikro-orm/core/fs-utils'); this.detectSourceFolder(fs); /* v8 ignore next */ const key = this.#config.get('preferTs', Utils.detectTypeScriptSupport()) && this.#options.pathTs ? 'pathTs' : 'path'; this.#absolutePath = fs.absolutePath(this.#options[key], this.#config.get('baseDir')); } } static register(orm) { orm.config.registerExtension('@mikro-orm/seeder', () => new SeedManager(orm.em)); } /** * Checks if `src` folder exists, it so, tries to adjust the migrations and seeders paths automatically to use it. * If there is a `dist` or `build` folder, it will be used for the JS variant (`path` option), while the `src` folder will be * used for the TS variant (`pathTs` option). * * If the default folder exists (e.g. `/migrations`), the config will respect that, so this auto-detection should not * break existing projects, only help with the new ones. */ detectSourceFolder(fs) { const baseDir = this.#config.get('baseDir'); const defaultPath = './seeders'; if (!fs.pathExists(baseDir + '/src')) { this.#options.path ??= defaultPath; return; } const exists = fs.pathExists(`${baseDir}/${defaultPath}`); const distDir = fs.pathExists(baseDir + '/dist'); const buildDir = fs.pathExists(baseDir + '/build'); // if neither `dist` nor `build` exist, we use the `src` folder as it might be a JS project without building, but with `src` folder const path = distDir ? './dist' : buildDir ? './build' : './src'; // only if the user did not provide any values and if the default path does not exist if (!this.#options.path && !this.#options.pathTs && !exists) { this.#options.path = `${path}/seeders`; this.#options.pathTs = './src/seeders'; } } async seed(...classNames) { for (const SeederClass of classNames) { const seeder = new SeederClass(); await seeder.run(this.#em); await this.#em.flush(); this.#em.clear(); } } /** * @internal */ async seedString(...classNames) { if (this.#options.seedersList) { const classMap = new Map(); for (const entry of this.#options.seedersList) { if (typeof entry === 'function') { classMap.set(entry.name, entry); } else { classMap.set(entry.name, entry.class); } } for (const className of classNames) { const seederClass = classMap.get(className); if (!seederClass) { throw new Error(`Seeder class ${className} not found in seedersList`); } await this.seed(seederClass); } return; } await this.init(); const { fs } = await import('@mikro-orm/core/fs-utils'); const path = fs.normalizePath(this.#absolutePath, this.#options.glob); const files = fs.glob(path).sort(); const classMap = new Map(); for (const filePath of files) { const exports = await fs.dynamicImport(filePath); for (const name of Object.keys(exports)) { classMap.set(name, exports[name]); } } for (const className of classNames) { const seederClass = classMap.get(className); if (!seederClass) { throw new Error(`Seeder class ${className} not found in ${fs.relativePath(path, process.cwd())}`); } await this.seed(seederClass); } } async create(className) { await this.init(); const { fs } = await import('@mikro-orm/core/fs-utils'); fs.ensureDir(this.#absolutePath); return this.generate(fs, className); } async generate(fs, className) { const fileName = `${this.#options.fileName(className)}.${this.#options.emit}`; const filePath = `${this.#absolutePath}/${fileName}`; let ret = ''; if (this.#options.emit === 'ts') { ret += `import type { EntityManager } from '@mikro-orm/core';\n`; ret += `import { Seeder } from '@mikro-orm/seeder';\n\n`; ret += `export class ${className} extends Seeder {\n\n`; ret += ` async run(em: EntityManager): Promise<void> {}\n\n`; ret += `}\n`; } else { ret += `'use strict';\n`; ret += `Object.defineProperty(exports, '__esModule', { value: true });\n`; ret += `const { Seeder } = require('@mikro-orm/seeder');\n\n`; ret += `class ${className} extends Seeder {\n\n`; ret += ` async run(em: EntityManager): Promise<void> {}\n\n`; ret += `}\n`; ret += `exports.${className} = ${className};\n`; } await fs.writeFile(filePath, ret, { flush: true }); return filePath; } }