From 130c68245830e303af5563f1c05c6771e9996d3c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 3 Oct 2019 23:34:48 +0200 Subject: [PATCH] mysql relations rewrite --- src/drivers/AbstractDriver.ts | 198 ++++++++++++++++---------------- src/drivers/MssqlDriver.ts | 200 +++++++++++++++++---------------- src/drivers/MysqlDriver.ts | 57 ++++++---- src/drivers/OracleDriver.ts | 92 +++++++-------- src/drivers/PostgresDriver.ts | 158 +++++++++++++------------- src/drivers/SqliteDriver.ts | 90 +++++++-------- src/models/RelationInternal.ts | 12 ++ 7 files changed, 419 insertions(+), 388 deletions(-) create mode 100644 src/models/RelationInternal.ts diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index b34d1e4..e8a94f7 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -3,15 +3,16 @@ import { WithPrecisionColumnType, WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; +import { JoinColumnOptions } from "typeorm"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import EntityInfo from "../oldModels/EntityInfo"; import RelationInfo from "../oldModels/RelationInfo"; import ColumnInfo from "../oldModels/ColumnInfo"; import IConnectionOptions from "../IConnectionOptions"; -import IndexInfo from "../oldModels/IndexInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import { Entity } from "../models/Entity"; +import { RelationInternal } from "../models/RelationInternal"; +import { Relation } from "../models/Relation"; export default abstract class AbstractDriver { public abstract standardPort: number; @@ -180,12 +181,11 @@ export default abstract class AbstractDriver { sqlEscapedSchema, connectionOptons.databaseName ); - // TODO: Uncomment - // dbModel = await this.GetRelations( - // dbModel, - // sqlEscapedSchema, - // connectionOptons.databaseName - // ); + dbModel = await this.GetRelations( + dbModel, + sqlEscapedSchema, + connectionOptons.databaseName + ); await this.DisconnectFromServer(); // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); // AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); @@ -215,20 +215,20 @@ export default abstract class AbstractDriver { } public static GetRelationsFromRelationTempInfo( - relationsTemp: RelationTempInfo[], - entities: EntityInfo[] + relationsTemp: RelationInternal[], + entities: Entity[] ) { relationsTemp.forEach(relationTmp => { - if (relationTmp.ownerColumnsNames.length > 1) { + if (relationTmp.ownerColumns.length > 1) { const relatedTable = entities.find( - entity => entity.tsEntityName === relationTmp.ownerTable + entity => entity.tscName === relationTmp.ownerTable.tscName )!; if ( - relatedTable.Columns.length !== - relationTmp.ownerColumnsNames.length * 2 + relatedTable.columns.length !== + relationTmp.ownerColumns.length * 2 ) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} wasn't generated correctly - complex relationships aren't supported yet.`, + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, false ); return; @@ -236,12 +236,13 @@ export default abstract class AbstractDriver { const secondRelation = relationsTemp.find( relation => - relation.ownerTable === relatedTable.tsEntityName && - relation.referencedTable !== relationTmp.referencedTable + relation.ownerTable.tscName === relatedTable.tscName && + relation.relatedTable.tscName !== + relationTmp.relatedTable.tscName )!; if (!secondRelation) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} wasn't generated correctly - complex relationships aren't supported yet.`, + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, false ); return; @@ -249,133 +250,126 @@ export default abstract class AbstractDriver { } const ownerEntity = entities.find( - entitity => entitity.tsEntityName === relationTmp.ownerTable + entity => entity.tscName === relationTmp.ownerTable.tscName ); if (!ownerEntity) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.ownerTable}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity model ${relationTmp.ownerTable.sqlName}.` ); return; } const referencedEntity = entities.find( - entitity => - entitity.tsEntityName === relationTmp.referencedTable + entity => entity.tscName === relationTmp.relatedTable.tscName ); if (!referencedEntity) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.referencedTable}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity model ${relationTmp.relatedTable.sqlName}.` ); return; } for ( let relationColumnIndex = 0; - relationColumnIndex < relationTmp.ownerColumnsNames.length; + relationColumnIndex < relationTmp.ownerColumns.length; relationColumnIndex++ ) { - const ownerColumn = ownerEntity.Columns.find( + const ownerColumn = ownerEntity.columns.find( column => - column.tsName === - relationTmp.ownerColumnsNames[relationColumnIndex] + column.tscName === + relationTmp.ownerColumns[relationColumnIndex] ); if (!ownerColumn) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.ownerTable}.${ownerColumn}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity column ${relationTmp.ownerTable.sqlName}.${ownerColumn}.` ); return; } - const relatedColumn = referencedEntity.Columns.find( + const relatedColumn = referencedEntity.columns.find( column => - column.tsName === - relationTmp.referencedColumnsNames[relationColumnIndex] + column.tscName === + relationTmp.relatedColumns[relationColumnIndex] ); if (!relatedColumn) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.referencedTable}.${relatedColumn}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity column ${relationTmp.relatedTable.sqlName}.${relatedColumn}.` ); return; } let isOneToMany: boolean; isOneToMany = false; - const index = ownerEntity.Indexes.find( + const index = ownerEntity.indices.find( ind => - ind.isUnique && + ind.options.unique && ind.columns.length === 1 && - ind.columns[0].name === ownerColumn!.tsName + ind.columns[0] === ownerColumn!.tscName ); isOneToMany = !index; - const ownerRelation = new RelationInfo(); - ownerRelation.actionOnDelete = relationTmp.actionOnDelete; - ownerRelation.actionOnUpdate = relationTmp.actionOnUpdate; - ownerRelation.isOwner = true; - ownerRelation.relatedColumn = relatedColumn.tsName.toLowerCase(); - ownerRelation.relatedTable = relationTmp.referencedTable; - ownerRelation.ownerTable = relationTmp.ownerTable; - ownerRelation.relationType = isOneToMany - ? "ManyToOne" - : "OneToOne"; - - let columnName = ownerEntity.tsEntityName; - if ( - referencedEntity.Columns.some(v => v.tsName === columnName) - ) { - columnName += "_"; - for (let i = 2; i <= referencedEntity.Columns.length; i++) { - columnName = - columnName.substring( - 0, - columnName.length - i.toString().length - ) + i.toString(); - if ( - referencedEntity.Columns.every( - v => v.tsName !== columnName - ) - ) { - break; + const ownerRelation: Relation = { + fieldName: AbstractDriver.findNameForNewField( + relationTmp.relatedTable.tscName, + ownerEntity + ), + joinColumnOptions: relationTmp.ownerColumns.map( + (v, idx) => { + const retVal: JoinColumnOptions = { + name: v, + referencedColumnName: + relationTmp.relatedColumns[idx] + }; + return retVal; } - } - } + ), + relatedField: AbstractDriver.findNameForNewField( + relationTmp.ownerTable.tscName, + relationTmp.relatedTable + ), + relatedTable: relationTmp.relatedTable.tscName, + relationOptions: { + onDelete: relationTmp.onDelete, + onUpdate: relationTmp.onUpdate + }, + relationType: isOneToMany ? "OneToMany" : "OneToOne" + }; + const relatedRelation: Relation = { + fieldName: ownerRelation.relatedField, + relatedField: ownerRelation.fieldName, + relatedTable: relationTmp.ownerTable.tscName, + relationOptions: ownerRelation.relationOptions, + relationType: isOneToMany ? "ManyToOne" : "OneToOne" + }; - ownerRelation.ownerColumn = columnName; - ownerColumn.relations.push(ownerRelation); - if (isOneToMany) { - const col = new ColumnInfo(); - col.tsName = columnName; - const referencedRelation = new RelationInfo(); - col.relations.push(referencedRelation); - referencedRelation.actionOnDelete = - relationTmp.actionOnDelete; - referencedRelation.actionOnUpdate = - relationTmp.actionOnUpdate; - referencedRelation.isOwner = false; - referencedRelation.relatedColumn = ownerColumn.tsName; - referencedRelation.relatedTable = relationTmp.ownerTable; - referencedRelation.ownerTable = relationTmp.referencedTable; - referencedRelation.ownerColumn = relatedColumn.tsName; - referencedRelation.relationType = "OneToMany"; - referencedEntity.Columns.push(col); - } else { - const col = new ColumnInfo(); - col.tsName = columnName; - const referencedRelation = new RelationInfo(); - col.relations.push(referencedRelation); - referencedRelation.actionOnDelete = - relationTmp.actionOnDelete; - referencedRelation.actionOnUpdate = - relationTmp.actionOnUpdate; - referencedRelation.isOwner = false; - referencedRelation.relatedColumn = ownerColumn.tsName; - referencedRelation.relatedTable = relationTmp.ownerTable; - referencedRelation.ownerTable = relationTmp.referencedTable; - referencedRelation.ownerColumn = relatedColumn.tsName; - referencedRelation.relationType = "OneToOne"; - referencedEntity.Columns.push(col); - } + ownerEntity.relations.push(ownerRelation); + relationTmp.relatedTable.relations.push(relatedRelation); } }); return entities; } + private static findNameForNewField(_fieldName: string, entity: Entity) { + let fieldName = _fieldName; + const validNameCondition = + entity.columns.every(v => v.tscName !== fieldName) && + entity.relations.every(v => v.fieldName !== fieldName); + if (validNameCondition) { + fieldName += "_"; + for ( + let i = 2; + i <= entity.columns.length + entity.relations.length; + i++ + ) { + fieldName = + fieldName.substring( + 0, + fieldName.length - i.toString().length + ) + i.toString(); + if (validNameCondition) { + break; + } + } + } + return fieldName; + } + public abstract async GetCoulmnsFromEntity( entities: Entity[], schema: string, @@ -389,10 +383,10 @@ export default abstract class AbstractDriver { ): Promise; public abstract async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise; + ): Promise; public static FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { dbModel.forEach(entity => { diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index e59ee8e..057357b 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -303,107 +303,109 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { - const request = new MSSQL.Request(this.Connection); - const response: { - TableWithForeignKey: string; - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - objectId: number; - }[] = []; - await Promise.all( - dbNames.split(",").map(async dbName => { - await this.UseDB(dbName); - const resp: { - TableWithForeignKey: string; - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - objectId: number; - }[] = (await request.query(`select - parentTable.name as TableWithForeignKey, - fkc.constraint_column_id as FK_PartNo, - parentColumn.name as ForeignKeyColumn, - referencedTable.name as TableReferenced, - referencedColumn.name as ForeignKeyColumnReferenced, - fk.delete_referential_action_desc as onDelete, - fk.update_referential_action_desc as onUpdate, - fk.object_id as objectId -from - sys.foreign_keys fk -inner join - sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id -inner join - sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id -inner join - sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id -inner join - sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id -inner join - sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id -inner join - sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id -where - fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) -order by - TableWithForeignKey, FK_PartNo`)).recordset; - response.push(...resp); - }) - ); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.objectId - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - switch (resp.onDelete) { - case "NO_ACTION": - rels.actionOnDelete = null; - break; - case "SET_NULL": - rels.actionOnDelete = "SET NULL"; - break; - default: - rels.actionOnDelete = resp.onDelete; - break; - } - switch (resp.onUpdate) { - case "NO_ACTION": - rels.actionOnUpdate = null; - break; - case "SET_NULL": - rels.actionOnUpdate = "SET NULL"; - break; - default: - rels.actionOnUpdate = resp.onUpdate; - break; - } - rels.objectId = resp.objectId; - rels.ownerTable = resp.TableWithForeignKey; - rels.referencedTable = resp.TableReferenced; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.ForeignKeyColumn); - rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); - }); - const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + ): Promise { + throw new Error(); + // TODO: Remove + // const request = new MSSQL.Request(this.Connection); + // const response: { + // TableWithForeignKey: string; + // FK_PartNo: number; + // ForeignKeyColumn: string; + // TableReferenced: string; + // ForeignKeyColumnReferenced: string; + // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // objectId: number; + // }[] = []; + // await Promise.all( + // dbNames.split(",").map(async dbName => { + // await this.UseDB(dbName); + // const resp: { + // TableWithForeignKey: string; + // FK_PartNo: number; + // ForeignKeyColumn: string; + // TableReferenced: string; + // ForeignKeyColumnReferenced: string; + // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // objectId: number; + // }[] = (await request.query(`select + // parentTable.name as TableWithForeignKey, + // fkc.constraint_column_id as FK_PartNo, + // parentColumn.name as ForeignKeyColumn, + // referencedTable.name as TableReferenced, + // referencedColumn.name as ForeignKeyColumnReferenced, + // fk.delete_referential_action_desc as onDelete, + // fk.update_referential_action_desc as onUpdate, + // fk.object_id as objectId + // from + // sys.foreign_keys fk + // inner join + // sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id + // inner join + // sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id + // inner join + // sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id + // inner join + // sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id + // inner join + // sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id + // inner join + // sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id + // where + // fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) + // order by + // TableWithForeignKey, FK_PartNo`)).recordset; + // response.push(...resp); + // }) + // ); + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.objectId + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // switch (resp.onDelete) { + // case "NO_ACTION": + // rels.actionOnDelete = null; + // break; + // case "SET_NULL": + // rels.actionOnDelete = "SET NULL"; + // break; + // default: + // rels.actionOnDelete = resp.onDelete; + // break; + // } + // switch (resp.onUpdate) { + // case "NO_ACTION": + // rels.actionOnUpdate = null; + // break; + // case "SET_NULL": + // rels.actionOnUpdate = "SET NULL"; + // break; + // default: + // rels.actionOnUpdate = resp.onUpdate; + // break; + // } + // rels.objectId = resp.objectId; + // rels.ownerTable = resp.TableWithForeignKey; + // rels.referencedTable = resp.TableReferenced; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.ForeignKeyColumn); + // rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); + // }); + // const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index cab7cb8..e9fcf65 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -13,6 +13,7 @@ import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; import { Index } from "../models/Index"; +import { RelationInternal } from "../models/RelationInternal"; export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ @@ -305,10 +306,10 @@ export default class MysqlDriver extends AbstractDriver { } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { + ): Promise { const response = await this.ExecQuery<{ TableWithForeignKey: string; FK_PartNo: number; @@ -336,27 +337,43 @@ export default class MysqlDriver extends AbstractDriver { TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList(dbNames)}) AND CU.REFERENCED_TABLE_NAME IS NOT NULL; `); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.object_id + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.object_id)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.object_id === relationId); + const ownerTable = entities.find( + v => v.sqlName === rows[0].TableWithForeignKey ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.onDelete === "NO_ACTION" ? null : resp.onDelete; - rels.actionOnUpdate = - resp.onUpdate === "NO_ACTION" ? null : resp.onUpdate; - rels.objectId = resp.object_id; - rels.ownerTable = resp.TableWithForeignKey; - rels.referencedTable = resp.TableReferenced; - relationsTemp.push(rels); + const relatedTable = entities.find( + v => v.sqlName === rows[0].TableReferenced + ); + + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${rows[0].TableWithForeignKey} and ${rows[0].TableReferenced} wasn't found in entity model.`, + true + ); + return; } - rels.ownerColumnsNames.push(resp.ForeignKeyColumn); - rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + if (rows[0].onDelete !== "NO_ACTION") { + internal.onDelete = rows[0].onDelete; + } + if (rows[0].onUpdate !== "NO_ACTION") { + internal.onUpdate = rows[0].onUpdate; + } + rows.forEach(row => { + internal.ownerColumns.push(row.ForeignKeyColumn); + internal.relatedColumns.push(row.ForeignKeyColumnReferenced); + }); }); + const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 9341774..d58eeba 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -252,52 +252,54 @@ export default class OracleDriver extends AbstractDriver { // return entities; } - public async GetRelations(entities: EntityInfo[]): Promise { - const response: { - OWNER_TABLE_NAME: string; - OWNER_POSITION: string; - OWNER_COLUMN_NAME: string; - CHILD_TABLE_NAME: string; - CHILD_COLUMN_NAME: string; - DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - CONSTRAINT_NAME: string; - }[] = (await this.Connection - .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, - child.TABLE_NAME CHILD_TABLE_NAME ,childCol.COLUMN_NAME CHILD_COLUMN_NAME, - owner.DELETE_RULE, - owner.CONSTRAINT_NAME - from user_constraints owner - join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') - JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME - JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION - ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) - .rows!; + public async GetRelations(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // OWNER_TABLE_NAME: string; + // OWNER_POSITION: string; + // OWNER_COLUMN_NAME: string; + // CHILD_TABLE_NAME: string; + // CHILD_COLUMN_NAME: string; + // DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // CONSTRAINT_NAME: string; + // }[] = (await this.Connection + // .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, + // child.TABLE_NAME CHILD_TABLE_NAME ,childCol.COLUMN_NAME CHILD_COLUMN_NAME, + // owner.DELETE_RULE, + // owner.CONSTRAINT_NAME + // from user_constraints owner + // join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') + // JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME + // JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION + // ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) + // .rows!; - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.CONSTRAINT_NAME - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; - rels.actionOnUpdate = null; - rels.objectId = resp.CONSTRAINT_NAME; - rels.ownerTable = resp.OWNER_TABLE_NAME; - rels.referencedTable = resp.CHILD_TABLE_NAME; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); - rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); - }); - const retVal = OracleDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.CONSTRAINT_NAME + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; + // rels.actionOnUpdate = null; + // rels.objectId = resp.CONSTRAINT_NAME; + // rels.ownerTable = resp.OWNER_TABLE_NAME; + // rels.referencedTable = resp.CHILD_TABLE_NAME; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); + // rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); + // }); + // const retVal = OracleDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 774a394..02c5615 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -469,85 +469,87 @@ export default class PostgresDriver extends AbstractDriver { } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string - ): Promise { - const response: { - tablewithforeignkey: string; - fk_partno: number; - foreignkeycolumn: string; - tablereferenced: string; - foreignkeycolumnreferenced: string; - ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - object_id: string; - // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html - }[] = (await this.Connection.query(`SELECT DISTINCT - con.relname AS tablewithforeignkey, - att.attnum as fk_partno, - att2.attname AS foreignkeycolumn, - cl.relname AS tablereferenced, - att.attname AS foreignkeycolumnreferenced, - delete_rule as ondelete, - update_rule as onupdate, - concat(con.conname,con.conrelid,con.confrelid) as object_id - FROM ( - SELECT - unnest(con1.conkey) AS parent, - unnest(con1.confkey) AS child, - con1.confrelid, - con1.conrelid, - cl_1.relname, - con1.conname, - nspname - FROM - pg_class cl_1, - pg_namespace ns, - pg_constraint con1 - WHERE - con1.contype = 'f'::"char" - AND cl_1.relnamespace = ns.oid - AND con1.conrelid = cl_1.oid - and nspname in (${schema}) - ) con, - pg_attribute att, - pg_class cl, - pg_attribute att2, - information_schema.referential_constraints rc - WHERE - att.attrelid = con.confrelid - AND att.attnum = con.child - AND cl.oid = con.confrelid - AND att2.attrelid = con.conrelid - AND att2.attnum = con.parent - AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname - `)).rows; - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.object_id - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.ondelete === "NO ACTION" ? null : resp.ondelete; - rels.actionOnUpdate = - resp.onupdate === "NO ACTION" ? null : resp.onupdate; - rels.objectId = resp.object_id; - rels.ownerTable = resp.tablewithforeignkey; - rels.referencedTable = resp.tablereferenced; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.foreignkeycolumn); - rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); - }); - const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + ): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // tablewithforeignkey: string; + // fk_partno: number; + // foreignkeycolumn: string; + // tablereferenced: string; + // foreignkeycolumnreferenced: string; + // ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // object_id: string; + // // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html + // }[] = (await this.Connection.query(`SELECT DISTINCT + // con.relname AS tablewithforeignkey, + // att.attnum as fk_partno, + // att2.attname AS foreignkeycolumn, + // cl.relname AS tablereferenced, + // att.attname AS foreignkeycolumnreferenced, + // delete_rule as ondelete, + // update_rule as onupdate, + // concat(con.conname,con.conrelid,con.confrelid) as object_id + // FROM ( + // SELECT + // unnest(con1.conkey) AS parent, + // unnest(con1.confkey) AS child, + // con1.confrelid, + // con1.conrelid, + // cl_1.relname, + // con1.conname, + // nspname + // FROM + // pg_class cl_1, + // pg_namespace ns, + // pg_constraint con1 + // WHERE + // con1.contype = 'f'::"char" + // AND cl_1.relnamespace = ns.oid + // AND con1.conrelid = cl_1.oid + // and nspname in (${schema}) + // ) con, + // pg_attribute att, + // pg_class cl, + // pg_attribute att2, + // information_schema.referential_constraints rc + // WHERE + // att.attrelid = con.confrelid + // AND att.attnum = con.child + // AND cl.oid = con.confrelid + // AND att2.attrelid = con.conrelid + // AND att2.attnum = con.parent + // AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname + // `)).rows; + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.object_id + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.ondelete === "NO ACTION" ? null : resp.ondelete; + // rels.actionOnUpdate = + // resp.onupdate === "NO ACTION" ? null : resp.onupdate; + // rels.objectId = resp.object_id; + // rels.ownerTable = resp.tablewithforeignkey; + // rels.referencedTable = resp.tablereferenced; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.foreignkeycolumn); + // rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); + // }); + // const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 1cdab2f..fac4571 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -277,50 +277,52 @@ export default class SqliteDriver extends AbstractDriver { // return entities; } - public async GetRelations(entities: EntityInfo[]): Promise { - let retVal = entities; - await Promise.all( - retVal.map(async entity => { - const response = await this.ExecQuery<{ - id: number; - seq: number; - table: string; - from: string; - to: string; - on_update: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "NO ACTION"; - on_delete: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "NO ACTION"; - match: string; - }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - const rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.on_delete === "NO ACTION" ? null : resp.on_delete; - rels.actionOnUpdate = - resp.on_update === "NO ACTION" ? null : resp.on_update; - rels.ownerTable = entity.tsEntityName; - rels.referencedTable = resp.table; - relationsTemp.push(rels); - rels.ownerColumnsNames.push(resp.from); - rels.referencedColumnsNames.push(resp.to); - }); - retVal = SqliteDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - retVal - ); - }) - ); - return retVal; + public async GetRelations(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // let retVal = entities; + // await Promise.all( + // retVal.map(async entity => { + // const response = await this.ExecQuery<{ + // id: number; + // seq: number; + // table: string; + // from: string; + // to: string; + // on_update: + // | "RESTRICT" + // | "CASCADE" + // | "SET NULL" + // | "NO ACTION"; + // on_delete: + // | "RESTRICT" + // | "CASCADE" + // | "SET NULL" + // | "NO ACTION"; + // match: string; + // }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // const rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.on_delete === "NO ACTION" ? null : resp.on_delete; + // rels.actionOnUpdate = + // resp.on_update === "NO ACTION" ? null : resp.on_update; + // rels.ownerTable = entity.tsEntityName; + // rels.referencedTable = resp.table; + // relationsTemp.push(rels); + // rels.ownerColumnsNames.push(resp.from); + // rels.referencedColumnsNames.push(resp.to); + // }); + // retVal = SqliteDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // retVal + // ); + // }) + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/models/RelationInternal.ts b/src/models/RelationInternal.ts new file mode 100644 index 0000000..0d3923a --- /dev/null +++ b/src/models/RelationInternal.ts @@ -0,0 +1,12 @@ +import { OnDeleteType } from "typeorm/metadata/types/OnDeleteType"; +import { OnUpdateType } from "typeorm/metadata/types/OnUpdateType"; +import { Entity } from "./Entity"; + +export type RelationInternal = { + ownerTable: Entity; + relatedTable: Entity; + ownerColumns: string[]; + relatedColumns: string[]; + onDelete?: OnDeleteType; + onUpdate?: OnUpdateType; +};