From 1a2c9e091c56a22b4d33a8071802c52a34159aee Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Wed, 21 Sep 2016 19:00:44 +0500 Subject: [PATCH] better implemented oracle driver; made fk names shorter because of oracle restrictions --- sample/sample3-many-to-one/app.ts | 18 ++- src/driver/oracle/OracleQueryRunner.ts | 112 +++++++++++-------- src/driver/postgres/PostgresQueryRunner.ts | 1 - src/entity-schema/EntitySchema.ts | 6 +- src/naming-strategy/DefaultNamingStrategy.ts | 2 +- 5 files changed, 84 insertions(+), 55 deletions(-) diff --git a/sample/sample3-many-to-one/app.ts b/sample/sample3-many-to-one/app.ts index 6a9488a21..1a50b321e 100644 --- a/sample/sample3-many-to-one/app.ts +++ b/sample/sample3-many-to-one/app.ts @@ -10,15 +10,21 @@ import {PostAuthor} from "./entity/PostAuthor"; const options: ConnectionOptions = { driver: { - type: "mssql", - host: "192.168.1.10", - username: "sa", - password: "admin12345", - database: "test", + // type: "mssql", + // host: "192.168.1.10", + // username: "sa", + // password: "admin12345", + // database: "test", + type: "oracle", + host: "localhost", + username: "system", + password: "oracle", + port: 1521, + sid: "xe.oracle.docker", }, autoSchemaSync: true, logging: { - // logQueries: true, + logQueries: true, logFailedQueryError: true }, entities: [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor] diff --git a/src/driver/oracle/OracleQueryRunner.ts b/src/driver/oracle/OracleQueryRunner.ts index 990d443d5..27b2ea306 100644 --- a/src/driver/oracle/OracleQueryRunner.ts +++ b/src/driver/oracle/OracleQueryRunner.ts @@ -237,24 +237,26 @@ end;`; throw new QueryRunnerAlreadyReleasedError(); // if no tables given then no need to proceed - if (!tableNames || !tableNames.length) return []; // load tables, columns, indices and foreign keys - const tablesSql = `SELECT table_name FROM user_tables`; - const columnsSql = `SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.dbName}'`; + const tableNamesString = tableNames.map(name => "'" + name + "'").join(", "); + const tablesSql = `SELECT TABLE_NAME FROM user_tables WHERE TABLE_NAME IN (${tableNamesString})`; + const columnsSql = `SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, IDENTITY_COLUMN FROM all_tab_cols WHERE TABLE_NAME IN (${tableNamesString})`; const indicesSql = `SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = '${this.dbName}' AND INDEX_NAME != 'PRIMARY'`; const foreignKeysSql = `SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = '${this.dbName}' AND REFERENCED_COLUMN_NAME IS NOT NULL`; const uniqueKeysSql = `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = '${this.dbName}' AND CONSTRAINT_TYPE = 'UNIQUE'`; - const primaryKeysSql = `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = '${this.dbName}' AND CONSTRAINT_TYPE = 'PRIMARY KEY'`; - const [dbTables, dbColumns, dbIndices, dbForeignKeys, dbUniqueKeys, primaryKeys]: ObjectLiteral[][] = await Promise.all([ + const constraintsSql = `SELECT cols.table_name, cols.column_name, cols.position, cons.constraint_type, cons.constraint_name +FROM all_constraints cons, all_cons_columns cols WHERE cols.table_name IN (${tableNamesString}) +AND cons.constraint_name = cols.constraint_name AND cons.owner = cols.owner ORDER BY cols.table_name, cols.position`; + const [dbTables, dbColumns, /*dbIndices, dbForeignKeys, dbUniqueKeys, */constraints]: ObjectLiteral[][] = await Promise.all([ this.query(tablesSql), this.query(columnsSql), - this.query(indicesSql), - this.query(foreignKeysSql), - this.query(uniqueKeysSql), - this.query(primaryKeysSql), + // this.query(indicesSql), + // this.query(foreignKeysSql), + // this.query(uniqueKeysSql), + this.query(constraintsSql), ]); // if tables were not found in the db, no need to proceed @@ -269,43 +271,63 @@ end;`; tableSchema.columns = dbColumns .filter(dbColumn => dbColumn["TABLE_NAME"] === tableSchema.name) .map(dbColumn => { + const isPrimary = !!constraints + .find(constraint => { + return constraint["TABLE_NAME"] === tableSchema.name && + constraint["CONSTRAINT_TYPE"] === "P" && + constraint["COLUMN_NAME"] === dbColumn["COLUMN_NAME"]; + }); + + let columnType = dbColumn["DATA_TYPE"].toLowerCase(); + if (dbColumn["DATA_TYPE"].toLowerCase() === "varchar2" && dbColumn["DATA_LENGTH"] !== null) { + columnType += "(" + dbColumn["DATA_LENGTH"] + ")"; + } else if (dbColumn["DATA_PRECISION"] !== null && dbColumn["DATA_SCALE"] !== null) { + columnType += "(" + dbColumn["DATA_PRECISION"] + "," + dbColumn["DATA_SCALE"] + ")"; + } else if (dbColumn["DATA_SCALE"] !== null) { + columnType += "(0," + dbColumn["DATA_SCALE"] + ")"; + } else if (dbColumn["DATA_PRECISION"] !== null) { + columnType += "(" + dbColumn["DATA_PRECISION"] + ",0)"; + } + const columnSchema = new ColumnSchema(); columnSchema.name = dbColumn["COLUMN_NAME"]; - columnSchema.type = dbColumn["COLUMN_TYPE"].toLowerCase(); // todo: use normalize type? + columnSchema.type = columnType; columnSchema.default = dbColumn["COLUMN_DEFAULT"] !== null && dbColumn["COLUMN_DEFAULT"] !== undefined ? dbColumn["COLUMN_DEFAULT"] : undefined; - columnSchema.isNullable = dbColumn["IS_NULLABLE"] === "YES"; - columnSchema.isPrimary = dbColumn["COLUMN_KEY"].indexOf("PRI") !== -1; - columnSchema.isGenerated = dbColumn["EXTRA"].indexOf("auto_increment") !== -1; - columnSchema.comment = dbColumn["COLUMN_COMMENT"]; + columnSchema.isNullable = dbColumn["NULLABLE"] !== "N"; + columnSchema.isPrimary = isPrimary; + columnSchema.isGenerated = dbColumn["IDENTITY_COLUMN"] === "YES"; // todo + columnSchema.comment = ""; // todo return columnSchema; }); // create primary key schema - tableSchema.primaryKeys = primaryKeys - .filter(primaryKey => primaryKey["TABLE_NAME"] === tableSchema.name) - .map(primaryKey => new PrimaryKeySchema(primaryKey["CONSTRAINT_NAME"], primaryKey["COLUMN_NAME"])); + tableSchema.primaryKeys = constraints + .filter(constraint => constraint["TABLE_NAME"] === tableSchema.name && constraint["CONSTRAINT_TYPE"] === "P") + .map(constraint => new PrimaryKeySchema(constraint["CONSTRAINT_NAME"], constraint["COLUMN_NAME"])); // create foreign key schemas from the loaded indices - tableSchema.foreignKeys = dbForeignKeys - .filter(dbForeignKey => dbForeignKey["TABLE_NAME"] === tableSchema.name) - .map(dbForeignKey => new ForeignKeySchema(dbForeignKey["CONSTRAINT_NAME"], [], [], "", "")); // todo: fix missing params + tableSchema.foreignKeys = constraints + .filter(constraint => constraint["TABLE_NAME"] === tableSchema.name && constraint["CONSTRAINT_TYPE"] === "R") + .map(constraint => new ForeignKeySchema(constraint["CONSTRAINT_NAME"], [], [], "", "")); // todo: fix missing params + + console.log(tableSchema); // create index schemas from the loaded indices - tableSchema.indices = dbIndices - .filter(dbIndex => { - return dbIndex["table_name"] === tableSchema.name && - (!tableSchema.foreignKeys.find(foreignKey => foreignKey.name === dbIndex["INDEX_NAME"])) && - (!tableSchema.primaryKeys.find(primaryKey => primaryKey.name === dbIndex["INDEX_NAME"])); - }) - .map(dbIndex => dbIndex["INDEX_NAME"]) - .filter((value, index, self) => self.indexOf(value) === index) // unqiue - .map(dbIndexName => { - const columnNames = dbIndices - .filter(dbIndex => dbIndex["TABLE_NAME"] === tableSchema.name && dbIndex["INDEX_NAME"] === dbIndexName) - .map(dbIndex => dbIndex["COLUMN_NAME"]); - - return new IndexSchema(dbTable["TABLE_NAME"], dbIndexName, columnNames, false /* todo: uniqueness */); - }); + // tableSchema.indices = dbIndices + // .filter(dbIndex => { + // return dbIndex["table_name"] === tableSchema.name && + // (!tableSchema.foreignKeys.find(foreignKey => foreignKey.name === dbIndex["INDEX_NAME"])) && + // (!tableSchema.primaryKeys.find(primaryKey => primaryKey.name === dbIndex["INDEX_NAME"])); + // }) + // .map(dbIndex => dbIndex["INDEX_NAME"]) + // .filter((value, index, self) => self.indexOf(value) === index) // unqiue + // .map(dbIndexName => { + // const columnNames = dbIndices + // .filter(dbIndex => dbIndex["TABLE_NAME"] === tableSchema.name && dbIndex["INDEX_NAME"] === dbIndexName) + // .map(dbIndex => dbIndex["COLUMN_NAME"]); + // + // return new IndexSchema(dbTable["TABLE_NAME"], dbIndexName, columnNames, false /* todo: uniqueness */); + // }); return tableSchema; }); @@ -378,9 +400,9 @@ end;`; throw new QueryRunnerAlreadyReleasedError(); const primaryColumnNames = dbTable.primaryKeys.map(primaryKey => "\"" + primaryKey.columnName + "\""); - await this.query(`ALTER TABLE ${dbTable.name} DROP PRIMARY KEY`); + await this.query(`ALTER TABLE "${dbTable.name}" DROP PRIMARY KEY`); if (primaryColumnNames.length > 0) - await this.query(`ALTER TABLE ${dbTable.name} ADD PRIMARY KEY (${primaryColumnNames.join(", ")})`); + await this.query(`ALTER TABLE "${dbTable.name}" ADD PRIMARY KEY (${primaryColumnNames.join(", ")})`); } /** @@ -393,7 +415,7 @@ end;`; const promises = foreignKeys.map(foreignKey => { const columnNames = foreignKey.columnNames.map(column => "\"" + column + "\"").join(", "); const referencedColumnNames = foreignKey.referencedColumnNames.map(column => "\"" + column + "\"").join(","); - let sql = `ALTER TABLE ${dbTable.name} ADD CONSTRAINT "${foreignKey.name}" ` + + let sql = `ALTER TABLE "${dbTable.name}" ADD CONSTRAINT "${foreignKey.name}" ` + `FOREIGN KEY (${columnNames}) ` + `REFERENCES "${foreignKey.referencedTableName}"(${referencedColumnNames})`; if (foreignKey.onDelete) sql += " ON DELETE " + foreignKey.onDelete; @@ -411,7 +433,7 @@ end;`; throw new QueryRunnerAlreadyReleasedError(); const promises = foreignKeys.map(foreignKey => { - const sql = `ALTER TABLE "${tableSchema.name}" DROP FOREIGN KEY "${foreignKey.name}"`; + const sql = `ALTER TABLE "${tableSchema.name}" DROP CONSTRAINT "${foreignKey.name}"`; return this.query(sql); }); @@ -454,14 +476,16 @@ end;`; return "number(1)"; case "integer": case "int": + // if (column.isGenerated) + // return `number(22)`; if (column.precision && column.scale) return `number(${column.precision},${column.scale})`; if (column.precision) - return `number(${column.precision})`; + return `number(${column.precision},0)`; if (column.scale) - return `number(${column.scale})`; + return `number(0,${column.scale})`; - return "number(10)"; + return "number(10,0)"; case "smallint": return "number(5)"; case "bigint": @@ -476,10 +500,10 @@ end;`; return `decimal(${column.precision},${column.scale})`; } else if (column.scale) { - return `decimal(${column.scale})`; + return `decimal(0,${column.scale})`; } else if (column.precision) { - return `decimal(${column.precision})`; + return `decimal(${column.precision},0)`; } else { return "decimal"; diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 88c7715f4..09dd3a7b6 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -215,7 +215,6 @@ export class PostgresQueryRunner implements QueryRunner { throw new QueryRunnerAlreadyReleasedError(); // if no tables given then no need to proceed - if (!tableNames || !tableNames.length) return []; diff --git a/src/entity-schema/EntitySchema.ts b/src/entity-schema/EntitySchema.ts index 82b7184f2..e99341863 100644 --- a/src/entity-schema/EntitySchema.ts +++ b/src/entity-schema/EntitySchema.ts @@ -1,10 +1,10 @@ - import {TableType} from "../metadata/types/TableTypes"; import {OrderByCondition} from "../find-options/OrderByCondition"; import {OnDeleteType} from "../metadata/ForeignKeyMetadata"; import {JoinColumnOptions} from "../decorator/options/JoinColumnOptions"; import {ColumnType} from "../metadata/types/ColumnTypes"; import {RelationType} from "../metadata/types/RelationTypes"; + export interface EntitySchema { /** @@ -25,7 +25,7 @@ export interface EntitySchema { /** * Entity table's options. */ - table: { + table?: { /** * Table name. @@ -35,7 +35,7 @@ export interface EntitySchema { /** * Table type. */ - type: TableType; + type?: TableType; /** * Specifies a property name by which queries will perform ordering by default when fetching rows. diff --git a/src/naming-strategy/DefaultNamingStrategy.ts b/src/naming-strategy/DefaultNamingStrategy.ts index 8e4736997..0b2c5dd56 100644 --- a/src/naming-strategy/DefaultNamingStrategy.ts +++ b/src/naming-strategy/DefaultNamingStrategy.ts @@ -64,7 +64,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface { foreignKeyName(tableName: string, columnNames: string[], referencedTableName: string, referencedColumnNames: string[]): string { const key = `${tableName}_${columnNames.join("_")}_${referencedTableName}_${referencedColumnNames.join("_")}`; - return "fk_" + require("sha1")(key); // todo: use crypto instead? + return "fk_" + require("sha1")(key).substr(0, 27); // todo: use crypto instead? } classTableInheritanceParentColumnName(parentTableName: any, parentTableIdPropertyName: any): string {