relationId #65
This commit is contained in:
parent
8bb80c13a6
commit
14ef1e7ddb
@ -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 () {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}}>) {
|
||||
|
20
src/index.ts
20
src/index.ts
@ -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
|
||||
});
|
||||
|
||||
|
@ -25,7 +25,6 @@ export class ColumnInfo {
|
||||
numericScale: number | null = null;
|
||||
enumOptions: string | null = null;
|
||||
relations: RelationInfo[];
|
||||
|
||||
constructor() {
|
||||
this.relations = [];
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
24
test/integration/github-issues/65/entity/Post.ts
Normal file
24
test/integration/github-issues/65/entity/Post.ts
Normal 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[];
|
||||
|
||||
}
|
23
test/integration/github-issues/65/entity/PostAuthor.ts
Normal file
23
test/integration/github-issues/65/entity/PostAuthor.ts
Normal 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;
|
||||
}
|
21
test/integration/github-issues/65/entity/PostReader.ts
Normal file
21
test/integration/github-issues/65/entity/PostReader.ts
Normal 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[];
|
||||
}
|
@ -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')
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user