mysql relations rewrite
This commit is contained in:
parent
76f3ed2ad2
commit
130c682458
@ -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 => {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
12
src/models/RelationInternal.ts
Normal file
12
src/models/RelationInternal.ts
Normal 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;
|
||||
};
|
Loading…
Reference in New Issue
Block a user