Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add basic CLI tool #102

Merged
merged 1 commit into from Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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;

}
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);
}

}