mikro-orm/mikro-orm

View on GitHub
packages/cli/src/commands/SchemaCommandFactory.ts

Summary

Maintainability
A
55 mins
Test Coverage
A
100%
import type { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
import { colors } from '@mikro-orm/core';
import { CLIHelper } from '../CLIHelper';

export class SchemaCommandFactory {

  static readonly DESCRIPTIONS = {
    create: 'Create database schema based on current metadata',
    update: 'Update database schema based on current metadata',
    drop: 'Drop database schema based on current metadata',
    fresh: 'Drop and recreate database schema based on current metadata',
  };

  static readonly SUCCESS_MESSAGES = {
    create: 'Schema successfully created',
    update: 'Schema successfully updated',
    drop: 'Schema successfully dropped',
    fresh: 'Schema successfully dropped and recreated',
  };

  static create<U extends Options = Options>(command: SchemaMethod): CommandModule<unknown, U> & { builder: (args: Argv) => Argv<U>; handler: (args: ArgumentsCamelCase<U>) => Promise<void> } {
    const successMessage = SchemaCommandFactory.SUCCESS_MESSAGES[command];

    return {
      command: `schema:${command}`,
      describe: SchemaCommandFactory.DESCRIPTIONS[command],
      builder: (args: Argv) => SchemaCommandFactory.configureSchemaCommand(args, command) as Argv<U>,
      handler: (args: ArgumentsCamelCase<U>) => SchemaCommandFactory.handleSchemaCommand(args, command, successMessage),
    };
  }

  static configureSchemaCommand(args: Argv, command: SchemaMethod) {
    args.option('r', {
      alias: 'run',
      type: 'boolean',
      desc: 'Runs queries',
    });

    if (command !== 'fresh') {
      args.option('d', {
        alias: 'dump',
        type: 'boolean',
        desc: 'Dumps all queries to console',
      });
      args.option('fk-checks', {
        type: 'boolean',
        desc: 'Do not skip foreign key checks',
      });
    }

    args.option('schema', {
      type: 'string',
      desc: 'Set the current schema for wildcard schema entities',
    });

    if (['create', 'fresh'].includes(command)) {
      args.option('seed', {
        type: 'string',
        desc: 'Allows to seed the database on create or drop and recreate',
      });
    }

    if (command === 'update') {
      args.option('safe', {
        type: 'boolean',
        desc: 'Allows to disable table and column dropping',
        default: false,
      });
      args.option('drop-tables', {
        type: 'boolean',
        desc: 'Allows to disable table dropping',
        default: true,
      });
    }

    if (command === 'drop') {
      args.option('drop-migrations-table', {
        type: 'boolean',
        desc: 'Drop also migrations table',
      });
    }

    if (['drop', 'fresh'].includes(command)) {
      args.option('drop-db', {
        type: 'boolean',
        desc: 'Drop the whole database',
      });
    }

    return args;
  }

  static async handleSchemaCommand(args: ArgumentsCamelCase<Options>, method: SchemaMethod, successMessage: string) {
    if (!args.run && !args.dump) {
      return CLIHelper.showHelp();
    }

    const orm = await CLIHelper.getORM();
    const generator = orm.getSchemaGenerator();
    const params = { wrap: args.fkChecks == null ? undefined : !args.fkChecks, ...args };

    if (args.dump) {
      const m = `get${method.substr(0, 1).toUpperCase()}${method.substr(1)}SchemaSQL` as 'getCreateSchemaSQL' | 'getUpdateSchemaSQL' | 'getDropSchemaSQL';
      const dump = await generator[m](params);

      /* istanbul ignore next */
      if (dump) {
        CLIHelper.dump(dump, orm.config);
        successMessage = '';
      } else {
        successMessage = 'Schema is up-to-date';
      }
    } else if (method === 'fresh') {
      await generator.dropSchema(params);
      await generator.createSchema(params);
    } else {
      const m = method + 'Schema' as 'createSchema';
      await generator[m](params);
    }

    if (args.seed !== undefined) {
      const seeder = orm.getSeeder();
      await seeder.seedString(args.seed || orm.config.get('seeder').defaultSeeder!);
    }

    CLIHelper.dump(colors.green(successMessage));
    await orm.close(true);
  }

}

type SchemaMethod = 'create' | 'update' | 'drop' | 'fresh';

export type Options = {
  dump: boolean;
  run: boolean;
  fkChecks: boolean;
  dropMigrationsTable: boolean;
  dropDb: boolean;
  dropTables: boolean;
  safe: boolean;
  seed: string;
  schema: string;
};