From d28f74c1adc90733555eb7281036e20b8018588e Mon Sep 17 00:00:00 2001 From: Zotov Dmitry Date: Fri, 8 Feb 2019 18:43:50 +0500 Subject: [PATCH] added testing configuration; working on tests; --- docker-compose.yml | 7 ++++ ormconfig.travis.json | 10 ++++++ src/metadata-builder/EntityMetadataBuilder.ts | 34 ++++++++++++++++--- src/schema-builder/RdbmsSchemaBuilder.ts | 12 +++++-- test/functional/schema-builder/add-column.ts | 6 ++-- .../schema-builder/change-column.ts | 24 +++++++++++-- .../functional/schema-builder/change-index.ts | 25 +++++++++++--- .../schema-builder/create-foreign-key.ts | 16 +++++++++ test/functional/schema-builder/drop-column.ts | 5 +++ .../schema-builder/update-primary-keys.ts | 9 +++++ 10 files changed, 132 insertions(+), 16 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c0d0955ca..af8556eb4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,6 +61,13 @@ services: SA_PASSWORD: "Admin12345" ACCEPT_EULA: "Y" + # cockroachdb + cockroachdb: + image: "cockroachdb/cockroach:v2.1.4" + container_name: "typeorm-cockroachdb" + ports: + - "26257:26257" + # mongodb mongodb: image: "mongo:3.4.18" diff --git a/ormconfig.travis.json b/ormconfig.travis.json index 47149bcd4..54a80faf9 100644 --- a/ormconfig.travis.json +++ b/ormconfig.travis.json @@ -60,6 +60,16 @@ "port": 1521, "sid": "xe.oracle.docker" }, + { + "skip": false, + "name": "cockroachdb", + "type": "cockroachdb", + "host": "localhost", + "port": 26257, + "username": "root", + "password": "", + "database": "defaultdb" + }, { "skip": false, "disabledIfNotEnabledImplicitly": true, diff --git a/src/metadata-builder/EntityMetadataBuilder.ts b/src/metadata-builder/EntityMetadataBuilder.ts index 969672c2e..ff8e74cba 100644 --- a/src/metadata-builder/EntityMetadataBuilder.ts +++ b/src/metadata-builder/EntityMetadataBuilder.ts @@ -1,3 +1,4 @@ +import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {EntityMetadata} from "../metadata/EntityMetadata"; import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {IndexMetadata} from "../metadata/IndexMetadata"; @@ -443,9 +444,6 @@ export class EntityMetadataBuilder { return new RelationCountMetadata({ entityMetadata, args }); }); - entityMetadata.ownIndices = this.metadataArgsStorage.filterIndices(entityMetadata.inheritanceTree).map(args => { - return new IndexMetadata({ entityMetadata, args }); - }); entityMetadata.ownListeners = this.metadataArgsStorage.filterListeners(entityMetadata.inheritanceTree).map(args => { return new EntityListenerMetadata({ entityMetadata: entityMetadata, args: args }); }); @@ -460,6 +458,33 @@ export class EntityMetadataBuilder { }); } + // Mysql stores unique indices constraints as unique constrains. + if (this.connection.driver instanceof CockroachDriver) { + entityMetadata.ownIndices = this.metadataArgsStorage.filterIndices(entityMetadata.inheritanceTree) + .filter(args => !args.unique) + .map(args => { + return new IndexMetadata({entityMetadata, args}); + }); + + const uniques = this.metadataArgsStorage.filterIndices(entityMetadata.inheritanceTree) + .filter(args => args.unique) + .map(args => { + return new UniqueMetadata({ + entityMetadata: entityMetadata, + args: { + target: args.target, + columns: args.columns, + } + }); + }); + entityMetadata.uniques.push(...uniques); + + } else { + entityMetadata.ownIndices = this.metadataArgsStorage.filterIndices(entityMetadata.inheritanceTree).map(args => { + return new IndexMetadata({entityMetadata, args}); + }); + } + // Mysql stores unique constraints as unique indices. if (this.connection.driver instanceof MysqlDriver) { const indices = this.metadataArgsStorage.filterUniques(entityMetadata.inheritanceTree).map(args => { @@ -477,9 +502,10 @@ export class EntityMetadataBuilder { entityMetadata.ownIndices.push(...indices); } else { - entityMetadata.uniques = this.metadataArgsStorage.filterUniques(entityMetadata.inheritanceTree).map(args => { + const uniques = this.metadataArgsStorage.filterUniques(entityMetadata.inheritanceTree).map(args => { return new UniqueMetadata({ entityMetadata, args }); }); + entityMetadata.uniques.push(...uniques); } } diff --git a/src/schema-builder/RdbmsSchemaBuilder.ts b/src/schema-builder/RdbmsSchemaBuilder.ts index d31ecfaba..d2d8cc4ae 100644 --- a/src/schema-builder/RdbmsSchemaBuilder.ts +++ b/src/schema-builder/RdbmsSchemaBuilder.ts @@ -1,3 +1,4 @@ +import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {Table} from "./table/Table"; import {TableColumn} from "./table/TableColumn"; import {TableForeignKey} from "./table/TableForeignKey"; @@ -59,7 +60,10 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { */ async build(): Promise { this.queryRunner = this.connection.createQueryRunner("master"); - await this.queryRunner.startTransaction(); + // CockroachDB implements asynchronous schema sync operations which can not been executed in transaction. + // E.g. if you try to DROP column and ADD it again in the same transaction, crdb throws error. + if (!(this.connection.driver instanceof CockroachDriver)) + await this.queryRunner.startTransaction(); try { const tablePaths = this.entityToSyncMetadatas.map(metadata => metadata.tablePath); await this.queryRunner.getTables(tablePaths); @@ -69,12 +73,14 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (this.connection.queryResultCache) await this.connection.queryResultCache.synchronize(this.queryRunner); - await this.queryRunner.commitTransaction(); + if (!(this.connection.driver instanceof CockroachDriver)) + await this.queryRunner.commitTransaction(); } catch (error) { try { // we throw original error even if rollback thrown an error - await this.queryRunner.rollbackTransaction(); + if (!(this.connection.driver instanceof CockroachDriver)) + await this.queryRunner.rollbackTransaction(); } catch (rollbackError) { } throw error; diff --git a/test/functional/schema-builder/add-column.ts b/test/functional/schema-builder/add-column.ts index 8e335c712..01e7ad217 100644 --- a/test/functional/schema-builder/add-column.ts +++ b/test/functional/schema-builder/add-column.ts @@ -1,5 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {ColumnMetadata} from "../../../src/metadata/ColumnMetadata"; import {ColumnMetadataArgs} from "../../../src/metadata-args/ColumnMetadataArgs"; @@ -31,7 +32,7 @@ describe("schema builder > add column", () => { options: { type: "int", name: "secondId", - primary: true, + primary: !(connection.driver instanceof CockroachDriver), // CockroachDB does not allow changing pk nullable: false } } @@ -62,8 +63,9 @@ describe("schema builder > add column", () => { const table = await queryRunner.getTable("post"); const column1 = table!.findColumnByName("secondId")!; column1.should.be.exist; - column1.isPrimary.should.be.true; column1.isNullable.should.be.false; + if (!(connection.driver instanceof CockroachDriver)) + column1.isPrimary.should.be.true; const column2 = table!.findColumnByName("description")!; column2.should.be.exist; diff --git a/test/functional/schema-builder/change-column.ts b/test/functional/schema-builder/change-column.ts index 296e950c9..7094ea2ee 100644 --- a/test/functional/schema-builder/change-column.ts +++ b/test/functional/schema-builder/change-column.ts @@ -1,5 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {expect} from "chai"; import {PromiseUtils} from "../../../src"; @@ -72,6 +73,11 @@ describe("schema builder > change column", () => { })); it("should correctly change column type", () => PromiseUtils.runInSequence(connections, async connection => { + + // TODO: https://github.com/cockroachdb/cockroach/issues/34710 + if (connection.driver instanceof CockroachDriver) + return; + const postMetadata = connection.getMetadata(Post); const versionColumn = postMetadata.findColumnWithPropertyName("version")!; versionColumn.type = "int"; @@ -95,6 +101,10 @@ describe("schema builder > change column", () => { })); it("should correctly make column primary and generated", () => PromiseUtils.runInSequence(connections, async connection => { + // CockroachDB does not allow changing PK + if (connection.driver instanceof CockroachDriver) + return; + const postMetadata = connection.getMetadata(Post); const idColumn = postMetadata.findColumnWithPropertyName("id")!; const versionColumn = postMetadata.findColumnWithPropertyName("version")!; @@ -147,6 +157,10 @@ describe("schema builder > change column", () => { })); it("should correctly change non-generated column on to uuid-generated column", () => PromiseUtils.runInSequence(connections, async connection => { + // CockroachDB does not allow changing PK + if (connection.driver instanceof CockroachDriver) + return; + const queryRunner = connection.createQueryRunner(); if (connection.driver instanceof PostgresDriver) @@ -158,7 +172,7 @@ describe("schema builder > change column", () => { idColumn.generationStrategy = "uuid"; // depending on driver, we must change column and referenced column types - if (connection.driver instanceof PostgresDriver) { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof CockroachDriver) { idColumn.type = "uuid"; } else if (connection.driver instanceof SqlServerDriver) { idColumn.type = "uniqueidentifier"; @@ -171,7 +185,7 @@ describe("schema builder > change column", () => { const postTable = await queryRunner.getTable("post"); await queryRunner.release(); - if (connection.driver instanceof PostgresDriver || connection.driver instanceof SqlServerDriver) { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof SqlServerDriver || connection.driver instanceof CockroachDriver) { postTable!.findColumnByName("id")!.isGenerated.should.be.true; postTable!.findColumnByName("id")!.generationStrategy!.should.be.equal("uuid"); @@ -191,6 +205,10 @@ describe("schema builder > change column", () => { })); it("should correctly change generated column generation strategy", () => PromiseUtils.runInSequence(connections, async connection => { + // CockroachDB does not allow changing PK + if (connection.driver instanceof CockroachDriver) + return; + const teacherMetadata = connection.getMetadata("teacher"); const studentMetadata = connection.getMetadata("student"); const idColumn = teacherMetadata.findColumnWithPropertyName("id")!; @@ -198,7 +216,7 @@ describe("schema builder > change column", () => { idColumn.generationStrategy = "uuid"; // depending on driver, we must change column and referenced column types - if (connection.driver instanceof PostgresDriver) { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof CockroachDriver) { idColumn.type = "uuid"; teacherColumn.type = "uuid"; } else if (connection.driver instanceof SqlServerDriver) { diff --git a/test/functional/schema-builder/change-index.ts b/test/functional/schema-builder/change-index.ts index c0c6e4a90..3f8f4548d 100644 --- a/test/functional/schema-builder/change-index.ts +++ b/test/functional/schema-builder/change-index.ts @@ -1,5 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {PromiseUtils} from "../../../src"; import {IndexMetadata} from "../../../src/metadata/IndexMetadata"; @@ -74,6 +75,8 @@ describe("schema builder > change index", () => { it("should ignore index synchronization when `synchronize` set to false", () => PromiseUtils.runInSequence(connections, async connection => { + // You can not disable synchronization for unique index in CockroachDB, because unique indices are stored as UNIQUE constraints + const queryRunner = connection.createQueryRunner(); let teacherTable = await queryRunner.getTable("teacher"); teacherTable!.indices.length.should.be.equal(0); @@ -82,14 +85,28 @@ describe("schema builder > change index", () => { await queryRunner.createIndex(teacherTable!, index); teacherTable = await queryRunner.getTable("teacher"); - teacherTable!.indices.length.should.be.equal(1); - teacherTable!.indices[0].isUnique!.should.be.true; + // CockroachDB stores unique indices as UNIQUE constraints + if (connection.driver instanceof CockroachDriver) { + teacherTable!.indices.length.should.be.equal(0); + teacherTable!.uniques.length.should.be.equal(1); + teacherTable!.findColumnByName("name")!.isUnique.should.be.true; + } else { + teacherTable!.indices.length.should.be.equal(1); + teacherTable!.indices[0].isUnique!.should.be.true; + } await connection.synchronize(); teacherTable = await queryRunner.getTable("teacher"); - teacherTable!.indices.length.should.be.equal(1); - teacherTable!.indices[0].isUnique!.should.be.true; + // CockroachDB stores unique indices as UNIQUE constraints + if (connection.driver instanceof CockroachDriver) { + teacherTable!.indices.length.should.be.equal(0); + teacherTable!.uniques.length.should.be.equal(0); + teacherTable!.findColumnByName("name")!.isUnique.should.be.false; + } else { + teacherTable!.indices.length.should.be.equal(1); + teacherTable!.indices[0].isUnique!.should.be.true; + } await queryRunner.release(); diff --git a/test/functional/schema-builder/create-foreign-key.ts b/test/functional/schema-builder/create-foreign-key.ts index a00ee8c98..a5b13b897 100644 --- a/test/functional/schema-builder/create-foreign-key.ts +++ b/test/functional/schema-builder/create-foreign-key.ts @@ -1,5 +1,7 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; +import {UniqueMetadata} from "../../../src/metadata/UniqueMetadata"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {ForeignKeyMetadata} from "../../../src/metadata/ForeignKeyMetadata"; @@ -21,6 +23,7 @@ describe("schema builder > create foreign key", () => { const postMetadata = connection.getMetadata("post"); const columns = categoryMetadata.columns.filter(column => ["postText", "postTag"].indexOf(column.propertyName) !== -1); const referencedColumns = postMetadata.columns.filter(column => ["text", "tag"].indexOf(column.propertyName) !== -1); + const fkMetadata = new ForeignKeyMetadata({ entityMetadata: categoryMetadata, referencedEntityMetadata: postMetadata, @@ -30,6 +33,19 @@ describe("schema builder > create foreign key", () => { }); categoryMetadata.foreignKeys.push(fkMetadata); + // CockroachDB requires unique constraint for foreign key referenced columns + if (connection.driver instanceof CockroachDriver) { + const uniqueConstraint = new UniqueMetadata({ + entityMetadata: categoryMetadata, + columns: fkMetadata.columns, + args: { + name: connection.namingStrategy.relationConstraintName(categoryMetadata.tablePath, fkMetadata.columns.map(c => c.databaseName)), + target: categoryMetadata.target, + } + }); + categoryMetadata.uniques.push(uniqueConstraint); + } + await connection.synchronize(); const queryRunner = connection.createQueryRunner(); diff --git a/test/functional/schema-builder/drop-column.ts b/test/functional/schema-builder/drop-column.ts index 66be37e4e..f0c006655 100644 --- a/test/functional/schema-builder/drop-column.ts +++ b/test/functional/schema-builder/drop-column.ts @@ -1,5 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {expect} from "chai"; @@ -17,6 +18,10 @@ describe("schema builder > drop column", () => { it("should correctly drop column", () => Promise.all(connections.map(async connection => { + // TODO: https://github.com/cockroachdb/cockroach/issues/34710 + if (connection.driver instanceof CockroachDriver) + return; + const studentMetadata = connection.getMetadata("student"); const removedColumns = studentMetadata.columns.filter(column => ["name", "faculty"].indexOf(column.propertyName) !== -1); removedColumns.forEach(column => { diff --git a/test/functional/schema-builder/update-primary-keys.ts b/test/functional/schema-builder/update-primary-keys.ts index 750a4d262..5f472287a 100644 --- a/test/functional/schema-builder/update-primary-keys.ts +++ b/test/functional/schema-builder/update-primary-keys.ts @@ -1,5 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; +import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {Category} from "./entity/Category"; import {Question} from "./entity/Question"; @@ -19,6 +20,10 @@ describe("schema builder > update primary keys", () => { it("should correctly update composite primary keys", () => Promise.all(connections.map(async connection => { + // CockroachDB does not support changing primary key constraint + if (connection.driver instanceof CockroachDriver) + return; + const metadata = connection.getMetadata(Category); const nameColumn = metadata.findColumnWithPropertyName("name"); nameColumn!.isPrimary = true; @@ -38,6 +43,10 @@ describe("schema builder > update primary keys", () => { if (connection.driver instanceof AbstractSqliteDriver) return; + // CockroachDB does not support changing primary key constraint + if (connection.driver instanceof CockroachDriver) + return; + const metadata = connection.getMetadata(Question); const nameColumn = metadata.findColumnWithPropertyName("name"); nameColumn!.isPrimary = true;