Skip to content

Commit

Permalink
feat(cli): add basic CLI tool
Browse files Browse the repository at this point in the history
Closes #101
  • Loading branch information
B4nan committed Aug 19, 2019
1 parent 5bcb626 commit df103d6
Show file tree
Hide file tree
Showing 31 changed files with 691 additions and 13 deletions.
36 changes: 36 additions & 0 deletions ents/Author3.ts
@@ -0,0 +1,36 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Author3 {

@PrimaryKey()
id: number;

@Property({ nullable: true })
createdAt: Date;

@Property({ nullable: true })
updatedAt: Date;

@Property()
name: string;

@Property()
email: string;

@Property({ nullable: true })
age: number;

@Property()
termsAccepted: number;

@Property({ nullable: true })
identities: string;

@Property({ nullable: true })
born: Date;

@Property({ nullable: true })
favouriteBookId: number;

}
18 changes: 18 additions & 0 deletions ents/Book3.ts
@@ -0,0 +1,18 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Book3 {

@PrimaryKey()
id: number;

@Property()
title: string;

@Property({ nullable: true })
authorId: number;

@Property({ nullable: true })
publisherId: number;

}
15 changes: 15 additions & 0 deletions ents/Book3ToBookTag3.ts
@@ -0,0 +1,15 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Book3ToBookTag3 {

@PrimaryKey()
id: number;

@Property({ fieldName: 'book3_id', nullable: true })
book3Id: number;

@Property({ fieldName: 'book_tag3_id', nullable: true })
bookTag3Id: number;

}
15 changes: 15 additions & 0 deletions ents/BookTag3.ts
@@ -0,0 +1,15 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class BookTag3 {

@PrimaryKey()
id: number;

@Property()
name: string;

@Property({ default: `current_timestamp` })
version: Date;

}
15 changes: 15 additions & 0 deletions ents/Publisher3.ts
@@ -0,0 +1,15 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Publisher3 {

@PrimaryKey()
id: number;

@Property()
name: string;

@Property()
type: string;

}
15 changes: 15 additions & 0 deletions ents/Publisher3ToTest3.ts
@@ -0,0 +1,15 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Publisher3ToTest3 {

@PrimaryKey()
id: number;

@Property({ fieldName: 'publisher3_id', nullable: true })
publisher3Id: number;

@Property({ fieldName: 'test3_id', nullable: true })
test3Id: number;

}
15 changes: 15 additions & 0 deletions ents/Test3.ts
@@ -0,0 +1,15 @@
import { Entity, PrimaryKey, Property } from 'mikro-orm';

@Entity()
export class Test3 {

@PrimaryKey()
id: number;

@Property({ nullable: true })
name: string;

@Property()
version: number = 1;

}
Empty file added foo_bar
Empty file.
2 changes: 1 addition & 1 deletion lib/MikroORM.ts
Expand Up @@ -13,7 +13,7 @@ export class MikroORM {
private readonly driver: IDatabaseDriver;
private readonly logger: Logger;

static async init(options: Options): Promise<MikroORM> {
static async init(options: Options | Configuration): Promise<MikroORM> {
const orm = new MikroORM(options);
const driver = await orm.connect();

Expand Down
2 changes: 2 additions & 0 deletions lib/cache/CacheAdapter.ts
Expand Up @@ -4,4 +4,6 @@ export interface CacheAdapter {

set(name: string, data: any, origin: string): Promise<void>;

clear(): Promise<void>;

}
12 changes: 11 additions & 1 deletion lib/cache/FileCacheAdapter.ts
@@ -1,4 +1,5 @@
import { ensureDir, pathExists, readJSON, stat, writeJSON } from 'fs-extra';
import globby from 'globby';
import { ensureDir, pathExists, readJSON, stat, unlink, writeJSON } from 'fs-extra';
import { CacheAdapter } from './CacheAdapter';

export class FileCacheAdapter implements CacheAdapter {
Expand Down Expand Up @@ -28,6 +29,15 @@ export class FileCacheAdapter implements CacheAdapter {
await writeJSON(path, { modified, data, origin });
}

async clear(): Promise<void> {
const path = await this.path('*');
const files = await globby(path);

for (const file of files) {
await unlink(file);
}
}

private async path(name: string): Promise<string> {
await ensureDir(this.options.cacheDir);
return `${this.options.cacheDir}/${name}.json`;
Expand Down
4 changes: 4 additions & 0 deletions lib/cache/NullCacheAdapter.ts
Expand Up @@ -10,4 +10,8 @@ export class NullCacheAdapter implements CacheAdapter {
// ignore
}

async clear(): Promise<void> {
// ignore
}

}
14 changes: 14 additions & 0 deletions lib/cli.ts
@@ -0,0 +1,14 @@
import yargs from 'yargs';
import { CLIHelper } from './cli/CLIHelper';

require('yargonaut')
.style('blue')
.style('yellow', 'required')
.helpStyle('green')
.errorsStyle('red');

const args = CLIHelper.configure().parse(process.argv.slice(2)) as { _: string[] };

if (args._.length === 0) {
yargs.showHelp();
}
58 changes: 58 additions & 0 deletions lib/cli/CLIHelper.ts
@@ -0,0 +1,58 @@
import yargs, { Argv } from 'yargs';
import { ClearCacheCommand } from './ClearCacheCommand';
import { GenerateEntitiesCommand } from './GenerateEntitiesCommand';
import { MikroORM } from '../MikroORM';
import { Configuration, Utils } from '../utils';
import { CreateSchemaCommand } from './CreateSchemaCommand';
import { UpdateSchemaCommand } from './UpdateSchemaCommand';
import { DropSchemaCommand } from './DropSchemaCommand';

export class CLIHelper {

static getConfiguration(): Configuration {
return new Configuration(require(Utils.normalizePath(process.env.MIKRO_ORM_CLI || './cli-config')));
}

static async getORM(): Promise<MikroORM> {
const options = CLIHelper.getConfiguration();
return MikroORM.init(options);
}

static configure() {
return yargs
.scriptName('mikro-orm')
.version(require('../../package.json').version)
.usage('Usage: $0 <command> [options]')
.example('$0 schema:update --run', 'Runs schema synchronization')
.alias('v', 'version')
.alias('h', 'help')
.command(new ClearCacheCommand())
.command(new GenerateEntitiesCommand())
.command(new CreateSchemaCommand())
.command(new DropSchemaCommand())
.command(new UpdateSchemaCommand())
.recommendCommands()
.strict();
}

static configureSchemaCommand(args: Argv) {
args.option('r', {
alias: 'run',
type: 'boolean',
desc: 'Runs queries',
});
args.option('d', {
alias: 'dump',
type: 'boolean',
desc: 'Dumps all queries to console',
});
args.option('no-fk', {
type: 'boolean',
desc: 'Disable foreign key checks if possible',
default: true,
});

return args;
}

}
19 changes: 19 additions & 0 deletions lib/cli/ClearCacheCommand.ts
@@ -0,0 +1,19 @@
import { Arguments, CommandModule } from 'yargs';
import chalk from 'chalk';
import { CLIHelper } from './CLIHelper';

export class ClearCacheCommand implements CommandModule {

command = 'cache:clear';
describe = 'Clear metadata cache';

async handler(args: Arguments) {
const config = CLIHelper.getConfiguration();
const cache = config.getCacheAdapter();
await cache.clear();

// tslint:disable-next-line:no-console
console.log(chalk.green('Metadata cache was successfully cleared') + '\n');
}

}
38 changes: 38 additions & 0 deletions lib/cli/CreateSchemaCommand.ts
@@ -0,0 +1,38 @@
import yargs, { Arguments, Argv, CommandModule } from 'yargs';
import chalk from 'chalk';
import { CLIHelper } from './CLIHelper';

export type Options = { dump: boolean; run: boolean; noFk: boolean };

export class CreateSchemaCommand<U extends Options = Options> implements CommandModule<{}, U> {

command = 'schema:create';
describe = 'Create database schema based on current metadata';

builder(args: Argv) {
return CLIHelper.configureSchemaCommand(args) as Argv<U>;
}

async handler(args: Arguments<U>) {
if (!args.run && !args.dump) {
yargs.showHelp();
return;
}

const orm = await CLIHelper.getORM();
const generator = orm.getSchemaGenerator();

if (args.dump) {
const dump = await generator.getCreateSchemaSQL(args.noFk);
// tslint:disable-next-line:no-console
console.log(dump);
} else {
await generator.createSchema(args.noFk);
// tslint:disable-next-line:no-console
console.log(chalk.green('Schema successfully created'));
}

await orm.close(true);
}

}
38 changes: 38 additions & 0 deletions lib/cli/DropSchemaCommand.ts
@@ -0,0 +1,38 @@
import yargs, { Arguments, Argv, CommandModule } from 'yargs';
import chalk from 'chalk';
import { CLIHelper } from './CLIHelper';

export type Options = { dump: boolean; run: boolean; noFk: boolean };

export class DropSchemaCommand<U extends Options = Options> implements CommandModule<{}, U> {

command = 'schema:drop';
describe = 'Drop all tables based on current metadata';

builder(args: Argv) {
return CLIHelper.configureSchemaCommand(args) as Argv<U>;
}

async handler(args: Arguments<U>) {
if (!args.run && !args.dump) {
yargs.showHelp();
return;
}

const orm = await CLIHelper.getORM();
const generator = orm.getSchemaGenerator();

if (args.dump) {
const dump = await generator.getDropSchemaSQL(args.noFk);
// tslint:disable-next-line:no-console
console.log(dump);
} else {
await generator.dropSchema(args.noFk);
// tslint:disable-next-line:no-console
console.log(chalk.green('Schema successfully dropped') + '\n');
}

await orm.close(true);
}

}

0 comments on commit df103d6

Please sign in to comment.