Skip to content

Commit

Permalink
feat(entity-generator): allow specifying schema
Browse files Browse the repository at this point in the history
Closes #1301
  • Loading branch information
B4nan committed Nov 27, 2021
1 parent 3cd49cd commit beb2993
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 29 deletions.
8 changes: 6 additions & 2 deletions packages/cli/src/commands/GenerateEntitiesCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Arguments, Argv, CommandModule } from 'yargs';
import type { EntityManager } from '@mikro-orm/knex';
import { CLIHelper } from '../CLIHelper';

export type Options = { dump: boolean; save: boolean; path: string };
export type Options = { dump: boolean; save: boolean; path: string; schema: string };

export class GenerateEntitiesCommand<U extends Options = Options> implements CommandModule<unknown, U> {

Expand All @@ -28,6 +28,10 @@ export class GenerateEntitiesCommand<U extends Options = Options> implements Com
type: 'string',
desc: 'Sets path to directory where to save entities',
});
args.option('schema', {
type: 'string',
desc: 'Generates entities only for given schema',
});

return args as unknown as Argv<U>;
}
Expand All @@ -43,7 +47,7 @@ export class GenerateEntitiesCommand<U extends Options = Options> implements Com
const orm = await CLIHelper.getORM(false);
const { EntityGenerator } = await import('@mikro-orm/entity-generator');
const generator = new EntityGenerator(orm.em as EntityManager);
const dump = await generator.generate({ save: args.save, baseDir: args.path });
const dump = await generator.generate({ save: args.save, baseDir: args.path, schema: args.schema });

if (args.dump) {
CLIHelper.dump(dump.join('\n\n'));
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ export interface ISchemaGenerator {
}

export interface IEntityGenerator {
generate(options?: { baseDir?: string; save?: boolean }): Promise<string[]>;
generate(options?: { baseDir?: string; save?: boolean; schema?: string }): Promise<string[]>;
}

type UmzugMigration = { path?: string; file: string };
Expand Down
8 changes: 5 additions & 3 deletions packages/entity-generator/src/EntityGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export class EntityGenerator {

constructor(private readonly em: EntityManager) { }

async generate(options: { baseDir?: string; save?: boolean } = {}): Promise<string[]> {
async generate(options: { baseDir?: string; save?: boolean; schema?: string } = {}): Promise<string[]> {
const baseDir = Utils.normalizePath(options.baseDir || this.config.get('baseDir') + '/generated-entities');
const schema = await DatabaseSchema.create(this.connection, this.platform, this.config);
schema.getTables().forEach(table => this.createEntity(table));
schema.getTables()
.filter(table => !options.schema || table.schema === options.schema)
.forEach(table => this.createEntity(table));

if (options.save) {
await ensureDir(baseDir);
Expand All @@ -31,7 +33,7 @@ export class EntityGenerator {

createEntity(table: DatabaseTable): void {
const meta = table.getEntityDeclaration(this.namingStrategy, this.helper);
this.sources.push(new SourceFile(meta, this.namingStrategy, this.platform, this.helper));
this.sources.push(new SourceFile(meta, this.namingStrategy, this.platform));
}

}
26 changes: 19 additions & 7 deletions packages/entity-generator/src/SourceFile.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Dictionary, EntityMetadata, EntityProperty, NamingStrategy, Platform } from '@mikro-orm/core';
import type { Dictionary, EntityMetadata, EntityOptions, EntityProperty, NamingStrategy, Platform } from '@mikro-orm/core';
import { ReferenceType, UnknownType, Utils } from '@mikro-orm/core';
import type { SchemaHelper } from '@mikro-orm/knex';

export class SourceFile {

Expand All @@ -9,8 +8,7 @@ export class SourceFile {

constructor(private readonly meta: EntityMetadata,
private readonly namingStrategy: NamingStrategy,
private readonly platform: Platform,
private readonly helper: SchemaHelper) { }
private readonly platform: Platform) { }

generate(): string {
this.coreImports.add('Entity');
Expand Down Expand Up @@ -57,9 +55,22 @@ export class SourceFile {
}

private getCollectionDecl() {
const needsCollection = this.meta.collection !== this.namingStrategy.classToTableName(this.meta.className);
const options: EntityOptions<unknown> = {};
const quote = (str: string) => `'${str}'`;

return needsCollection ? `{ collection: '${this.meta.collection}' }` : '';
if (this.meta.collection !== this.namingStrategy.classToTableName(this.meta.className)) {
options.tableName = quote(this.meta.collection);
}

if (this.meta.schema) {
options.schema = quote(this.meta.schema);
}

if (!Utils.hasObjectKeys(options)) {
return '';
}

return `{ ${Object.entries(options).map(([opt, val]) => `${opt}: ${val}`).join(', ')} }`;
}

private getPropertyDefinition(prop: EntityProperty, padLeft: number): string {
Expand Down Expand Up @@ -181,7 +192,8 @@ export class SourceFile {
}

private getForeignKeyDecoratorOptions(options: Dictionary, prop: EntityProperty) {
const className = this.namingStrategy.getClassName(prop.referencedTableName, '_');
const parts = prop.referencedTableName.split('.', 2);
const className = this.namingStrategy.getClassName(parts.length > 1 ? parts[1] : parts[0], '_');
this.entityImports.add(className);
options.entity = `() => ${className}`;

Expand Down
5 changes: 3 additions & 2 deletions packages/knex/src/schema/DatabaseTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class DatabaseTable {
getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper): EntityMetadata {
let name = namingStrategy.getClassName(this.name, '_');
name = name.match(/^\d/) ? 'E' + name : name;
const schema = new EntitySchema({ name, collection: this.name });
const schema = new EntitySchema({ name, collection: this.name, schema: this.schema });
const compositeFkIndexes: Dictionary<{ keyName: string }> = {};
const compositeFkUniques: Dictionary<{ keyName: string }> = {};

Expand Down Expand Up @@ -275,7 +275,8 @@ export class DatabaseTable {

private getPropertyType(namingStrategy: NamingStrategy, column: Column, fk?: ForeignKey): string {
if (fk) {
return namingStrategy.getClassName(fk.referencedTableName, '_');
const parts = fk.referencedTableName.split('.', 2);
return namingStrategy.getClassName(parts.length > 1 ? parts[1] : parts[0], '_');
}

return column.mappedType?.compareAsType() ?? 'unknown';
Expand Down
2 changes: 1 addition & 1 deletion tests/features/cli/GenerateEntitiesCommand.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('GenerateEntitiesCommand', () => {

const args = { option: jest.fn() };
cmd.builder(args as any);
expect(args.option.mock.calls.length).toBe(3);
expect(args.option.mock.calls.length).toBe(4);
expect(args.option.mock.calls[0][0]).toBe('s');
expect(args.option.mock.calls[0][1]).toMatchObject({ alias: 'save', type: 'boolean' });
expect(args.option.mock.calls[1][0]).toBe('d');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class Author2 {
"import { Entity, ManyToOne } from '@mikro-orm/core';
import { Author2 } from './Author2';
@Entity({ collection: 'author2_following' })
@Entity({ tableName: 'author2_following' })
export class Author2Following {
@ManyToOne({ entity: () => Author2, fieldName: 'author2_1_id', onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand Down Expand Up @@ -177,7 +177,7 @@ export class Book2 {
import { Book2 } from './Book2';
import { BookTag2 } from './BookTag2';
@Entity({ collection: 'book2_tags' })
@Entity({ tableName: 'book2_tags' })
export class Book2Tags {
@PrimaryKey()
Expand Down Expand Up @@ -391,7 +391,7 @@ export class Publisher2 {
import { Publisher2 } from './Publisher2';
import { Test2 } from './Test2';
@Entity({ collection: 'publisher2_tests' })
@Entity({ tableName: 'publisher2_tests' })
export class Publisher2Tests {
@PrimaryKey()
Expand Down Expand Up @@ -455,7 +455,7 @@ export class Test2 {
import { FooBar2 } from './FooBar2';
import { Test2 } from './Test2';
@Entity({ collection: 'test2_bars' })
@Entity({ tableName: 'test2_bars' })
export class Test2Bars {
@ManyToOne({ entity: () => Test2, onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand Down Expand Up @@ -490,7 +490,7 @@ export class User2 {
import { Car2 } from './Car2';
import { User2 } from './User2';
@Entity({ collection: 'user2_cars' })
@Entity({ tableName: 'user2_cars' })
export class User2Cars {
@ManyToOne({ entity: () => User2, onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand All @@ -505,7 +505,7 @@ export class User2Cars {
import { Sandwich } from './Sandwich';
import { User2 } from './User2';
@Entity({ collection: 'user2_sandwiches' })
@Entity({ tableName: 'user2_sandwiches' })
export class User2Sandwiches {
@ManyToOne({ entity: () => User2, onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand Down Expand Up @@ -593,7 +593,7 @@ export class Author2 {
"import { Entity, ManyToOne } from '@mikro-orm/core';
import { Author2 } from './Author2';
@Entity({ collection: 'author2_following' })
@Entity({ tableName: 'author2_following' })
export class Author2Following {
@ManyToOne({ entity: () => Author2, fieldName: 'author2_1_id', onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand Down Expand Up @@ -661,7 +661,7 @@ export class Book2 {
import { Book2 } from './Book2';
import { BookTag2 } from './BookTag2';
@Entity({ collection: 'book2_tags' })
@Entity({ tableName: 'book2_tags' })
export class Book2Tags {
@PrimaryKey()
Expand Down Expand Up @@ -843,7 +843,7 @@ export class Publisher2 {
import { Publisher2 } from './Publisher2';
import { Test2 } from './Test2';
@Entity({ collection: 'publisher2_tests' })
@Entity({ tableName: 'publisher2_tests' })
export class Publisher2Tests {
@PrimaryKey()
Expand Down Expand Up @@ -887,7 +887,7 @@ export class Test2 {
import { FooBar2 } from './FooBar2';
import { Test2 } from './Test2';
@Entity({ collection: 'test2_bars' })
@Entity({ tableName: 'test2_bars' })
export class Test2Bars {
@ManyToOne({ entity: () => Test2, onUpdateIntegrity: 'cascade', onDelete: 'cascade', primary: true })
Expand Down Expand Up @@ -977,7 +977,7 @@ export class Book3 {
import { Book3 } from './Book3';
import { BookTag3 } from './BookTag3';
@Entity({ collection: 'book3_tags' })
@Entity({ tableName: 'book3_tags' })
export class Book3Tags {
@PrimaryKey()
Expand Down Expand Up @@ -1027,7 +1027,7 @@ export class Publisher3 {
import { Publisher3 } from './Publisher3';
import { Test3 } from './Test3';
@Entity({ collection: 'publisher3_tests' })
@Entity({ tableName: 'publisher3_tests' })
export class Publisher3Tests {
@PrimaryKey()
Expand Down Expand Up @@ -1064,7 +1064,7 @@ exports[`EntityGenerator table name starting with number [mysql]: mysql-entity-d
Array [
"import { Entity, PrimaryKey } from '@mikro-orm/core';
@Entity({ collection: '123_table_name' })
@Entity({ tableName: '123_table_name' })
export class E123TableName {
@PrimaryKey()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`multiple connected schemas in postgres generate entities for given schema only 1`] = `
Array [
"import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { Author } from './Author';
@Entity({ schema: 'n2' })
export class Book {
@PrimaryKey()
id!: number;
@Property({ length: 255, nullable: true })
name?: string;
@ManyToOne({ entity: () => Author, onUpdateIntegrity: 'cascade', onDelete: 'cascade', nullable: true })
author?: Author;
@ManyToOne({ entity: () => Book, onUpdateIntegrity: 'cascade', onDelete: 'set null', nullable: true })
basedOn?: Book;
}
",
]
`;
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,10 @@ describe('multiple connected schemas in postgres', () => {
});
});

test('generate entities for given schema only', async () => {
const generator = orm.getEntityGenerator();
const entities = await generator.generate({ schema: 'n2' });
expect(entities).toMatchSnapshot();
});

});

0 comments on commit beb2993

Please sign in to comment.