testing driver functionality;

This commit is contained in:
Zotov Dmitry 2019-02-08 13:29:47 +05:00
parent 601cb19a8f
commit 9f6704e2e8
12 changed files with 213 additions and 11 deletions

View File

@ -321,7 +321,8 @@ export class CockroachDriver implements Driver {
if (value === null || value === undefined)
return value;
if (columnMetadata.type === Number && !columnMetadata.isArray) {
// unique_rowid() generates bigint value and should not be converted to number
if (columnMetadata.type === Number && !columnMetadata.isArray && !columnMetadata.isGenerated) {
value = parseInt(value);
} else if (columnMetadata.type === Boolean) {
@ -410,7 +411,7 @@ export class CockroachDriver implements Driver {
/**
* Creates a database type from a given column metadata.
*/
normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number|null, scale?: number, isArray?: boolean }): string {
normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number|null, scale?: number, isArray?: boolean, isGenerated?: boolean, generationStrategy?: "increment"|"uuid" }): string {
if (column.type === Number || column.type === "integer" || column.type === "int4") {
return "int";

View File

@ -1289,6 +1289,11 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner
tableColumn.name = dbColumn["column_name"];
tableColumn.type = dbColumn["crdb_sql_type"].toLowerCase();
if (dbColumn["crdb_sql_type"].indexOf("COLLATE") !== -1) {
tableColumn.collation = dbColumn["crdb_sql_type"].substr(dbColumn["crdb_sql_type"].indexOf("COLLATE") + "COLLATE".length + 1, dbColumn["crdb_sql_type"].length);
tableColumn.type = tableColumn.type.substr(0, dbColumn["crdb_sql_type"].indexOf("COLLATE") - 1);
}
if (tableColumn.type.indexOf("(") !== -1)
tableColumn.type = tableColumn.type.substr(0, tableColumn.type.indexOf("("));
@ -1332,7 +1337,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner
tableColumn.isGenerated = true;
tableColumn.generationStrategy = "increment";
} else if (/^uuid_generate_v\d\(\)/.test(dbColumn["column_default"])) {
} else if (dbColumn["column_default"] === "gen_random_uuid()") {
tableColumn.isGenerated = true;
tableColumn.generationStrategy = "uuid";
@ -1344,8 +1349,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner
tableColumn.comment = ""; // dbColumn["COLUMN_COMMENT"];
if (dbColumn["character_set_name"])
tableColumn.charset = dbColumn["character_set_name"];
if (dbColumn["collation_name"])
tableColumn.collation = dbColumn["collation_name"];
return tableColumn;
}));
@ -1689,7 +1693,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner
if (column.default !== undefined && column.default !== null)
c += " DEFAULT " + column.default;
if (column.isGenerated && column.generationStrategy === "uuid" && !column.default)
c += " DEFAULT uuid_generate_v4()";
c += " DEFAULT gen_random_uuid()";
return c;
}

View File

@ -1,3 +1,4 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {ObjectType} from "../common/ObjectType";
@ -258,7 +259,7 @@ export class DeleteQueryBuilder<Entity> extends QueryBuilder<Entity> implements
const whereExpression = this.createWhereExpression();
const returningExpression = this.createReturningExpression();
if (returningExpression && this.connection.driver instanceof PostgresDriver) {
if (returningExpression && (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof CockroachDriver)) {
return `DELETE FROM ${tableName}${whereExpression} RETURNING ${returningExpression}`;
} else if (returningExpression !== "" && this.connection.driver instanceof SqlServerDriver) {

View File

@ -1,3 +1,4 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {ObjectType} from "../common/ObjectType";
@ -316,7 +317,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
}
// add RETURNING expression
if (returningExpression && (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof OracleDriver)) {
if (returningExpression && (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof OracleDriver || this.connection.driver instanceof CockroachDriver)) {
query += ` RETURNING ${returningExpression}`;
}

View File

@ -1,3 +1,4 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {Connection} from "../connection/Connection";
@ -470,7 +471,7 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
const returningExpression = this.createReturningExpression();
// generate and return sql update query
if (returningExpression && (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof OracleDriver)) {
if (returningExpression && (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof OracleDriver || this.connection.driver instanceof CockroachDriver)) {
return `UPDATE ${this.getTableName(this.getMainTableName())} SET ${updateColumnAndValues.join(", ")}${whereExpression} RETURNING ${returningExpression}`;
} else if (returningExpression && this.connection.driver instanceof SqlServerDriver) {

View File

@ -0,0 +1,33 @@
import "reflect-metadata";
import {Post} from "./entity/Post";
import {Connection} from "../../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
describe("database schema > column collation > cockroach", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["cockroachdb"],
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should correctly create column with collation option", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(Post);
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post");
await queryRunner.release();
const post = new Post();
post.id = 1;
post.name = "Post";
await postRepository.save(post);
table!.findColumnByName("name")!.collation!.should.be.equal("en_US");
})));
});

View File

@ -0,0 +1,14 @@
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../../src/decorator/columns/Column";
@Entity()
export class Post {
@PrimaryColumn()
id: number;
@Column({ collation: "en_US" })
name: string;
}

View File

@ -0,0 +1,16 @@
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {Column} from "../../../../../src/decorator/columns/Column";
import {Generated} from "../../../../../src/decorator/Generated";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: string;
@Column()
@Generated("uuid")
uuid: string;
}

View File

@ -0,0 +1,26 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
import {Generated} from "../../../../../src/decorator/Generated";
@Entity()
export class Question {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
@Generated("uuid")
uuid: string;
@Column("uuid")
uuid2: string;
@Column("uuid", { nullable: true })
uuid3: string|null;
@Column({ nullable: true })
@Generated("uuid")
uuid4: string|null;
}

View File

@ -0,0 +1,10 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@Entity()
export class Record {
@PrimaryGeneratedColumn("uuid")
id: string;
}

View File

@ -0,0 +1,95 @@
import "reflect-metadata";
import {expect} from "chai";
import {Record} from "./entity/Record";
import {Connection} from "../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Post} from "./entity/Post";
import {Question} from "./entity/Question";
describe("uuid-cockroach", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["cockroachdb"],
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should make correct schema with CockroachDB uuid type", () => Promise.all(connections.map(async connection => {
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("record");
await queryRunner.release();
expect(table).not.to.be.empty;
expect(table!.columns.find(tableColumn => tableColumn.name === "id" && tableColumn.type === "uuid" && tableColumn.isGenerated)).to.be.not.empty;
})));
it("should persist uuid correctly", () => Promise.all(connections.map(async connection => {
const recordRepo = connection.getRepository(Record);
const record = new Record();
record.id = "fd357b8f-8838-42f6-b7a2-ae027444e895";
const persistedRecord = await recordRepo.save(record);
const foundRecord = await recordRepo.findOne(persistedRecord.id);
expect(foundRecord).to.be.exist;
expect(foundRecord!.id).to.eq("fd357b8f-8838-42f6-b7a2-ae027444e895");
})));
it("should persist uuid correctly when it is generated non primary column", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(Post);
const questionRepository = connection.getRepository(Question);
const queryRunner = connection.createQueryRunner();
const postTable = await queryRunner.getTable("post");
const questionTable = await queryRunner.getTable("question");
await queryRunner.release();
const post = new Post();
await postRepository.save(post);
const loadedPost = await postRepository.findOne(post.id);
expect(loadedPost!.uuid).to.be.exist;
postTable!.findColumnByName("uuid")!.type.should.be.equal("uuid");
const post2 = new Post();
post2.uuid = "fd357b8f-8838-42f6-b7a2-ae027444e895";
await postRepository.save(post2);
const loadedPost2 = await postRepository.findOne(post2.id);
expect(loadedPost2!.uuid).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
const question = new Question();
question.uuid2 = "fd357b8f-8838-42f6-b7a2-ae027444e895";
const savedQuestion = await questionRepository.save(question);
expect(savedQuestion!.id).to.be.exist;
expect(savedQuestion!.uuid).to.be.exist;
expect(savedQuestion!.uuid2).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
expect(savedQuestion!.uuid3).to.be.null;
expect(savedQuestion!.uuid4).to.be.exist;
const loadedQuestion = await questionRepository.findOne(savedQuestion.id);
expect(loadedQuestion!.id).to.be.exist;
expect(loadedQuestion!.uuid).to.be.exist;
expect(loadedQuestion!.uuid2).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
expect(loadedQuestion!.uuid3).to.be.null;
expect(loadedQuestion!.uuid4).to.be.exist;
questionTable!.findColumnByName("id")!.type.should.be.equal("uuid");
questionTable!.findColumnByName("uuid")!.type.should.be.equal("uuid");
questionTable!.findColumnByName("uuid2")!.type.should.be.equal("uuid");
questionTable!.findColumnByName("uuid3")!.type.should.be.equal("uuid");
const question2 = new Question();
question2.id = "1ecad7f6-23ee-453e-bb44-16eca26d5189";
question2.uuid = "35b44650-b2cd-44ec-aa54-137fbdf1c373";
question2.uuid2 = "fd357b8f-8838-42f6-b7a2-ae027444e895";
question2.uuid3 = null;
question2.uuid4 = null;
await questionRepository.save(question2);
const loadedQuestion2 = await questionRepository.findOne("1ecad7f6-23ee-453e-bb44-16eca26d5189");
expect(loadedQuestion2!.id).to.equal("1ecad7f6-23ee-453e-bb44-16eca26d5189");
expect(loadedQuestion2!.uuid).to.equal("35b44650-b2cd-44ec-aa54-137fbdf1c373");
expect(loadedQuestion2!.uuid2).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
expect(loadedQuestion2!.uuid3).to.be.null;
expect(loadedQuestion2!.uuid4).to.be.null;
})));
});

View File

@ -47,14 +47,14 @@ describe("uuid-postgres", () => {
const post = new Post();
await postRepository.save(post);
const loadedPost = await postRepository.findOne(1);
const loadedPost = await postRepository.findOne(post.id);
expect(loadedPost!.uuid).to.be.exist;
postTable!.findColumnByName("uuid")!.type.should.be.equal("uuid");
const post2 = new Post();
post2.uuid = "fd357b8f-8838-42f6-b7a2-ae027444e895";
await postRepository.save(post2);
const loadedPost2 = await postRepository.findOne(2);
const loadedPost2 = await postRepository.findOne(post2.id);
expect(loadedPost2!.uuid).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
const question = new Question();