oracledb implementation

This commit is contained in:
Kononnable 2019-10-10 22:18:22 +02:00
parent 2551a5629a
commit d1407ab5d9
3 changed files with 278 additions and 257 deletions

View File

@ -2,13 +2,12 @@ import * as TypeormDriver from "typeorm/driver/oracle/OracleDriver";
import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults";
import * as TomgUtils from "../Utils";
import AbstractDriver from "./AbstractDriver";
import EntityInfo from "../oldModels/EntityInfo";
import ColumnInfo from "../oldModels/ColumnInfo";
import IndexInfo from "../oldModels/IndexInfo";
import IndexColumnInfo from "../oldModels/IndexColumnInfo";
import RelationTempInfo from "../oldModels/RelationTempInfo";
import IConnectionOptions from "../IConnectionOptions";
import { Entity } from "../models/Entity";
import { Column } from "../models/Column";
import { Index } from "../models/Index";
import IGenerationOptions from "../IGenerationOptions";
import { RelationInternal } from "../models/RelationInternal";
export default class OracleDriver extends AbstractDriver {
public defaultValues: DataTypeDefaults = new TypeormDriver.OracleDriver({
@ -49,257 +48,281 @@ export default class OracleDriver extends AbstractDriver {
};
public async GetCoulmnsFromEntity(entities: Entity[]): Promise<Entity[]> {
throw new Error();
// TODO: Remove
// const response: {
// TABLE_NAME: string;
// COLUMN_NAME: string;
// DATA_DEFAULT: string;
// NULLABLE: string;
// DATA_TYPE: string;
// DATA_LENGTH: number;
// DATA_PRECISION: number;
// DATA_SCALE: number;
// IDENTITY_COLUMN: string;
// IS_UNIQUE: number;
// }[] = (await this.Connection
// .execute(`SELECT utc.TABLE_NAME, utc.COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH,
// DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN,
// (select count(*) from USER_CONS_COLUMNS ucc
// JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U'
// where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE
// FROM USER_TAB_COLUMNS utc`)).rows!;
const response: {
TABLE_NAME: string;
COLUMN_NAME: string;
DATA_DEFAULT: string;
NULLABLE: string;
DATA_TYPE: string;
DATA_LENGTH: number;
DATA_PRECISION: number;
DATA_SCALE: number;
IDENTITY_COLUMN: string;
IS_UNIQUE: number;
}[] = (await this.Connection
.execute(`SELECT utc.TABLE_NAME, utc.COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH,
DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN,
(select count(*) from USER_CONS_COLUMNS ucc
JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U'
where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE
FROM USER_TAB_COLUMNS utc`)).rows!;
// entities.forEach(ent => {
// response
// .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName)
// .forEach(resp => {
// const colInfo: ColumnInfo = new ColumnInfo();
// colInfo.tsName = resp.COLUMN_NAME;
// colInfo.options.name = resp.COLUMN_NAME;
// colInfo.options.nullable = resp.NULLABLE === "Y";
// colInfo.options.generated = resp.IDENTITY_COLUMN === "YES";
// colInfo.options.default =
// !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"')
// ? null
// : OracleDriver.ReturnDefaultValueFunction(
// resp.DATA_DEFAULT
// );
// colInfo.options.unique = resp.IS_UNIQUE > 0;
// const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, "");
// colInfo.options.type = DATA_TYPE.toLowerCase() as any;
// switch (DATA_TYPE.toLowerCase()) {
// case "char":
// colInfo.tsType = "string";
// break;
// case "nchar":
// colInfo.tsType = "string";
// break;
// case "nvarchar2":
// colInfo.tsType = "string";
// break;
// case "varchar2":
// colInfo.tsType = "string";
// break;
// case "long":
// colInfo.tsType = "string";
// break;
// case "raw":
// colInfo.tsType = "Buffer";
// break;
// case "long raw":
// colInfo.tsType = "Buffer";
// break;
// case "number":
// colInfo.tsType = "number";
// break;
// case "numeric":
// colInfo.tsType = "number";
// break;
// case "float":
// colInfo.tsType = "number";
// break;
// case "dec":
// colInfo.tsType = "number";
// break;
// case "decimal":
// colInfo.tsType = "number";
// break;
// case "integer":
// colInfo.tsType = "number";
// break;
// case "int":
// colInfo.tsType = "number";
// break;
// case "smallint":
// colInfo.tsType = "number";
// break;
// case "real":
// colInfo.tsType = "number";
// break;
// case "double precision":
// colInfo.tsType = "number";
// break;
// case "date":
// colInfo.tsType = "Date";
// break;
// case "timestamp":
// colInfo.tsType = "Date";
// break;
// case "timestamp with time zone":
// colInfo.tsType = "Date";
// break;
// case "timestamp with local time zone":
// colInfo.tsType = "Date";
// break;
// case "interval year to month":
// colInfo.tsType = "string";
// break;
// case "interval day to second":
// colInfo.tsType = "string";
// break;
// case "bfile":
// colInfo.tsType = "Buffer";
// break;
// case "blob":
// colInfo.tsType = "Buffer";
// break;
// case "clob":
// colInfo.tsType = "string";
// break;
// case "nclob":
// colInfo.tsType = "string";
// break;
// case "rowid":
// colInfo.tsType = "number";
// break;
// case "urowid":
// colInfo.tsType = "number";
// break;
// default:
// TomgUtils.LogError(
// `Unknown column type:${DATA_TYPE}`
// );
// break;
// }
// if (
// this.ColumnTypesWithPrecision.some(
// v => v === colInfo.options.type
// )
// ) {
// colInfo.options.precision = resp.DATA_PRECISION;
// colInfo.options.scale = resp.DATA_SCALE;
// }
// if (
// this.ColumnTypesWithLength.some(
// v => v === colInfo.options.type
// )
// ) {
// colInfo.options.length =
// resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined;
// }
entities.forEach(ent => {
response
.filter(filterVal => filterVal.TABLE_NAME === ent.tscName)
.forEach(resp => {
const tscName = resp.COLUMN_NAME;
const options: Partial<Column["options"]> = {};
options.name = resp.COLUMN_NAME;
if (resp.NULLABLE === "Y") options.nullable = true;
if (resp.IS_UNIQUE > 0) options.unique = true;
const generated =
resp.IDENTITY_COLUMN === "YES" ? true : undefined;
const defaultValue =
!resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"')
? undefined
: OracleDriver.ReturnDefaultValueFunction(
resp.DATA_DEFAULT
);
const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, "");
const columnType = DATA_TYPE.toLowerCase() as any;
let tscType = "";
switch (DATA_TYPE.toLowerCase()) {
case "char":
tscType = "string";
break;
case "nchar":
tscType = "string";
break;
case "nvarchar2":
tscType = "string";
break;
case "varchar2":
tscType = "string";
break;
case "long":
tscType = "string";
break;
case "raw":
tscType = "Buffer";
break;
case "long raw":
tscType = "Buffer";
break;
case "number":
tscType = "number";
break;
case "numeric":
tscType = "number";
break;
case "float":
tscType = "number";
break;
case "dec":
tscType = "number";
break;
case "decimal":
tscType = "number";
break;
case "integer":
tscType = "number";
break;
case "int":
tscType = "number";
break;
case "smallint":
tscType = "number";
break;
case "real":
tscType = "number";
break;
case "double precision":
tscType = "number";
break;
case "date":
tscType = "Date";
break;
case "timestamp":
tscType = "Date";
break;
case "timestamp with time zone":
tscType = "Date";
break;
case "timestamp with local time zone":
tscType = "Date";
break;
case "interval year to month":
tscType = "string";
break;
case "interval day to second":
tscType = "string";
break;
case "bfile":
tscType = "Buffer";
break;
case "blob":
tscType = "Buffer";
break;
case "clob":
tscType = "string";
break;
case "nclob":
tscType = "string";
break;
case "rowid":
tscType = "number";
break;
case "urowid":
tscType = "number";
break;
default:
TomgUtils.LogError(
`Unknown column type:${DATA_TYPE}`
);
break;
}
if (
this.ColumnTypesWithPrecision.some(
v => v === columnType
)
) {
if (resp.DATA_PRECISION !== null) {
options.precision = resp.DATA_PRECISION;
}
if (resp.DATA_SCALE !== null) {
options.scale = resp.DATA_SCALE;
}
}
if (
this.ColumnTypesWithLength.some(v => v === columnType)
) {
options.length =
resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined;
}
// if (colInfo.options.type) {
// ent.Columns.push(colInfo);
// }
// });
// });
// return entities;
if (columnType) {
ent.columns.push({
generated,
type: columnType,
default: defaultValue,
options: { name: "", ...options }, // TODO: Change
tscName,
tscType
});
}
});
});
return entities;
}
public async GetIndexesFromEntity(entities: Entity[]): Promise<Entity[]> {
throw new Error();
// TODO: Remove
// const response: {
// COLUMN_NAME: string;
// TABLE_NAME: string;
// INDEX_NAME: string;
// UNIQUENESS: string;
// ISPRIMARYKEY: number;
// }[] = (await this.Connection
// .execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END ISPRIMARYKEY
// FROM USER_INDEXES ind
// JOIN USER_IND_COLUMNS col ON ind.INDEX_NAME=col.INDEX_NAME
// LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME
// ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!;
const response: {
COLUMN_NAME: string;
TABLE_NAME: string;
INDEX_NAME: string;
UNIQUENESS: string;
ISPRIMARYKEY: number;
}[] = (await this.Connection
.execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END ISPRIMARYKEY
FROM USER_INDEXES ind
JOIN USER_IND_COLUMNS col ON ind.INDEX_NAME=col.INDEX_NAME
LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME
ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!;
// entities.forEach(ent => {
// response
// .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName)
// .forEach(resp => {
// let indexInfo: IndexInfo = {} as IndexInfo;
// const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo;
// if (
// ent.Indexes.filter(
// filterVal => filterVal.name === resp.INDEX_NAME
// ).length > 0
// ) {
// indexInfo = ent.Indexes.find(
// filterVal => filterVal.name === resp.INDEX_NAME
// )!;
// } else {
// indexInfo.columns = [] as IndexColumnInfo[];
// indexInfo.name = resp.INDEX_NAME;
// indexInfo.isUnique = resp.UNIQUENESS === "UNIQUE";
// indexInfo.isPrimaryKey = resp.ISPRIMARYKEY === 1;
// ent.Indexes.push(indexInfo);
// }
// indexColumnInfo.name = resp.COLUMN_NAME;
// indexInfo.columns.push(indexColumnInfo);
// });
// });
entities.forEach(ent => {
const entityIndices = response.filter(
filterVal => filterVal.TABLE_NAME === ent.tscName
);
const indexNames = new Set(entityIndices.map(v => v.INDEX_NAME));
indexNames.forEach(indexName => {
const records = entityIndices.filter(
v => v.INDEX_NAME === indexName
);
const indexInfo: Index = {
columns: [],
options: {},
name: records[0].INDEX_NAME
};
if (records[0].ISPRIMARYKEY === 1) indexInfo.primary = true;
if (records[0].UNIQUENESS === "UNIQUE")
indexInfo.options.unique = true;
records.forEach(record => {
indexInfo.columns.push(record.COLUMN_NAME);
});
ent.indices.push(indexInfo);
});
});
// return entities;
return entities;
}
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!;
public async GetRelations(
entities: Entity[],
schema: string,
dbNames: string,
generationOptions: IGenerationOptions
): Promise<Entity[]> {
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: RelationInternal[] = [] as RelationInternal[];
const relationKeys = new Set(response.map(v => v.CONSTRAINT_NAME));
relationKeys.forEach(relationId => {
const rows = response.filter(v => v.CONSTRAINT_NAME === relationId);
const ownerTable = entities.find(
v => v.sqlName === rows[0].OWNER_TABLE_NAME
);
const relatedTable = entities.find(
v => v.sqlName === rows[0].CHILD_TABLE_NAME
);
if (!ownerTable || !relatedTable) {
TomgUtils.LogError(
`Relation between tables ${rows[0].OWNER_TABLE_NAME} and ${rows[0].CHILD_TABLE_NAME} wasn't found in entity model.`,
true
);
return;
}
const internal: RelationInternal = {
ownerColumns: [],
relatedColumns: [],
ownerTable,
relatedTable
};
if (rows[0].DELETE_RULE !== "NO ACTION") {
internal.onDelete = rows[0].DELETE_RULE;
}
rows.forEach(row => {
internal.ownerColumns.push(row.OWNER_COLUMN_NAME);
internal.relatedColumns.push(row.CHILD_COLUMN_NAME);
});
relationsTemp.push(internal);
});
const retVal = OracleDriver.GetRelationsFromRelationTempInfo(
relationsTemp,
entities,
generationOptions
);
return retVal;
}
public async DisconnectFromServer() {
@ -373,10 +396,10 @@ export default class OracleDriver extends AbstractDriver {
private static ReturnDefaultValueFunction(
defVal: string | null
): string | null {
): string | undefined {
let defaultVal = defVal;
if (!defaultVal) {
return null;
return undefined;
}
if (defaultVal.endsWith(" ")) {
defaultVal = defaultVal.slice(0, -1);

View File

@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm";
@Entity("Post")
export class Post {
@PrimaryColumn()
id: number;
@ -58,7 +57,7 @@ export class Post {
real: number;
@Column("double precision")
double_precision: number;
doublePrecision: number;
@Column("date")
date: Date;
@ -67,16 +66,16 @@ export class Post {
timestamp: Date;
@Column("timestamp with time zone")
timestamp_with_time_zone: Date;
timestampWithTimeZone: Date;
@Column("timestamp with local time zone")
timestamp_with_local_time_zone: Date;
timestampWithLocalTimeZone: Date;
@Column("interval year to month")
interval_year_to_month: string;
intervalYearToMonth: string;
@Column("interval day to second")
interval_day_to_second: string;
intervalDayToSecond: string;
@Column("bfile")
bfile: Buffer;
@ -95,5 +94,4 @@ export class Post {
@Column("urowid")
urowid: number;
}

View File

@ -24,8 +24,8 @@ export class Post {
@ManyToOne(type => Author, author => author.posts, {
lazy: true,
// cascade: ["insert"],
onDelete: "SET NULL",
onUpdate: "CASCADE"
onDelete: "SET NULL"
// onUpdate: "CASCADE" - onUpdate not supported on oracledb
})
author: Promise<Author | null>;