mysql relations rewrite

This commit is contained in:
Kononnable 2019-10-03 23:34:48 +02:00
parent 76f3ed2ad2
commit 130c682458
7 changed files with 419 additions and 388 deletions

View File

@ -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<Entity[]>;
public abstract async GetRelations(
entities: EntityInfo[],
entities: Entity[],
schema: string,
dbNames: string
): Promise<EntityInfo[]>;
): Promise<Entity[]>;
public static FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) {
dbModel.forEach(entity => {

View File

@ -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<EntityInfo[]> {
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<Entity[]> {
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() {

View File

@ -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<EntityInfo[]> {
): Promise<Entity[]> {
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

View File

@ -252,52 +252,54 @@ export default class OracleDriver extends AbstractDriver {
// return entities;
}
public async GetRelations(entities: EntityInfo[]): Promise<EntityInfo[]> {
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<Entity[]> {
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() {

View File

@ -469,85 +469,87 @@ export default class PostgresDriver extends AbstractDriver {
}
public async GetRelations(
entities: EntityInfo[],
entities: Entity[],
schema: string
): Promise<EntityInfo[]> {
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<Entity[]> {
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() {

View File

@ -277,50 +277,52 @@ export default class SqliteDriver extends AbstractDriver {
// return entities;
}
public async GetRelations(entities: EntityInfo[]): Promise<EntityInfo[]> {
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<Entity[]> {
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() {

View File

@ -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;
};