From fcf593e3ae61cb5e6e8517d49305aaae90c645d7 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 23 Apr 2017 23:41:49 +0200 Subject: [PATCH] added relations --- src/Engine.ts | 3 ++ src/drivers/AbstractDriver.ts | 8 ++-- src/drivers/MssqlDriver.ts | 86 +++++++++++++++++++++++++++++----- src/entity.mst | 8 +++- src/models/ColumnInfo.ts | 3 +- src/models/DatabaseModel.ts | 8 +++- src/models/RelationInfo.ts | 11 ++--- src/models/RelationTempInfo.ts | 8 ++++ 8 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 src/models/RelationTempInfo.ts diff --git a/src/Engine.ts b/src/Engine.ts index 1df25ea..0f1fd20 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -26,7 +26,9 @@ export class Engine { private createModelFromMetadata(databaseModel: DatabaseModel) { let templatePath = path.resolve(__dirname,'entity.mst') let template = fs.readFileSync(templatePath,'UTF-8'); + //TODO:get results path to argvs, check if dir exists before let resultPath = path.resolve(__dirname,'../results') + //TODO:Refactor to new method fs.writeFileSync(path.resolve(resultPath,'tsconfig.json'),`{"compilerOptions": { "lib": ["es5", "es6"], "target": "es6", @@ -36,6 +38,7 @@ export class Engine { "experimentalDecorators": true, "sourceMap": true }}`,{encoding:'UTF-8',flag:'w'}); + //TODO:Create ormconfig file databaseModel.entities.forEach(element => { let resultFilePath = path.resolve(resultPath,element.EntityName+'.ts'); let rendered = Mustache.render(template, element); diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index d1b3958..b9ff832 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -8,16 +8,16 @@ export abstract class AbstractDriver { dbModel.entities = await this.GetAllTables(); await this.GetCoulmnsFromEntity(dbModel.entities); await this.GetIndexesFromEntity(dbModel.entities); - dbModel.relations = await this.GetRelations(); + dbModel.entities = await this.GetRelations(dbModel.entities); await this.DisconnectFromServer(); this.FindPrimaryColumnsFromIndexes(dbModel) return dbModel; } abstract async ConnectToServer(database:string,server:string,port:number,user:string,password:string); abstract async GetAllTables(): Promise - abstract async GetCoulmnsFromEntity(entities: EntityInfo[]); - abstract async GetIndexesFromEntity(entities: EntityInfo[]); - abstract async GetRelations():Promise; + abstract async GetCoulmnsFromEntity(entities: EntityInfo[]):Promise; + abstract async GetIndexesFromEntity(entities: EntityInfo[]):Promise; + abstract async GetRelations(entities: EntityInfo[]):Promise; abstract async FindPrimaryColumnsFromIndexes(dbModel:DatabaseModel); abstract async DisconnectFromServer(); } \ No newline at end of file diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 1f171d3..dbc25a8 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -32,7 +32,7 @@ export class MssqlDriver extends AbstractDriver { }) return ret; } - async GetCoulmnsFromEntity(entities: EntityInfo[]) { + async GetCoulmnsFromEntity(entities: EntityInfo[]): Promise { let request = new MSSQL.Request(this.Connection) let response: { TABLE_NAME: string, COLUMN_NAME: string, COLUMN_DEFAULT: string, IS_NULLABLE: string, DATA_TYPE: string, CHARACTER_MAXIMUM_LENGTH: number, @@ -114,9 +114,10 @@ export class MssqlDriver extends AbstractDriver { colInfo.numericPrecision=resp.NUMERIC_PRECISION colInfo.numericScale=resp.NUMERIC_SCALE break; - // case "xml": - // colInfo.ts_type = "number" - // break; + case "xml": + colInfo.ts_type = "string" + colInfo.sql_type = "text" + break; default: console.error("Unknown column type:" + resp.DATA_TYPE); break; @@ -127,7 +128,7 @@ export class MssqlDriver extends AbstractDriver { }) return entities; } - async GetIndexesFromEntity(entities: EntityInfo[]) { + async GetIndexesFromEntity(entities: EntityInfo[]): Promise { let request = new MSSQL.Request(this.Connection) let response: { TableName: string, IndexName: string, ColumnName: string, is_unique: number, @@ -181,7 +182,7 @@ ORDER BY }) return entities; } - async GetRelations(): Promise { + async GetRelations(entities: EntityInfo[]): Promise { let request = new MSSQL.Request(this.Connection) let response: { TableWithForeignKey: string, FK_PartNo: number, ForeignKeyColumn: string, @@ -212,25 +213,86 @@ where fk.is_disabled=0 and fk.is_ms_shipped=0 order by TableWithForeignKey, FK_PartNo`); - let relations: RelationInfo[] = []; + let relationsTemp: RelationTempInfo[] = []; response.forEach((resp) => { - let rels = relations.find((val) => { + let rels = relationsTemp.find((val) => { return val.object_id == resp.object_id; }) if (rels == undefined) { - rels = {}; + rels = {}; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = resp.onDelete; rels.object_id = resp.object_id; rels.ownerTable = resp.TableWithForeignKey; - rels.referencedTableName = resp.TableReferenced; - relations.push(rels); + rels.referencedTable = resp.TableReferenced; + relationsTemp.push(rels); } rels.ownerColumnsNames.push(resp.ForeignKeyColumn); rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); }) - return relations; + relationsTemp.forEach( (relationTmp)=>{ + let ownerEntity = entities.find((entitity)=>{ + return entitity.EntityName==relationTmp.ownerTable; + }) + if (!ownerEntity){ + console.error(`Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.ownerTable}.`) + return; + } + let referencedEntity = entities.find((entitity)=>{ + return entitity.EntityName==relationTmp.referencedTable; + }) + if (!referencedEntity){ + console.error(`Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.referencedTable}.`) + return; + } + let ownerColumn = ownerEntity.Columns.find((column)=>{ + return column.name==relationTmp.ownerColumnsNames[0]; + }) + if(!ownerColumn){ + console.error(`Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.ownerTable}.${ownerColumn}.`) + return; + } + let relatedColumn = referencedEntity.Columns.find((column)=>{ + return column.name==relationTmp.referencedColumnsNames[0]; + }) + if(!relatedColumn){ + console.error(`Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.referencedTable}.${relatedColumn}.`) + return; + } + let ownColumn:ColumnInfo = ownerColumn; + let isOneToMany:boolean; + isOneToMany=false; + let index = ownerEntity.Indexes.find( + (index)=>{ + return index.isUnique && index.columns.some(col=>{ + return col.name==ownColumn.name + }) + } + ) + if (!index){ + isOneToMany=true; + }else{ + isOneToMany=false; + } + + ownerColumn.relation={ + actionOnDelete:relationTmp.actionOnDelete, + isOwner:true, + relatedColumn:relatedColumn.name, + relatedTable:relationTmp.referencedTable, + relationType:isOneToMany?"OneToMany":"OneToOne" + } + relatedColumn.relation={ + actionOnDelete:relationTmp.actionOnDelete, + isOwner:false, + relatedColumn:ownerColumn.name, + relatedTable:relationTmp.ownerTable, + relationType:isOneToMany?"ManyToOne":"OneToOne" + } + + }) + return entities; } async DisconnectFromServer() { if (this.Connection) diff --git a/src/entity.mst b/src/entity.mst index b973030..e8063b4 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,4 +1,6 @@ -import {Index,Entity, PrimaryColumn, Column, OneToMany, ManyToOne, JoinTable} from "typeorm"; +import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinTable} from "typeorm"; +{{#Columns}}{{#relation}}import{ {{relatedTable}} } from "./{{relatedTable}}"; +{{/relation}}{{/Columns}} @Entity() {{#Indexes}}{{^isPrimaryKey}}@Index("{{name}}",[{{#columns}}"{{name}}",{{/columns}}]{{#isUnique}},{unique:true}{{/isUnique}}) @@ -6,7 +8,9 @@ import {Index,Entity, PrimaryColumn, Column, OneToMany, ManyToOne, JoinTable} fr {{#Columns}} - @Column("{{sql_type}}",{ {{#is_nullable}}nullable:true,{{/is_nullable}}{{#char_max_lenght}}length:{{char_max_lenght}},{{/char_max_lenght}}{{#default}}default:{{default}},{{/default}}{{#numericPrecision}}precision:{numericPrecision},{{/numericPrecision}}{{#numericScale}}scale:{{numericScale}},{{/numericScale}}{{#isPrimary}}primary:{{isPrimary}},{{/isPrimary}}}) + @Column("{{sql_type}}",{ {{#is_nullable}}nullable:true,{{/is_nullable}}{{#char_max_lenght}}length:{{char_max_lenght}},{{/char_max_lenght}}{{#default}}default:{{default}},{{/default}}{{#numericPrecision}}precision:{numericPrecision},{{/numericPrecision}}{{#numericScale}}scale:{{numericScale}},{{/numericScale}}{{#isPrimary}}primary:{{isPrimary}},{{/isPrimary}}}){{#relation}} + @{{relationType}}(type=>{{relatedTable}},x=>x.{{relatedColumn}}){{#isOwner}} + @JoinTable(){{/isOwner}}{{/relation}} {{name}}:{{ts_type}}; {{/Columns}} } \ No newline at end of file diff --git a/src/models/ColumnInfo.ts b/src/models/ColumnInfo.ts index 228d2cd..1cacc36 100644 --- a/src/models/ColumnInfo.ts +++ b/src/models/ColumnInfo.ts @@ -11,7 +11,8 @@ interface ColumnInfo { char_max_lenght: number|null, isPrimary:boolean, numericPrecision:number|null, - numericScale:number|null + numericScale:number|null, + relation:RelationInfo } diff --git a/src/models/DatabaseModel.ts b/src/models/DatabaseModel.ts index 5931883..a4ef6e3 100644 --- a/src/models/DatabaseModel.ts +++ b/src/models/DatabaseModel.ts @@ -1,4 +1,8 @@ -interface DatabaseModel{ +interface DatabaseModel { entities: EntityInfo[], - relations: RelationInfo[] + config: { + cascadeInsert: boolean, + cascadeUpdate: boolean, + cascadeRemove: boolean, + } } \ No newline at end of file diff --git a/src/models/RelationInfo.ts b/src/models/RelationInfo.ts index edf02fa..f9801aa 100644 --- a/src/models/RelationInfo.ts +++ b/src/models/RelationInfo.ts @@ -1,8 +1,7 @@ -interface RelationInfo{ - ownerTable:string, - ownerColumnsNames:string[], - referencedTableName:string, - referencedColumnsNames:string[], +interface RelationInfo { + isOwner: boolean, + relationType: "OneToOne", "OneToMany", "ManyToOne" + relatedTable: string, + relatedColumn: string, actionOnDelete:"RESTRICT"|"CASCADE"|"SET NULL", - object_id:number } \ No newline at end of file diff --git a/src/models/RelationTempInfo.ts b/src/models/RelationTempInfo.ts new file mode 100644 index 0000000..81f00de --- /dev/null +++ b/src/models/RelationTempInfo.ts @@ -0,0 +1,8 @@ +interface RelationTempInfo{ + ownerTable:string, + ownerColumnsNames:string[], + referencedTable:string, + referencedColumnsNames:string[], + actionOnDelete:"RESTRICT"|"CASCADE"|"SET NULL", + object_id:number +} \ No newline at end of file