relationId #65

This commit is contained in:
Kononnable 2018-06-17 20:46:50 +02:00
parent 8bb80c13a6
commit 14ef1e7ddb
15 changed files with 185 additions and 64 deletions

View File

@ -24,6 +24,7 @@ gulp.task('clean', function () {
gulp.task('prettier', function () {
return gulp.src('.prettierrc')
.pipe(shell(['prettier ./src/**/*.ts --write']))
.pipe(shell(['prettier ./src/*.ts --write']))
});
gulp.task('pre-commit', ['prettier'], function () {

View File

@ -2,7 +2,11 @@ import { RelationInfo } from "./models/RelationInfo";
import { DatabaseModel } from "./models/DatabaseModel";
export abstract class AbstractNamingStrategy {
abstract relationName(columnName: string, relation: RelationInfo, dbModel: DatabaseModel): string;
abstract relationName(
columnName: string,
relation: RelationInfo,
dbModel: DatabaseModel
): string;
abstract entityName(entityName: string): string;

View File

@ -22,7 +22,8 @@ export class Engine {
this.Options.password,
this.Options.schemaName,
this.Options.ssl,
this.Options.namingStrategy
this.Options.namingStrategy,
this.Options.relationIds
);
if (dbModel.entities.length > 0) {
this.createModelFromMetadata(dbModel);
@ -42,7 +43,8 @@ export class Engine {
password: string,
schemaName: string,
ssl: boolean,
namingStrategy: AbstractNamingStrategy
namingStrategy: AbstractNamingStrategy,
relationIds: boolean
): Promise<DatabaseModel> {
return await this.driver.GetDataFromServer(
database,
@ -52,7 +54,8 @@ export class Engine {
password,
schemaName,
ssl,
namingStrategy
namingStrategy,
relationIds
);
}
private createModelFromMetadata(databaseModel: DatabaseModel) {
@ -276,4 +279,5 @@ export interface EngineOptions {
lazy: boolean;
constructor: boolean;
namingStrategy: AbstractNamingStrategy;
relationIds: boolean;
}

View File

@ -4,54 +4,64 @@ import { DatabaseModel } from "./models/DatabaseModel";
export class NamingStrategy extends AbstractNamingStrategy {
relationName(
columnOldName:string,
columnOldName: string,
relation: RelationInfo,
dbModel:DatabaseModel
dbModel: DatabaseModel
): string {
let isRelationToMany = relation.isOneToMany || relation.isManyToMany
let isRelationToMany = relation.isOneToMany || relation.isManyToMany;
let ownerEntity = dbModel.entities.filter(v => {
return v.EntityName==relation.ownerTable
})[0]
return v.EntityName == relation.ownerTable;
})[0];
let referencedEntity = dbModel.entities.filter(v => {
return v.EntityName == relation.relatedTable
})[0]
return v.EntityName == relation.relatedTable;
})[0];
let columnName = columnOldName[0].toLowerCase()+ columnOldName.substring(1,columnOldName.length);
if ( columnName.endsWith("id")) {
columnName = columnName.substring(0, columnName.lastIndexOf("id"));
let columnName =
columnOldName[0].toLowerCase() +
columnOldName.substring(1, columnOldName.length);
if (
columnName
.toLowerCase()
.endsWith(
"id"
) /*&& !ownerEntity.Columns.some(x=>x.tsName==columnName && x.isPrimary)*/
) {
columnName = columnName.substring(
0,
columnName.toLowerCase().lastIndexOf("id")
);
}
if (!isNaN(parseInt(columnName[columnName.length-1]))) {
let num = columnName[columnName.length-1]
columnName = columnName.substring(0, columnName.length - 1)
columnName += (isRelationToMany ? "s" : "")+num.toString();
} else {
columnName += isRelationToMany ? "s" : "";
if (!isNaN(parseInt(columnName[columnName.length - 1]))) {
columnName = columnName.substring(0, columnName.length - 1);
}
if (!isNaN(parseInt(columnName[columnName.length - 1]))) {
columnName = columnName.substring(0, columnName.length - 1);
}
columnName += isRelationToMany ? "s" : "";
if (relation.relationType!="ManyToMany") {
if (columnOldName!=columnName) {
if (!relation.isOwner) {
if (ownerEntity.Columns.some(v => v.tsName == columnName)) {
columnName = columnName + "_"
for (let i = 2; i <= ownerEntity.Columns.length; i++) {
columnName = columnName.substring(0, columnName.length - 1) + i.toString();
if (ownerEntity.Columns.every(v => v.tsName != columnName)) break;
}
}
} else {
if (referencedEntity.Columns.some(v => v.tsName == columnName)) {
columnName = columnName + "_"
for (let i = 2; i <= referencedEntity.Columns.length; i++) {
columnName = columnName.substring(0, columnName.length - 1) + i.toString();
if (referencedEntity.Columns.every(v => v.tsName != columnName)) break;
}
if (
relation.relationType != "ManyToMany" &&
columnOldName != columnName
) {
if (ownerEntity.Columns.some(v => v.tsName == columnName)) {
columnName = columnName + "_";
for (let i = 2; i <= ownerEntity.Columns.length; i++) {
columnName =
columnName.substring(
0,
columnName.length - i.toString().length
) + i.toString();
if (
ownerEntity.Columns.every(
v =>
v.tsName != columnName ||
columnName == columnOldName
)
)
break;
}
}
}
}
return columnName;
}

View File

@ -158,6 +158,7 @@ export abstract class AbstractDriver {
"varbinary"
];
namingStrategy: AbstractNamingStrategy;
generateRelationsIds: boolean;
FindManyToManyRelations(dbModel: DatabaseModel) {
let manyToManyEntities = dbModel.entities.filter(entity => {
@ -238,8 +239,10 @@ export abstract class AbstractDriver {
password: string,
schema: string,
ssl: boolean,
namingStrategy: AbstractNamingStrategy
namingStrategy: AbstractNamingStrategy,
relationIds: boolean
): Promise<DatabaseModel> {
this.generateRelationsIds = relationIds;
let dbModel = <DatabaseModel>{};
this.namingStrategy = namingStrategy;
await this.ConnectToServer(database, server, port, user, password, ssl);
@ -259,9 +262,9 @@ export abstract class AbstractDriver {
}
private ApplyNamingStrategy(dbModel: DatabaseModel) {
this.changeColumnNames(dbModel);
this.changeEntityNames(dbModel);
this.changeRelationNames(dbModel);
this.changeEntityNames(dbModel);
this.changeColumnNames(dbModel);
}
abstract async ConnectToServer(
@ -386,6 +389,7 @@ export abstract class AbstractDriver {
ownerRelation.relationType = isOneToMany
? "ManyToOne"
: "OneToOne";
ownerRelation.relationIdField = this.generateRelationsIds;
let columnName = ownerEntity.EntityName;
if (
@ -394,8 +398,10 @@ export abstract class AbstractDriver {
columnName = columnName + "_";
for (let i = 2; i <= referencedEntity.Columns.length; i++) {
columnName =
columnName.substring(0, columnName.length - 1) +
i.toString();
columnName.substring(
0,
columnName.length - i.toString().length
) + i.toString();
if (
referencedEntity.Columns.every(
v => v.tsName != columnName

View File

@ -1,4 +1,4 @@
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm";
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
{{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}";
{{/each}}
@ -28,7 +28,11 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Man
{{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../sqlName}}'}){{/if}}{{/isOwner}}
{{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) "[]")}};
{{else}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) ' | null')}};
{{/if}}{{/relations}}
{{/if}}
{{#if relationIdField }}
@RelationId(({{../../EntityName}}: {{../../EntityName}}) => {{../../EntityName}}.{{toPropertyName ../tsName}})
{{toPropertyName ../tsName}}Id: {{#if isOneToOne}}{{toLazy ../ts_type}}{{else}}{{toLazy (concat ../ts_type "[]")}}{{/if}};{{/if}}{{/relations}}
{{/Columns}}
{{#if GenerateConstructor}}
constructor(init?: Partial<{{toEntityName EntityName}}>) {

View File

@ -87,7 +87,12 @@ var argv = Yargs.usage(
default: false
})
.option("namingStrategy", {
describe: "Use custom naming strategy",
describe: "Use custom naming strategy"
})
.option("relationIds", {
describe: "Generate RelationId fields",
boolean: true,
default: false
})
.option("generateConstructor", {
describe: "Generate constructor allowing partial initialization",
@ -118,7 +123,7 @@ switch (argv.e) {
standardUser = "root";
break;
case "mariadb":
driver = new MysqlDriver();
driver = new MariaDbDriver();
standardPort = 3306;
standardUser = "root";
break;
@ -134,17 +139,15 @@ switch (argv.e) {
default:
TomgUtils.LogError("Database engine not recognized.", false);
throw new Error("Database engine not recognized.");
}
let namingStrategy: AbstractNamingStrategy;
if (argv.namingStrategy && argv.namingStrategy!='') {
if (argv.namingStrategy && argv.namingStrategy != "") {
let req = require(argv.namingStrategy);
namingStrategy= new req.NamingStrategy();
namingStrategy = new req.NamingStrategy();
} else {
namingStrategy= new NamingStrategy();
namingStrategy = new NamingStrategy();
}
debugger;
let engine = new Engine(driver, {
host: argv.h,
port: parseInt(argv.p) || standardPort,
@ -161,6 +164,7 @@ let engine = new Engine(driver, {
convertCaseProperty: argv.cp,
lazy: argv.lazy,
constructor: argv.generateConstructor,
relationIds: argv.relationIds,
namingStrategy: namingStrategy
});

View File

@ -25,7 +25,6 @@ export class ColumnInfo {
numericScale: number | null = null;
enumOptions: string | null = null;
relations: RelationInfo[];
constructor() {
this.relations = [];
}

View File

@ -7,6 +7,7 @@ export class RelationInfo {
ownerColumn: string;
actionOnDelete: "RESTRICT" | "CASCADE" | "SET NULL" | null;
actionOnUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | null;
relationIdField: boolean = false;
get isOneToMany(): boolean {
return this.relationType == "OneToMany";
@ -14,4 +15,10 @@ export class RelationInfo {
get isManyToMany(): boolean {
return this.relationType == "ManyToMany";
}
get isOneToOne(): boolean {
return this.relationType == "OneToOne";
}
get isManyToOne(): boolean {
return this.relationType == "OneToOne";
}
}

View File

@ -95,7 +95,7 @@ describe('MssqlDriver', function () {
ts_type: 'number',
enumOptions: null,
is_unique:false,
relations: <RelationInfo[]>[]
relations: <RelationInfo[]>[],
})
let result = await driver.GetCoulmnsFromEntity(entities, 'schema');
expect(result).to.be.deep.equal(expected)

View File

@ -0,0 +1,24 @@
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm";
import { PostAuthor } from "./PostAuthor";
import { PostReader } from "./PostReader";
@Entity("Post")
export class Post {
@Column("int",{
nullable:false,
primary:true,
name:"Id"
})
Id:number;
@OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id)
postAuthor: PostAuthor;
@OneToMany(type => PostReader, PostReader => PostReader.Id)
postReaders: PostReader[];
}

View File

@ -0,0 +1,23 @@
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
import { Post } from "./Post";
@Entity("PostAuthor")
export class PostAuthor {
@Column("int",{
nullable:false,
primary:true,
name:"Id"
})
Id:number;
@OneToOne(type => Post, Post => Post.Id)
@JoinColumn()
post:Post;
@RelationId((postAuthor: PostAuthor) => postAuthor.post)
postId: number;
}

View File

@ -0,0 +1,21 @@
import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm";
import { Post } from "./Post";
@Entity("PostReader")
export class PostReader {
@Column("int",{
nullable:false,
primary:true,
name:"Id"
})
Id:number;
@ManyToOne(type => Post, Post => Post.Id)
@JoinColumn()
post:Post;
@RelationId((postReader: PostReader) => postReader.post)
postId: number[];
}

View File

@ -78,6 +78,14 @@ describe("GitHub issues", async function () {
break;
}
switch (folder) {
case '65':
engine.Options.relationIds = true;
break;
default:
break;
}
await engine.createModelFromDatabase()
let filesGenPath = path.resolve(resultsPath, 'entities')

View File

@ -67,7 +67,8 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin
convertCaseProperty: 'none',
lazy: false,
constructor: false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds:false
});
conn = await createConnection(connOpt)
@ -134,7 +135,8 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st
convertCaseProperty: 'none',
lazy: false,
constructor:false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds: false
});
conn = await createConnection(connOpt)
@ -193,7 +195,8 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri
convertCaseProperty: 'none',
lazy: false,
constructor:false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds: false
});
conn = await createConnection(connOpt)
@ -250,7 +253,8 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin
convertCaseProperty: 'none',
lazy: false,
constructor:false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds: false
});
return engine;
@ -300,7 +304,8 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str
convertCaseProperty: 'none',
lazy: false,
constructor:false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds: false
});
@ -353,7 +358,8 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st
convertCaseProperty: 'none',
lazy: false,
constructor:false,
namingStrategy: namingStrategy
namingStrategy: namingStrategy,
relationIds: false
});
return engine;