From 89c21a2cecb6754eb39d565b6186e3114315a271 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 11 Mar 2023 09:53:12 -0500 Subject: [PATCH 01/12] feat: mariadb inet4, inet6, uuid data type support --- docker-compose.yml | 2 +- docs/entities.md | 6 +- src/driver/mysql/MysqlDriver.ts | 49 ++++++++++++++- src/driver/types/ColumnTypes.ts | 4 +- test/github-issues/8832/entity/User.ts | 16 +++++ test/github-issues/8832/issue-8832.ts | 85 ++++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 test/github-issues/8832/entity/User.ts create mode 100644 test/github-issues/8832/issue-8832.ts diff --git a/docker-compose.yml b/docker-compose.yml index a82254ec09..f2a93e4e23 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: # mariadb mariadb: - image: "mariadb:10.8.4" + image: "mariadb:10.10.3" container_name: "typeorm-mariadb" ports: - "3307:3306" diff --git a/docs/entities.md b/docs/entities.md index 43f4c94298..98b044a339 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -369,7 +369,11 @@ or `timestamp`, `time`, `year`, `char`, `nchar`, `national char`, `varchar`, `nvarchar`, `national varchar`, `text`, `tinytext`, `mediumtext`, `blob`, `longtext`, `tinyblob`, `mediumblob`, `longblob`, `enum`, `set`, `json`, `binary`, `varbinary`, `geometry`, `point`, `linestring`, `polygon`, `multipoint`, `multilinestring`, -`multipolygon`, `geometrycollection` +`multipolygon`, `geometrycollection`, `uuid`, `inet4`, `inet6` + +> Note: UUID, INET4, and INET6 are only available for mariadb and for respective versions that made them available. If provided and +> the current drive/version does not support the data type the default will be varchar + ### Column types for `postgres` diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 29766325c1..076a0144cc 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -152,6 +152,10 @@ export class MysqlDriver implements Driver { "multilinestring", "multipolygon", "geometrycollection", + // additional data types for mariadb + "uuid", + "inet4", + "inet6", ] /** @@ -721,8 +725,24 @@ export class MysqlDriver implements Driver { } else if (column.type === Boolean) { return "tinyint" } else if (column.type === "uuid") { - return "varchar" - } else if (column.type === "json" && this.options.type === "mariadb") { + /** + * MariaDb version 10.7.0 supports UUID type + * @see https://mariadb.com/kb/en/uuid-data-type/ + */ + return this.isUUIDColumnTypeSupported() ? "uuid" : "varchar" + } else if (column.type === "inet4") { + /** + * MariaDb version 10.10.0 supports INET4 type + * @see https://mariadb.com/kb/en/inet4/ + */ + return this.isInet4ColumnTypeSupported() ? "inet4" : "varchar" + } else if (column.type === "inet6") { + /** + * MariaDb version 10.5.0 supports INET6 type + * @see https://mariadb.com/kb/en/inet6/ + */ + return this.isInet6ColumnTypeSupported() ? "inet6" : "varchar" + }else if (column.type === "json" && this.options.type === "mariadb") { /* * MariaDB implements this as a LONGTEXT rather, as the JSON data type contradicts the SQL standard, * and MariaDB's benchmarks indicate that performance is at least equivalent. @@ -847,6 +867,13 @@ export class MysqlDriver implements Driver { createFullType(column: TableColumn): string { let type = column.type + if (type === "uuid" && this.isUUIDColumnTypeSupported()) { + return type + } + if (type === "inet" && this.isInet6ColumnTypeSupported()) { + type += "6" + return type + } // used 'getColumnLength()' method, because MySQL requires column length for `varchar`, `nvarchar` and `varbinary` data types if (this.getColumnLength(column)) { type += `(${this.getColumnLength(column)})` @@ -1126,6 +1153,24 @@ export class MysqlDriver implements Driver { return false } + /** + * MariaDb version 10.7.0 and greater allows UUID as a column type, however they do not allow this to be a default + */ + isUUIDColumnTypeSupported(): boolean { + return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.7.0") + } + + isInet4ColumnTypeSupported(): boolean { + return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.10.0") + } + + /** + * MariaDb version 10.5.0 and greater allows INET6 as a column type. + */ + isInet6ColumnTypeSupported(): boolean { + return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.5.0") + } + /** * Returns true if driver supports fulltext indices. */ diff --git a/src/driver/types/ColumnTypes.ts b/src/driver/types/ColumnTypes.ts index 105d4571bd..f40ec1a4f1 100644 --- a/src/driver/types/ColumnTypes.ts +++ b/src/driver/types/ColumnTypes.ts @@ -177,13 +177,15 @@ export type SimpleColumnType = | "set" // mysql | "cidr" // postgres | "inet" // postgres, cockroachdb + | "inet4" // mariadb + | "inet6" // mariadb | "macaddr" // postgres | "bit" // postgres, mssql | "bit varying" // postgres | "varbit" // postgres | "tsvector" // postgres | "tsquery" // postgres - | "uuid" // postgres, cockroachdb + | "uuid" // postgres, cockroachdb, mariadb | "xml" // mssql, postgres | "json" // mysql, postgres, cockroachdb, spanner | "jsonb" // postgres, cockroachdb diff --git a/test/github-issues/8832/entity/User.ts b/test/github-issues/8832/entity/User.ts new file mode 100644 index 0000000000..59a5febfd1 --- /dev/null +++ b/test/github-issues/8832/entity/User.ts @@ -0,0 +1,16 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class User { + @PrimaryGeneratedColumn("increment") + id?: number + + @Column({ type: "uuid", precision: 16 }) + uuid: string + + @Column({ type: "inet4" }) + inet4: string + + @Column({ type: "inet6" }) + inet6: string +} diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts new file mode 100644 index 0000000000..f2959b93ee --- /dev/null +++ b/test/github-issues/8832/issue-8832.ts @@ -0,0 +1,85 @@ +import "../../utils/test-setup" +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils" +import { DataSource } from "../../../src/index" +import { expect } from "chai" +import { User } from "../8832/entity/User" +import { VersionUtils } from "../../../src/util/VersionUtils" + +describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { + let connections: DataSource[] + + const newUser: User = { + uuid: "ceb2897c-a1cf-11ed-8dbd-040300000000", + inet4: "192.0.2.146", + inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", + } + + const expectedInet6 = "2001:db8::ff00:42:8329"; + + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql", "mariadb"], + })), + ) + beforeEach(() => reloadTestingDatabases(connections)) + after(() => closeTestingConnections(connections)) + + it("should create table with uuid type set to column for relevant mariadb versions", () => + Promise.all( + connections.map(async (connection) => { + const userRepository = connection.getRepository(User) + + const savedUser = await userRepository.save(newUser) + + const foundUser = await userRepository.find({ + where: { id: savedUser.id }, + }) + const { + options: { type }, + driver: { version = "0.0.0" }, + } = connection + + const { allowsUuidType, allowsInet4Type, allowsInet6Type } = { + allowsUuidType: type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.7.0"), + allowsInet4Type: type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.10.0"), + allowsInet6Type: type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.5.0") + } + + expect(foundUser[0].uuid).to.deep.equal(newUser.uuid) + expect(foundUser[0].inet6).to.deep.equal( + allowsInet6Type ? expectedInet6 : newUser.inet6, + ) + + const columnTypes: { COLUMN_NAME: string, DATA_TYPE: string}[] = await connection.query(` + SELECT + COLUMN_NAME, + DATA_TYPE + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_NAME = ? + AND COLUMN_NAME IN (?, ?, ?, ?) + `, ["user", "id", "uuid", "inet4", "inet6"]); + const expectedColumnTypes: Record = { + "id": "int", + "uuid": allowsUuidType ? "uuid" : "varchar", + "inet4": allowsInet4Type ? "inet4" : "varchar", + "inet6": allowsInet6Type ? "inet6" : "varchar" + }; + + columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { + expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]); + }); + }), + )) +}) From 4a8c454afae847ce95682da585d60f840b1e373d Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 11 Mar 2023 11:06:59 -0500 Subject: [PATCH 02/12] refactor: cleanup unnecessary methods --- src/driver/mysql/MysqlDriver.ts | 74 ++++++++++++-------------- test/github-issues/8832/entity/User.ts | 5 ++ test/github-issues/8832/issue-8832.ts | 11 ++-- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 076a0144cc..b4860ed196 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -314,6 +314,16 @@ export class MysqlDriver implements Driver { bigint: { width: 20 }, } + /** + * Managing version specific data types + */ + columnTypeVersionSupportMap = { + uuid: "varchar", + inet4: "varchar", + inet6: "varchar", + } + + /** * Max length allowed by MySQL for aliases. * @see https://dev.mysql.com/doc/refman/5.5/en/identifiers.html @@ -425,6 +435,27 @@ export class MysqlDriver implements Driver { if (VersionUtils.isGreaterOrEqual(dbVersion, "10.2.0")) { this.cteCapabilities.enabled = true } + /** + * MariaDb version 10.7.0 supports UUID type + * @see https://mariadb.com/kb/en/uuid-data-type/ + */ + if (VersionUtils.isGreaterOrEqual(dbVersion, "10.7.0")) { + this.columnTypeVersionSupportMap.uuid = "uuid"; + } + /** + * MariaDb version 10.10.0 supports INET4 type + * @see https://mariadb.com/kb/en/inet4/ + */ + if (VersionUtils.isGreaterOrEqual(dbVersion, "10.10.0")) { + this.columnTypeVersionSupportMap.inet4 = "inet4"; + } + /** + * MariaDb version 10.5.0 supports INET6 type + * @see https://mariadb.com/kb/en/inet6/ + */ + if (VersionUtils.isGreaterOrEqual(dbVersion, "10.5.0")) { + this.columnTypeVersionSupportMap.inet6 = "inet6"; + } } else if (this.options.type === "mysql") { if (VersionUtils.isGreaterOrEqual(dbVersion, "8.0.0")) { this.cteCapabilities.enabled = true @@ -725,23 +756,11 @@ export class MysqlDriver implements Driver { } else if (column.type === Boolean) { return "tinyint" } else if (column.type === "uuid") { - /** - * MariaDb version 10.7.0 supports UUID type - * @see https://mariadb.com/kb/en/uuid-data-type/ - */ - return this.isUUIDColumnTypeSupported() ? "uuid" : "varchar" + return this.columnTypeVersionSupportMap.uuid } else if (column.type === "inet4") { - /** - * MariaDb version 10.10.0 supports INET4 type - * @see https://mariadb.com/kb/en/inet4/ - */ - return this.isInet4ColumnTypeSupported() ? "inet4" : "varchar" + return this.columnTypeVersionSupportMap.inet4 } else if (column.type === "inet6") { - /** - * MariaDb version 10.5.0 supports INET6 type - * @see https://mariadb.com/kb/en/inet6/ - */ - return this.isInet6ColumnTypeSupported() ? "inet6" : "varchar" + return this.columnTypeVersionSupportMap.inet6 }else if (column.type === "json" && this.options.type === "mariadb") { /* * MariaDB implements this as a LONGTEXT rather, as the JSON data type contradicts the SQL standard, @@ -867,13 +886,6 @@ export class MysqlDriver implements Driver { createFullType(column: TableColumn): string { let type = column.type - if (type === "uuid" && this.isUUIDColumnTypeSupported()) { - return type - } - if (type === "inet" && this.isInet6ColumnTypeSupported()) { - type += "6" - return type - } // used 'getColumnLength()' method, because MySQL requires column length for `varchar`, `nvarchar` and `varbinary` data types if (this.getColumnLength(column)) { type += `(${this.getColumnLength(column)})` @@ -1153,24 +1165,6 @@ export class MysqlDriver implements Driver { return false } - /** - * MariaDb version 10.7.0 and greater allows UUID as a column type, however they do not allow this to be a default - */ - isUUIDColumnTypeSupported(): boolean { - return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.7.0") - } - - isInet4ColumnTypeSupported(): boolean { - return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.10.0") - } - - /** - * MariaDb version 10.5.0 and greater allows INET6 as a column type. - */ - isInet6ColumnTypeSupported(): boolean { - return this.options.type === "mariadb" && VersionUtils.isGreaterOrEqual(this.version ?? "0.0.0", "10.5.0") - } - /** * Returns true if driver supports fulltext indices. */ diff --git a/test/github-issues/8832/entity/User.ts b/test/github-issues/8832/entity/User.ts index 59a5febfd1..b54741ae20 100644 --- a/test/github-issues/8832/entity/User.ts +++ b/test/github-issues/8832/entity/User.ts @@ -5,6 +5,7 @@ export class User { @PrimaryGeneratedColumn("increment") id?: number + /** can use a default but testing against mysql since they're shared drivers */ @Column({ type: "uuid", precision: 16 }) uuid: string @@ -13,4 +14,8 @@ export class User { @Column({ type: "inet6" }) inet6: string + + /** testing generation */ + @Column({ type: "uuid", generated: "uuid" }) + anotherUuid?: string; } diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index f2959b93ee..9599ab8129 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -57,9 +57,11 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( } expect(foundUser[0].uuid).to.deep.equal(newUser.uuid) + expect(foundUser[0].inet4).to.deep.equal(newUser.inet4) expect(foundUser[0].inet6).to.deep.equal( allowsInet6Type ? expectedInet6 : newUser.inet6, ) + expect(foundUser[0].anotherUuid).to.not.be.undefined const columnTypes: { COLUMN_NAME: string, DATA_TYPE: string}[] = await connection.query(` SELECT @@ -69,17 +71,18 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( WHERE TABLE_NAME = ? AND COLUMN_NAME IN (?, ?, ?, ?) - `, ["user", "id", "uuid", "inet4", "inet6"]); + `, ["user", "id", "uuid", "inet4", "inet6", "anotherUuid"]) const expectedColumnTypes: Record = { "id": "int", "uuid": allowsUuidType ? "uuid" : "varchar", "inet4": allowsInet4Type ? "inet4" : "varchar", - "inet6": allowsInet6Type ? "inet6" : "varchar" - }; + "inet6": allowsInet6Type ? "inet6" : "varchar", + "anotherUuid": allowsUuidType ? "uuid" : "varchar", + } columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]); - }); + }) }), )) }) From f938bb55670bb63bbe703674a68dd0fcc0bb68c1 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 11 Mar 2023 11:10:24 -0500 Subject: [PATCH 03/12] style: mysqldriver formatting --- src/driver/mysql/MysqlDriver.ts | 11 ++++---- test/github-issues/8832/entity/User.ts | 2 +- test/github-issues/8832/issue-8832.ts | 39 ++++++++++++++++---------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index b4860ed196..d8bbcc065f 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -323,7 +323,6 @@ export class MysqlDriver implements Driver { inet6: "varchar", } - /** * Max length allowed by MySQL for aliases. * @see https://dev.mysql.com/doc/refman/5.5/en/identifiers.html @@ -440,21 +439,21 @@ export class MysqlDriver implements Driver { * @see https://mariadb.com/kb/en/uuid-data-type/ */ if (VersionUtils.isGreaterOrEqual(dbVersion, "10.7.0")) { - this.columnTypeVersionSupportMap.uuid = "uuid"; + this.columnTypeVersionSupportMap.uuid = "uuid" } /** * MariaDb version 10.10.0 supports INET4 type * @see https://mariadb.com/kb/en/inet4/ */ - if (VersionUtils.isGreaterOrEqual(dbVersion, "10.10.0")) { - this.columnTypeVersionSupportMap.inet4 = "inet4"; + if (VersionUtils.isGreaterOrEqual(dbVersion, "10.10.0")) { + this.columnTypeVersionSupportMap.inet4 = "inet4" } /** * MariaDb version 10.5.0 supports INET6 type * @see https://mariadb.com/kb/en/inet6/ */ if (VersionUtils.isGreaterOrEqual(dbVersion, "10.5.0")) { - this.columnTypeVersionSupportMap.inet6 = "inet6"; + this.columnTypeVersionSupportMap.inet6 = "inet6" } } else if (this.options.type === "mysql") { if (VersionUtils.isGreaterOrEqual(dbVersion, "8.0.0")) { @@ -761,7 +760,7 @@ export class MysqlDriver implements Driver { return this.columnTypeVersionSupportMap.inet4 } else if (column.type === "inet6") { return this.columnTypeVersionSupportMap.inet6 - }else if (column.type === "json" && this.options.type === "mariadb") { + } else if (column.type === "json" && this.options.type === "mariadb") { /* * MariaDB implements this as a LONGTEXT rather, as the JSON data type contradicts the SQL standard, * and MariaDB's benchmarks indicate that performance is at least equivalent. diff --git a/test/github-issues/8832/entity/User.ts b/test/github-issues/8832/entity/User.ts index b54741ae20..4e4202511f 100644 --- a/test/github-issues/8832/entity/User.ts +++ b/test/github-issues/8832/entity/User.ts @@ -17,5 +17,5 @@ export class User { /** testing generation */ @Column({ type: "uuid", generated: "uuid" }) - anotherUuid?: string; + anotherUuid?: string } diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 9599ab8129..a3563e88ee 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -18,7 +18,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", } - const expectedInet6 = "2001:db8::ff00:42:8329"; + const expectedInet6 = "2001:db8::ff00:42:8329" before( async () => @@ -48,12 +48,15 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( } = connection const { allowsUuidType, allowsInet4Type, allowsInet6Type } = { - allowsUuidType: type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.7.0"), - allowsInet4Type: type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.10.0"), - allowsInet6Type: type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.5.0") + allowsUuidType: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.7.0"), + allowsInet4Type: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.10.0"), + allowsInet6Type: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.5.0"), } expect(foundUser[0].uuid).to.deep.equal(newUser.uuid) @@ -63,7 +66,11 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( ) expect(foundUser[0].anotherUuid).to.not.be.undefined - const columnTypes: { COLUMN_NAME: string, DATA_TYPE: string}[] = await connection.query(` + const columnTypes: { + COLUMN_NAME: string + DATA_TYPE: string + }[] = await connection.query( + ` SELECT COLUMN_NAME, DATA_TYPE @@ -71,17 +78,19 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( WHERE TABLE_NAME = ? AND COLUMN_NAME IN (?, ?, ?, ?) - `, ["user", "id", "uuid", "inet4", "inet6", "anotherUuid"]) + `, + ["user", "id", "uuid", "inet4", "inet6", "anotherUuid"], + ) const expectedColumnTypes: Record = { - "id": "int", - "uuid": allowsUuidType ? "uuid" : "varchar", - "inet4": allowsInet4Type ? "inet4" : "varchar", - "inet6": allowsInet6Type ? "inet6" : "varchar", - "anotherUuid": allowsUuidType ? "uuid" : "varchar", + id: "int", + uuid: allowsUuidType ? "uuid" : "varchar", + inet4: allowsInet4Type ? "inet4" : "varchar", + inet6: allowsInet6Type ? "inet6" : "varchar", + anotherUuid: allowsUuidType ? "uuid" : "varchar", } columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { - expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]); + expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]) }) }), )) From 9fa50536f61c34e0aa265fceeebc2a295d1c87c7 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 18 Mar 2023 14:09:55 -0400 Subject: [PATCH 04/12] fix: handle length column metadata mariadb uuid --- src/driver/mysql/MysqlDriver.ts | 8 +- .../JunctionEntityMetadataBuilder.ts | 8 + .../RelationJoinColumnBuilder.ts | 4 + test/github-issues/8832/entity/Address.ts | 22 ++ test/github-issues/8832/entity/User.ts | 19 +- test/github-issues/8832/issue-8832.ts | 343 ++++++++++++++---- 6 files changed, 325 insertions(+), 79 deletions(-) create mode 100644 test/github-issues/8832/entity/Address.ts diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index d8bbcc065f..a0be7d3432 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -863,8 +863,14 @@ export class MysqlDriver implements Driver { /** * fix https://github.com/typeorm/typeorm/issues/1139 + * as part of adding uuid support for mariadb, we need to check that we aren't actually using the uuid type + * because this should not receive the length value by default */ - if (column.generationStrategy === "uuid") return "36" + if ( + this.columnTypeVersionSupportMap.uuid !== "uuid" && + column.generationStrategy === "uuid" + ) + return "36" switch (column.type) { case String: diff --git a/src/metadata-builder/JunctionEntityMetadataBuilder.ts b/src/metadata-builder/JunctionEntityMetadataBuilder.ts index d80632198a..6e1424ae6f 100644 --- a/src/metadata-builder/JunctionEntityMetadataBuilder.ts +++ b/src/metadata-builder/JunctionEntityMetadataBuilder.ts @@ -102,6 +102,10 @@ export class JunctionEntityMetadataBuilder { ) || this.connection.driver.options.type === "aurora-mysql") && + // some versions of mariadb support the column type and should not try to provide the length property + this.connection.driver.normalizeType( + referencedColumn, + ) !== "uuid" && (referencedColumn.generationStrategy === "uuid" || referencedColumn.type === "uuid") ? "36" @@ -166,6 +170,10 @@ export class JunctionEntityMetadataBuilder { ) || this.connection.driver.options.type === "aurora-mysql") && + // some versions of mariadb support the column type and should not try to provide the length property + this.connection.driver.normalizeType( + inverseReferencedColumn, + ) !== "uuid" && (inverseReferencedColumn.generationStrategy === "uuid" || inverseReferencedColumn.type === "uuid") diff --git a/src/metadata-builder/RelationJoinColumnBuilder.ts b/src/metadata-builder/RelationJoinColumnBuilder.ts index 5d32530ff3..143d405523 100644 --- a/src/metadata-builder/RelationJoinColumnBuilder.ts +++ b/src/metadata-builder/RelationJoinColumnBuilder.ts @@ -208,6 +208,10 @@ export class RelationJoinColumnBuilder { ) || this.connection.driver.options.type === "aurora-mysql") && + // some versions of mariadb support the column type and should not try to provide the length property + this.connection.driver.normalizeType( + referencedColumn, + ) !== "uuid" && (referencedColumn.generationStrategy === "uuid" || referencedColumn.type === "uuid") diff --git a/test/github-issues/8832/entity/Address.ts b/test/github-issues/8832/entity/Address.ts new file mode 100644 index 0000000000..b8256ebd69 --- /dev/null +++ b/test/github-issues/8832/entity/Address.ts @@ -0,0 +1,22 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, +} from "../../../../src" +import { User } from "./User" + +@Entity() +export class Address { + @PrimaryGeneratedColumn("increment") + id?: number + + @Column() + city: string + + @Column() + state: string + + @ManyToOne(() => User, (user) => user.addresses) + user: User +} diff --git a/test/github-issues/8832/entity/User.ts b/test/github-issues/8832/entity/User.ts index 4e4202511f..06d3fb9a2c 100644 --- a/test/github-issues/8832/entity/User.ts +++ b/test/github-issues/8832/entity/User.ts @@ -1,12 +1,18 @@ -import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src" +import { + Column, + Entity, + OneToMany, + PrimaryGeneratedColumn, +} from "../../../../src" +import { Address } from "./Address" @Entity() export class User { - @PrimaryGeneratedColumn("increment") - id?: number + @PrimaryGeneratedColumn("uuid") + id?: string /** can use a default but testing against mysql since they're shared drivers */ - @Column({ type: "uuid", precision: 16 }) + @Column({ type: "uuid" }) uuid: string @Column({ type: "inet4" }) @@ -17,5 +23,8 @@ export class User { /** testing generation */ @Column({ type: "uuid", generated: "uuid" }) - anotherUuid?: string + another_uuid_field?: string + + @OneToMany(() => Address, (address) => address.user) + addresses?: Address[] } diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index a3563e88ee..4d5928edca 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -4,94 +4,291 @@ import { closeTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" -import { DataSource } from "../../../src/index" +import { + Column, + DatabaseType, + DataSource, + Entity, + PrimaryGeneratedColumn, + TypeORMError, +} from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" import { VersionUtils } from "../../../src/util/VersionUtils" +import { Address } from "./entity/Address" + +function getSupportedTypesMap( + type: DatabaseType, + version: string, +): { + allowsUuidType: boolean + allowsInet4Type: boolean + allowsInet6Type: boolean +} { + return { + allowsUuidType: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.7.0"), + allowsInet4Type: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.10.0"), + allowsInet6Type: + type === "mariadb" && + VersionUtils.isGreaterOrEqual(version, "10.5.0"), + } +} describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { let connections: DataSource[] - const newUser: User = { - uuid: "ceb2897c-a1cf-11ed-8dbd-040300000000", - inet4: "192.0.2.146", - inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", - } + afterEach(() => closeTestingConnections(connections)) + + describe("basic use of new maria db types", () => { + const newUser: User = { + uuid: "ceb2897c-a1cf-11ed-8dbd-040300000000", + inet4: "192.0.2.146", + inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", + } + + const expectedInet6 = "2001:db8::ff00:42:8329" + + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql", "mariadb"], + })), + ) + beforeEach(() => reloadTestingDatabases(connections)) + + it("should create table with uuid type set to column for relevant mariadb versions", () => + Promise.all( + connections.map(async (connection) => { + const userRepository = connection.getRepository(User) + + // seems there is an issue with the persisting id that crosses over from mysql to mariadb + await userRepository.save(newUser) + + const savedUser = await userRepository.findOneOrFail({ + where: { uuid: newUser.uuid }, + }) + + const foundUser = await userRepository.findOne({ + where: { id: savedUser.id }, + }) + + const { + options: { type }, + driver: { version = "0.0.0" }, + } = connection + + const { allowsUuidType, allowsInet4Type, allowsInet6Type } = + getSupportedTypesMap(type, version) + + expect(foundUser).to.not.be.null + expect(foundUser!.uuid).to.deep.equal(newUser.uuid) + expect(foundUser!.inet4).to.deep.equal(newUser.inet4) + expect(foundUser!.inet6).to.deep.equal( + allowsInet6Type ? expectedInet6 : newUser.inet6, + ) + expect(foundUser!.another_uuid_field).to.not.be.undefined + + const columnTypes: { + COLUMN_NAME: string + DATA_TYPE: string + }[] = await connection.query( + ` + SELECT + COLUMN_NAME, + DATA_TYPE + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_SCHEMA = ? + AND TABLE_NAME = ? + AND COLUMN_NAME IN (?, ?, ?, ?) + `, + [ + connection.driver.database, + "user", + "id", + "uuid", + "inet4", + "inet6", + "anotherUuid", + ], + ) + const expectedColumnTypes: Record = { + id: allowsUuidType ? "uuid" : "varchar", + uuid: allowsUuidType ? "uuid" : "varchar", + inet4: allowsInet4Type ? "inet4" : "varchar", + inet6: allowsInet6Type ? "inet6" : "varchar", + another_uuid_field: allowsUuidType ? "uuid" : "varchar", + } + + columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { + expect(DATA_TYPE).to.equal( + expectedColumnTypes[COLUMN_NAME], + ) + }) + + // save a relation + const addressRepository = connection.getRepository(Address) + + const newAddress: Address = { + city: "Codersville", + state: "Coderado", + user: foundUser!, + } + + await addressRepository.save(newAddress) + + const foundAddress = await addressRepository.findOne({ + where: { user: { id: foundUser!.id } }, + }) + + expect(foundAddress).to.not.be.null + }), + )) + }) + + describe("errors using incorrect properties for maria db supported types", () => { + @Entity() + class BadUuidEntity { + @PrimaryGeneratedColumn("uuid") + id?: string + + @Column({ type: "uuid", length: "36" }) + badUuid: string + } + + @Entity() + class BadInet4Entity { + @PrimaryGeneratedColumn("uuid") + id?: string + + @Column({ type: "inet4", length: "28" }) + badinet4: string + } - const expectedInet6 = "2001:db8::ff00:42:8329" + @Entity() + class BadInet6Entity { + @PrimaryGeneratedColumn("uuid") + id?: string - before( - async () => - (connections = await createTestingConnections({ - entities: [__dirname + "/entity/*{.js,.ts}"], + @Column({ type: "inet6", length: "28" }) + badinet6: string + } + + afterEach(() => closeTestingConnections(connections)) + + it("should throw error when validating uuid type with a length provided only for mariadb", async () => { + const expectedError = new TypeORMError( + `Column badUuid of Entity BadUuidEntity does not support length property.`, + ) + + await createTestingConnections({ + entities: [BadUuidEntity], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mysql", "mariadb"], - })), - ) - beforeEach(() => reloadTestingDatabases(connections)) - after(() => closeTestingConnections(connections)) + enabledDrivers: ["mariadb"], + }) + .then(() => { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) + }) - it("should create table with uuid type set to column for relevant mariadb versions", () => - Promise.all( - connections.map(async (connection) => { - const userRepository = connection.getRepository(User) + await createTestingConnections({ + entities: [BadUuidEntity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"], + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", + ) + }) + }) - const savedUser = await userRepository.save(newUser) + it("should throw error when validating inet4 type with a length provided only for mariadb", async () => { + const expectedError = new TypeORMError( + `Column badinet4 of Entity BadInet4Entity does not support length property.`, + ) - const foundUser = await userRepository.find({ - where: { id: savedUser.id }, + await createTestingConnections({ + entities: [BadInet4Entity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mariadb"], + }) + .then(() => { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) }) - const { - options: { type }, - driver: { version = "0.0.0" }, - } = connection - - const { allowsUuidType, allowsInet4Type, allowsInet6Type } = { - allowsUuidType: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.7.0"), - allowsInet4Type: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.10.0"), - allowsInet6Type: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.5.0"), - } - - expect(foundUser[0].uuid).to.deep.equal(newUser.uuid) - expect(foundUser[0].inet4).to.deep.equal(newUser.inet4) - expect(foundUser[0].inet6).to.deep.equal( - allowsInet6Type ? expectedInet6 : newUser.inet6, - ) - expect(foundUser[0].anotherUuid).to.not.be.undefined - - const columnTypes: { - COLUMN_NAME: string - DATA_TYPE: string - }[] = await connection.query( - ` - SELECT - COLUMN_NAME, - DATA_TYPE - FROM INFORMATION_SCHEMA.COLUMNS - WHERE - TABLE_NAME = ? - AND COLUMN_NAME IN (?, ?, ?, ?) - `, - ["user", "id", "uuid", "inet4", "inet6", "anotherUuid"], + .catch((err) => { + expect(err.message).to.equal(expectedError.message) + }) + + connections = await createTestingConnections({ + entities: [BadInet4Entity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"], + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", ) - const expectedColumnTypes: Record = { - id: "int", - uuid: allowsUuidType ? "uuid" : "varchar", - inet4: allowsInet4Type ? "inet4" : "varchar", - inet6: allowsInet6Type ? "inet6" : "varchar", - anotherUuid: allowsUuidType ? "uuid" : "varchar", - } - - columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { - expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]) + }) + }) + + it("should throw error when validating inet6 type with a length provided", async () => { + const expectedError = new TypeORMError( + `Column badinet6 of Entity BadInet6Entity does not support length property.`, + ) + + await createTestingConnections({ + entities: [BadInet6Entity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mariadb"], + }) + .then(() => { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) }) - }), - )) + + connections = await createTestingConnections({ + entities: [BadInet6Entity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"], + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", + ) + }) + }) + }) }) From 1ade6b12d9b43da4d806b72a61d041d4b9be2ca3 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 18 Mar 2023 16:48:21 -0400 Subject: [PATCH 05/12] fix: 8832 test suite to verify errors correctly --- test/github-issues/8832/issue-8832.ts | 151 ++++++++++---------------- 1 file changed, 55 insertions(+), 96 deletions(-) diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 4d5928edca..61637acab7 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -4,28 +4,14 @@ import { closeTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" -import { - Column, - DatabaseType, - DataSource, - Entity, - PrimaryGeneratedColumn, - TypeORMError, -} from "../../../src/index" +import { Column, DatabaseType, DataSource, Entity, PrimaryGeneratedColumn, TypeORMError } from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" import { VersionUtils } from "../../../src/util/VersionUtils" import { Address } from "./entity/Address" -function getSupportedTypesMap( - type: DatabaseType, - version: string, -): { - allowsUuidType: boolean - allowsInet4Type: boolean - allowsInet6Type: boolean -} { - return { +function getSupportedTypesMap(type: DatabaseType, version: string): { allowsUuidType: boolean, allowsInet4Type: boolean; allowsInet6Type: boolean} { + return { allowsUuidType: type === "mariadb" && VersionUtils.isGreaterOrEqual(version, "10.7.0"), @@ -36,6 +22,7 @@ function getSupportedTypesMap( type === "mariadb" && VersionUtils.isGreaterOrEqual(version, "10.5.0"), } + } describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { @@ -49,44 +36,44 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( inet4: "192.0.2.146", inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", } - + const expectedInet6 = "2001:db8::ff00:42:8329" - + before( async () => (connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mysql", "mariadb"], + enabledDrivers: ["mysql", "mariadb"], })), ) beforeEach(() => reloadTestingDatabases(connections)) - + it("should create table with uuid type set to column for relevant mariadb versions", () => Promise.all( connections.map(async (connection) => { + const userRepository = connection.getRepository(User) - + // seems there is an issue with the persisting id that crosses over from mysql to mariadb await userRepository.save(newUser) - + const savedUser = await userRepository.findOneOrFail({ where: { uuid: newUser.uuid }, }) - + const foundUser = await userRepository.findOne({ where: { id: savedUser.id }, }) - + const { options: { type }, driver: { version = "0.0.0" }, } = connection - const { allowsUuidType, allowsInet4Type, allowsInet6Type } = - getSupportedTypesMap(type, version) - + const { allowsUuidType, allowsInet4Type, allowsInet6Type } = getSupportedTypesMap(type, version); + expect(foundUser).to.not.be.null expect(foundUser!.uuid).to.deep.equal(newUser.uuid) expect(foundUser!.inet4).to.deep.equal(newUser.inet4) @@ -94,7 +81,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( allowsInet6Type ? expectedInet6 : newUser.inet6, ) expect(foundUser!.another_uuid_field).to.not.be.undefined - + const columnTypes: { COLUMN_NAME: string DATA_TYPE: string @@ -109,15 +96,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( AND TABLE_NAME = ? AND COLUMN_NAME IN (?, ?, ?, ?) `, - [ - connection.driver.database, - "user", - "id", - "uuid", - "inet4", - "inet6", - "anotherUuid", - ], + [connection.driver.database, "user", "id", "uuid", "inet4", "inet6", "anotherUuid"], ) const expectedColumnTypes: Record = { id: allowsUuidType ? "uuid" : "varchar", @@ -126,15 +105,13 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( inet6: allowsInet6Type ? "inet6" : "varchar", another_uuid_field: allowsUuidType ? "uuid" : "varchar", } - + columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { - expect(DATA_TYPE).to.equal( - expectedColumnTypes[COLUMN_NAME], - ) + expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]) }) // save a relation - const addressRepository = connection.getRepository(Address) + const addressRepository = connection.getRepository(Address); const newAddress: Address = { city: "Codersville", @@ -152,14 +129,14 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( }), )) }) - - describe("errors using incorrect properties for maria db supported types", () => { + + describe("mariadb entity manager metadata validations for uuid, inet4, inet6 types", () => { @Entity() class BadUuidEntity { @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "uuid", length: "36" }) + @Column({ type: "uuid", length: "36"}) badUuid: string } @@ -168,7 +145,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "inet4", length: "28" }) + @Column({ type: "inet4", length: "28"}) badinet4: string } @@ -177,7 +154,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "inet6", length: "28" }) + @Column({ type: "inet6", length: "28"}) badinet6: string } @@ -193,29 +170,23 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], + }).then((conns) => { + if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsUuidType)) { + expect.fail(null, null, 'creating the connection did not reject with an error') + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) }) - .then(() => { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) await createTestingConnections({ entities: [BadUuidEntity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) + }) + .catch(() => { + expect.fail(null, null, 'creating the connection threw an unexpected error') }) }) @@ -229,29 +200,23 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], + }).then((conns) => { + if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsInet4Type)) { + expect.fail(null, null, 'creating the connection did not reject with an error') + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) }) - .then(() => { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) connections = await createTestingConnections({ entities: [BadInet4Entity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) + }) + .catch(() => { + expect.fail(null, null, 'creating the connection threw an unexpected error') }) }) @@ -265,29 +230,23 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], + }).then((conns) => { + if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsInet6Type)) { + expect.fail(null, null, 'creating the connection did not reject with an error') + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) }) - .then(() => { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) connections = await createTestingConnections({ entities: [BadInet6Entity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) + }) + .catch(() => { + expect.fail(null, null, 'creating the connection threw an unexpected error') }) }) }) From cd37c350ff127bc69b87e1a13d91372f338ef08d Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 18 Mar 2023 16:53:50 -0400 Subject: [PATCH 06/12] style: fix 8832 test formatting --- test/github-issues/8832/issue-8832.ts | 179 ++++++++++++++++++-------- 1 file changed, 125 insertions(+), 54 deletions(-) diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 61637acab7..dacb319e28 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -4,14 +4,28 @@ import { closeTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" -import { Column, DatabaseType, DataSource, Entity, PrimaryGeneratedColumn, TypeORMError } from "../../../src/index" +import { + Column, + DatabaseType, + DataSource, + Entity, + PrimaryGeneratedColumn, + TypeORMError, +} from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" import { VersionUtils } from "../../../src/util/VersionUtils" import { Address } from "./entity/Address" -function getSupportedTypesMap(type: DatabaseType, version: string): { allowsUuidType: boolean, allowsInet4Type: boolean; allowsInet6Type: boolean} { - return { +function getSupportedTypesMap( + type: DatabaseType, + version: string, +): { + allowsUuidType: boolean + allowsInet4Type: boolean + allowsInet6Type: boolean +} { + return { allowsUuidType: type === "mariadb" && VersionUtils.isGreaterOrEqual(version, "10.7.0"), @@ -22,7 +36,6 @@ function getSupportedTypesMap(type: DatabaseType, version: string): { allowsUuid type === "mariadb" && VersionUtils.isGreaterOrEqual(version, "10.5.0"), } - } describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { @@ -36,44 +49,44 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( inet4: "192.0.2.146", inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329", } - + const expectedInet6 = "2001:db8::ff00:42:8329" - + before( async () => (connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mysql", "mariadb"], + enabledDrivers: ["mysql", "mariadb"], })), ) beforeEach(() => reloadTestingDatabases(connections)) - + it("should create table with uuid type set to column for relevant mariadb versions", () => Promise.all( connections.map(async (connection) => { - const userRepository = connection.getRepository(User) - + // seems there is an issue with the persisting id that crosses over from mysql to mariadb await userRepository.save(newUser) - + const savedUser = await userRepository.findOneOrFail({ where: { uuid: newUser.uuid }, }) - + const foundUser = await userRepository.findOne({ where: { id: savedUser.id }, }) - + const { options: { type }, driver: { version = "0.0.0" }, } = connection - const { allowsUuidType, allowsInet4Type, allowsInet6Type } = getSupportedTypesMap(type, version); - + const { allowsUuidType, allowsInet4Type, allowsInet6Type } = + getSupportedTypesMap(type, version) + expect(foundUser).to.not.be.null expect(foundUser!.uuid).to.deep.equal(newUser.uuid) expect(foundUser!.inet4).to.deep.equal(newUser.inet4) @@ -81,7 +94,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( allowsInet6Type ? expectedInet6 : newUser.inet6, ) expect(foundUser!.another_uuid_field).to.not.be.undefined - + const columnTypes: { COLUMN_NAME: string DATA_TYPE: string @@ -96,7 +109,15 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( AND TABLE_NAME = ? AND COLUMN_NAME IN (?, ?, ?, ?) `, - [connection.driver.database, "user", "id", "uuid", "inet4", "inet6", "anotherUuid"], + [ + connection.driver.database, + "user", + "id", + "uuid", + "inet4", + "inet6", + "anotherUuid", + ], ) const expectedColumnTypes: Record = { id: allowsUuidType ? "uuid" : "varchar", @@ -105,13 +126,15 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( inet6: allowsInet6Type ? "inet6" : "varchar", another_uuid_field: allowsUuidType ? "uuid" : "varchar", } - + columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { - expect(DATA_TYPE).to.equal(expectedColumnTypes[COLUMN_NAME]) + expect(DATA_TYPE).to.equal( + expectedColumnTypes[COLUMN_NAME], + ) }) // save a relation - const addressRepository = connection.getRepository(Address); + const addressRepository = connection.getRepository(Address) const newAddress: Address = { city: "Codersville", @@ -129,14 +152,14 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( }), )) }) - + describe("mariadb entity manager metadata validations for uuid, inet4, inet6 types", () => { @Entity() class BadUuidEntity { @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "uuid", length: "36"}) + @Column({ type: "uuid", length: "36" }) badUuid: string } @@ -145,7 +168,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "inet4", length: "28"}) + @Column({ type: "inet4", length: "28" }) badinet4: string } @@ -154,7 +177,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( @PrimaryGeneratedColumn("uuid") id?: string - @Column({ type: "inet6", length: "28"}) + @Column({ type: "inet6", length: "28" }) badinet6: string } @@ -170,23 +193,39 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], - }).then((conns) => { - if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsUuidType)) { - expect.fail(null, null, 'creating the connection did not reject with an error') - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) }) + .then((conns) => { + if ( + conns.some( + (conn) => + getSupportedTypesMap( + conn.options.type, + conn.driver.version ?? "0.0.0", + ).allowsUuidType, + ) + ) { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) + }) await createTestingConnections({ entities: [BadUuidEntity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }) - .catch(() => { - expect.fail(null, null, 'creating the connection threw an unexpected error') + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", + ) }) }) @@ -200,23 +239,39 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], - }).then((conns) => { - if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsInet4Type)) { - expect.fail(null, null, 'creating the connection did not reject with an error') - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) }) + .then((conns) => { + if ( + conns.some( + (conn) => + getSupportedTypesMap( + conn.options.type, + conn.driver.version ?? "0.0.0", + ).allowsInet4Type, + ) + ) { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) + }) connections = await createTestingConnections({ entities: [BadInet4Entity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }) - .catch(() => { - expect.fail(null, null, 'creating the connection threw an unexpected error') + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", + ) }) }) @@ -230,23 +285,39 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( schemaCreate: true, dropSchema: true, enabledDrivers: ["mariadb"], - }).then((conns) => { - if (conns.some((conn) => getSupportedTypesMap(conn.options.type, conn.driver.version ?? "0.0.0").allowsInet6Type)) { - expect.fail(null, null, 'creating the connection did not reject with an error') - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) }) + .then((conns) => { + if ( + conns.some( + (conn) => + getSupportedTypesMap( + conn.options.type, + conn.driver.version ?? "0.0.0", + ).allowsInet6Type, + ) + ) { + expect.fail( + null, + null, + "creating the connection did not reject with an error", + ) + } + }) + .catch((err) => { + expect(err.message).to.equal(expectedError.message) + }) connections = await createTestingConnections({ entities: [BadInet6Entity], schemaCreate: true, dropSchema: true, enabledDrivers: ["mysql"], - }) - .catch(() => { - expect.fail(null, null, 'creating the connection threw an unexpected error') + }).catch(() => { + expect.fail( + null, + null, + "creating the connection threw an unexpected error", + ) }) }) }) From 9e780526a803659919c3464e9729c9c017fc2b2d Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:21:37 -0400 Subject: [PATCH 07/12] fix: 8832 error testing cleanup --- test/github-issues/8832/badEntity/BadInet4.ts | 10 + test/github-issues/8832/badEntity/BadInet6.ts | 10 + test/github-issues/8832/badEntity/BadUuid.ts | 10 + test/github-issues/8832/issue-8832.ts | 243 ++++++------------ 4 files changed, 105 insertions(+), 168 deletions(-) create mode 100644 test/github-issues/8832/badEntity/BadInet4.ts create mode 100644 test/github-issues/8832/badEntity/BadInet6.ts create mode 100644 test/github-issues/8832/badEntity/BadUuid.ts diff --git a/test/github-issues/8832/badEntity/BadInet4.ts b/test/github-issues/8832/badEntity/BadInet4.ts new file mode 100644 index 0000000000..35bace3c73 --- /dev/null +++ b/test/github-issues/8832/badEntity/BadInet4.ts @@ -0,0 +1,10 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class BadInet4 { + @PrimaryGeneratedColumn("uuid") + id?: string + + @Column({ type: "inet4", length: "36" }) + inet4: string +} diff --git a/test/github-issues/8832/badEntity/BadInet6.ts b/test/github-issues/8832/badEntity/BadInet6.ts new file mode 100644 index 0000000000..bf5ecc7a8e --- /dev/null +++ b/test/github-issues/8832/badEntity/BadInet6.ts @@ -0,0 +1,10 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class BadInet6 { + @PrimaryGeneratedColumn("uuid") + id?: string + + @Column({ type: "inet6", length: "36" }) + inet6: string +} diff --git a/test/github-issues/8832/badEntity/BadUuid.ts b/test/github-issues/8832/badEntity/BadUuid.ts new file mode 100644 index 0000000000..961a50baa8 --- /dev/null +++ b/test/github-issues/8832/badEntity/BadUuid.ts @@ -0,0 +1,10 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class BadUuid { + @PrimaryGeneratedColumn("uuid") + id?: string + + @Column({ type: "uuid", length: "36" }) + uuid: string +} diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index dacb319e28..5993f86c2d 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -4,18 +4,14 @@ import { closeTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" -import { - Column, - DatabaseType, - DataSource, - Entity, - PrimaryGeneratedColumn, - TypeORMError, -} from "../../../src/index" +import { DatabaseType, DataSource } from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" import { VersionUtils } from "../../../src/util/VersionUtils" import { Address } from "./entity/Address" +import { ConnectionMetadataBuilder } from "../../../src/connection/ConnectionMetadataBuilder" +import { EntityMetadataValidator } from "../../../src/metadata-builder/EntityMetadataValidator" +import { MysqlDriver } from "../../../src/driver/mysql/MysqlDriver" function getSupportedTypesMap( type: DatabaseType, @@ -153,172 +149,83 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( )) }) - describe("mariadb entity manager metadata validations for uuid, inet4, inet6 types", () => { - @Entity() - class BadUuidEntity { - @PrimaryGeneratedColumn("uuid") - id?: string - - @Column({ type: "uuid", length: "36" }) - badUuid: string - } - - @Entity() - class BadInet4Entity { - @PrimaryGeneratedColumn("uuid") - id?: string - - @Column({ type: "inet4", length: "28" }) - badinet4: string - } - - @Entity() - class BadInet6Entity { - @PrimaryGeneratedColumn("uuid") - id?: string - - @Column({ type: "inet6", length: "28" }) - badinet6: string - } - - afterEach(() => closeTestingConnections(connections)) + describe("entity-metadata-validator", () => { + it("should throw error if mariadb uuid is supported and length is provided to property", async () => { + Promise.all( + ["BadInet4", "BadInet6", "BadUuid"].map(async (entity) => { + const entityLocation = `${__dirname}/badEntity/${entity}{.js,.ts}"` + const connection = new DataSource({ + // dummy connection options, connection won't be established anyway + type: "mariadb", + host: "localhost", + username: "test", + password: "test", + database: "test", + entities: [entityLocation], + }) - it("should throw error when validating uuid type with a length provided only for mariadb", async () => { - const expectedError = new TypeORMError( - `Column badUuid of Entity BadUuidEntity does not support length property.`, + // version supports all the new types + connection.driver.version = "10.10.0" + const driver = connection.driver as MysqlDriver + driver.columnTypeVersionSupportMap.uuid = "uuid" + driver.columnTypeVersionSupportMap.inet4 = "inet4" + driver.columnTypeVersionSupportMap.inet6 = "inet6" + + const connectionMetadataBuilder = + new ConnectionMetadataBuilder(connection) + const entityMetadatas = + await connectionMetadataBuilder.buildEntityMetadatas([ + entityLocation, + ]) + const entityMetadataValidator = + new EntityMetadataValidator() + expect(() => + entityMetadataValidator.validateMany( + entityMetadatas, + connection.driver, + ), + ).to.throw(Error) + }), ) - - await createTestingConnections({ - entities: [BadUuidEntity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mariadb"], - }) - .then((conns) => { - if ( - conns.some( - (conn) => - getSupportedTypesMap( - conn.options.type, - conn.driver.version ?? "0.0.0", - ).allowsUuidType, - ) - ) { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) - - await createTestingConnections({ - entities: [BadUuidEntity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) - }) }) - it("should throw error when validating inet4 type with a length provided only for mariadb", async () => { - const expectedError = new TypeORMError( - `Column badinet4 of Entity BadInet4Entity does not support length property.`, - ) - - await createTestingConnections({ - entities: [BadInet4Entity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mariadb"], - }) - .then((conns) => { - if ( - conns.some( - (conn) => - getSupportedTypesMap( - conn.options.type, - conn.driver.version ?? "0.0.0", - ).allowsInet4Type, - ) - ) { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) - - connections = await createTestingConnections({ - entities: [BadInet4Entity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) - }) - }) + it("should not throw error for mysql when uuid is provided and a length property is provided", async () => { + Promise.all( + ["BadInet4", "BadInet6", "BadUuid"].map(async (entity) => { + const entityLocation = `${__dirname}/badEntity/${entity}{.js,.ts}"` + const connection = new DataSource({ + // dummy connection options, connection won't be established anyway + type: "mysql", + host: "localhost", + username: "test", + password: "test", + database: "test", + entities: [entityLocation], + }) - it("should throw error when validating inet6 type with a length provided", async () => { - const expectedError = new TypeORMError( - `Column badinet6 of Entity BadInet6Entity does not support length property.`, + // version supports all the new types + connection.driver.version = "10.10.0" + const driver = connection.driver as MysqlDriver + driver.columnTypeVersionSupportMap.uuid = "uuid" + driver.columnTypeVersionSupportMap.inet4 = "inet4" + driver.columnTypeVersionSupportMap.inet6 = "inet6" + + const connectionMetadataBuilder = + new ConnectionMetadataBuilder(connection) + const entityMetadatas = + await connectionMetadataBuilder.buildEntityMetadatas([ + entityLocation, + ]) + const entityMetadataValidator = + new EntityMetadataValidator() + expect(() => + entityMetadataValidator.validateMany( + entityMetadatas, + connection.driver, + ), + ).not.to.throw() + }), ) - - await createTestingConnections({ - entities: [BadInet6Entity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mariadb"], - }) - .then((conns) => { - if ( - conns.some( - (conn) => - getSupportedTypesMap( - conn.options.type, - conn.driver.version ?? "0.0.0", - ).allowsInet6Type, - ) - ) { - expect.fail( - null, - null, - "creating the connection did not reject with an error", - ) - } - }) - .catch((err) => { - expect(err.message).to.equal(expectedError.message) - }) - - connections = await createTestingConnections({ - entities: [BadInet6Entity], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mysql"], - }).catch(() => { - expect.fail( - null, - null, - "creating the connection threw an unexpected error", - ) - }) }) }) }) From c39dbec6ddef94abb5c4fee5ed27ad67d148fe5b Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 15 Apr 2023 12:15:12 -0400 Subject: [PATCH 08/12] fix: remove defaulting column type feature --- src/driver/mysql/MysqlDriver.ts | 47 ++----------- .../6540/entity/order.entity.ts.ts | 6 +- test/github-issues/6540/issue-6540.ts | 1 + test/github-issues/8832/issue-8832.ts | 69 ++++++------------- 4 files changed, 31 insertions(+), 92 deletions(-) diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index a0be7d3432..22579604c3 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -314,15 +314,6 @@ export class MysqlDriver implements Driver { bigint: { width: 20 }, } - /** - * Managing version specific data types - */ - columnTypeVersionSupportMap = { - uuid: "varchar", - inet4: "varchar", - inet6: "varchar", - } - /** * Max length allowed by MySQL for aliases. * @see https://dev.mysql.com/doc/refman/5.5/en/identifiers.html @@ -434,27 +425,6 @@ export class MysqlDriver implements Driver { if (VersionUtils.isGreaterOrEqual(dbVersion, "10.2.0")) { this.cteCapabilities.enabled = true } - /** - * MariaDb version 10.7.0 supports UUID type - * @see https://mariadb.com/kb/en/uuid-data-type/ - */ - if (VersionUtils.isGreaterOrEqual(dbVersion, "10.7.0")) { - this.columnTypeVersionSupportMap.uuid = "uuid" - } - /** - * MariaDb version 10.10.0 supports INET4 type - * @see https://mariadb.com/kb/en/inet4/ - */ - if (VersionUtils.isGreaterOrEqual(dbVersion, "10.10.0")) { - this.columnTypeVersionSupportMap.inet4 = "inet4" - } - /** - * MariaDb version 10.5.0 supports INET6 type - * @see https://mariadb.com/kb/en/inet6/ - */ - if (VersionUtils.isGreaterOrEqual(dbVersion, "10.5.0")) { - this.columnTypeVersionSupportMap.inet6 = "inet6" - } } else if (this.options.type === "mysql") { if (VersionUtils.isGreaterOrEqual(dbVersion, "8.0.0")) { this.cteCapabilities.enabled = true @@ -754,12 +724,8 @@ export class MysqlDriver implements Driver { return "blob" } else if (column.type === Boolean) { return "tinyint" - } else if (column.type === "uuid") { - return this.columnTypeVersionSupportMap.uuid - } else if (column.type === "inet4") { - return this.columnTypeVersionSupportMap.inet4 - } else if (column.type === "inet6") { - return this.columnTypeVersionSupportMap.inet6 + } else if (column.type === "uuid" && this.options.type === "mysql") { + return "varchar" } else if (column.type === "json" && this.options.type === "mariadb") { /* * MariaDB implements this as a LONGTEXT rather, as the JSON data type contradicts the SQL standard, @@ -863,14 +829,9 @@ export class MysqlDriver implements Driver { /** * fix https://github.com/typeorm/typeorm/issues/1139 - * as part of adding uuid support for mariadb, we need to check that we aren't actually using the uuid type - * because this should not receive the length value by default + * note that if the db did support uuid column type it wouldn't have been defaulted to varchar */ - if ( - this.columnTypeVersionSupportMap.uuid !== "uuid" && - column.generationStrategy === "uuid" - ) - return "36" + if (column.generationStrategy === "uuid" && column.type !== "uuid") return "36" switch (column.type) { case String: diff --git a/test/github-issues/6540/entity/order.entity.ts.ts b/test/github-issues/6540/entity/order.entity.ts.ts index a10ba9b587..1592ef9a9b 100644 --- a/test/github-issues/6540/entity/order.entity.ts.ts +++ b/test/github-issues/6540/entity/order.entity.ts.ts @@ -16,7 +16,11 @@ export enum OrderStatus { @Entity() export class Order extends BaseEntity { - @PrimaryGeneratedColumn("uuid") + /** + * modified to remove the uuid since some versions of mariadb have uuid as a type + * which would create an additional upsert between the tests -> https://github.com/typeorm/typeorm/issues/8832 + */ + @PrimaryGeneratedColumn() id: string @Column({ type: "enum", enum: OrderStatus }) diff --git a/test/github-issues/6540/issue-6540.ts b/test/github-issues/6540/issue-6540.ts index 95d44d2cb0..8ccdf30040 100644 --- a/test/github-issues/6540/issue-6540.ts +++ b/test/github-issues/6540/issue-6540.ts @@ -38,6 +38,7 @@ describe("github issues > #6540 Enum not resolved if it is from an external file const sqlInMemory = await connection.driver .createSchemaBuilder() .log() + console.log(connection.driver.options.type, sqlInMemory.upQueries) sqlInMemory.upQueries.length.should.be.equal(0) sqlInMemory.downQueries.length.should.be.equal(0) }), diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 5993f86c2d..70339450d0 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -7,32 +7,9 @@ import { import { DatabaseType, DataSource } from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" -import { VersionUtils } from "../../../src/util/VersionUtils" import { Address } from "./entity/Address" import { ConnectionMetadataBuilder } from "../../../src/connection/ConnectionMetadataBuilder" import { EntityMetadataValidator } from "../../../src/metadata-builder/EntityMetadataValidator" -import { MysqlDriver } from "../../../src/driver/mysql/MysqlDriver" - -function getSupportedTypesMap( - type: DatabaseType, - version: string, -): { - allowsUuidType: boolean - allowsInet4Type: boolean - allowsInet6Type: boolean -} { - return { - allowsUuidType: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.7.0"), - allowsInet4Type: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.10.0"), - allowsInet6Type: - type === "mariadb" && - VersionUtils.isGreaterOrEqual(version, "10.5.0"), - } -} describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { let connections: DataSource[] @@ -54,7 +31,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( entities: [__dirname + "/entity/*{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mysql", "mariadb"], + enabledDrivers: ["mariadb"], })), ) beforeEach(() => reloadTestingDatabases(connections)) @@ -75,20 +52,10 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( where: { id: savedUser.id }, }) - const { - options: { type }, - driver: { version = "0.0.0" }, - } = connection - - const { allowsUuidType, allowsInet4Type, allowsInet6Type } = - getSupportedTypesMap(type, version) - expect(foundUser).to.not.be.null expect(foundUser!.uuid).to.deep.equal(newUser.uuid) expect(foundUser!.inet4).to.deep.equal(newUser.inet4) - expect(foundUser!.inet6).to.deep.equal( - allowsInet6Type ? expectedInet6 : newUser.inet6, - ) + expect(foundUser!.inet6).to.deep.equal(expectedInet6) expect(foundUser!.another_uuid_field).to.not.be.undefined const columnTypes: { @@ -116,11 +83,11 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( ], ) const expectedColumnTypes: Record = { - id: allowsUuidType ? "uuid" : "varchar", - uuid: allowsUuidType ? "uuid" : "varchar", - inet4: allowsInet4Type ? "inet4" : "varchar", - inet6: allowsInet6Type ? "inet6" : "varchar", - another_uuid_field: allowsUuidType ? "uuid" : "varchar", + id: "uuid", + uuid: "uuid", + inet4: "inet4", + inet6: "inet6", + another_uuid_field: "uuid", } columnTypes.forEach(({ COLUMN_NAME, DATA_TYPE }) => { @@ -149,6 +116,20 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( )) }) + describe("using new mariadb types with mysql driver", () => { + it("should throw an error when mysql attempts to use the uuid, inet4, inet6 database types", () => + Promise.all( + ["mysql"].map(async (dbType: DatabaseType) => { + return createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: [dbType], + }).should.be.rejected + }), + )) + }) + describe("entity-metadata-validator", () => { it("should throw error if mariadb uuid is supported and length is provided to property", async () => { Promise.all( @@ -166,10 +147,6 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( // version supports all the new types connection.driver.version = "10.10.0" - const driver = connection.driver as MysqlDriver - driver.columnTypeVersionSupportMap.uuid = "uuid" - driver.columnTypeVersionSupportMap.inet4 = "inet4" - driver.columnTypeVersionSupportMap.inet6 = "inet6" const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection) @@ -205,10 +182,6 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( // version supports all the new types connection.driver.version = "10.10.0" - const driver = connection.driver as MysqlDriver - driver.columnTypeVersionSupportMap.uuid = "uuid" - driver.columnTypeVersionSupportMap.inet4 = "inet4" - driver.columnTypeVersionSupportMap.inet6 = "inet6" const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection) From 8253ce7e9e11ac18f400e312bc6ccb6617383c1f Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 15 Apr 2023 12:17:09 -0400 Subject: [PATCH 09/12] style: fix formatting --- src/driver/mysql/MysqlDriver.ts | 3 ++- test/github-issues/6540/issue-6540.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 22579604c3..3e2dee6f9f 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -831,7 +831,8 @@ export class MysqlDriver implements Driver { * fix https://github.com/typeorm/typeorm/issues/1139 * note that if the db did support uuid column type it wouldn't have been defaulted to varchar */ - if (column.generationStrategy === "uuid" && column.type !== "uuid") return "36" + if (column.generationStrategy === "uuid" && column.type !== "uuid") + return "36" switch (column.type) { case String: diff --git a/test/github-issues/6540/issue-6540.ts b/test/github-issues/6540/issue-6540.ts index 8ccdf30040..0f30dc2605 100644 --- a/test/github-issues/6540/issue-6540.ts +++ b/test/github-issues/6540/issue-6540.ts @@ -38,7 +38,10 @@ describe("github issues > #6540 Enum not resolved if it is from an external file const sqlInMemory = await connection.driver .createSchemaBuilder() .log() - console.log(connection.driver.options.type, sqlInMemory.upQueries) + console.log( + connection.driver.options.type, + sqlInMemory.upQueries, + ) sqlInMemory.upQueries.length.should.be.equal(0) sqlInMemory.downQueries.length.should.be.equal(0) }), From 165fa2389e5b57ea50a3ec6965fca1635dacb1ff Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 15 Apr 2023 12:26:52 -0400 Subject: [PATCH 10/12] fix: remove unnecessary dbms error test --- test/github-issues/8832/issue-8832.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 70339450d0..12a1861b01 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -116,20 +116,6 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( )) }) - describe("using new mariadb types with mysql driver", () => { - it("should throw an error when mysql attempts to use the uuid, inet4, inet6 database types", () => - Promise.all( - ["mysql"].map(async (dbType: DatabaseType) => { - return createTestingConnections({ - entities: [__dirname + "/entity/*{.js,.ts}"], - schemaCreate: true, - dropSchema: true, - enabledDrivers: [dbType], - }).should.be.rejected - }), - )) - }) - describe("entity-metadata-validator", () => { it("should throw error if mariadb uuid is supported and length is provided to property", async () => { Promise.all( From 0cffbe6a19b35ceb429b6d9f678d4e1b4c136269 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Sat, 15 Apr 2023 12:31:08 -0400 Subject: [PATCH 11/12] fix: remove unused import in test --- test/github-issues/8832/issue-8832.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index 12a1861b01..ec64dac51f 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -4,7 +4,7 @@ import { closeTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" -import { DatabaseType, DataSource } from "../../../src/index" +import { DataSource } from "../../../src/index" import { expect } from "chai" import { User } from "../8832/entity/User" import { Address } from "./entity/Address" From a7213fc6604e40566726cba3dd50abdf33736955 Mon Sep 17 00:00:00 2001 From: smith-xyz <51304449+smith-xyz@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:25:32 -0400 Subject: [PATCH 12/12] fix: ensure defaulting uuid generation column type --- docs/entities.md | 3 +- src/driver/mysql/MysqlDriver.ts | 10 +++- test/github-issues/6540/issue-6540.ts | 4 -- test/github-issues/8832/entity/UuidEntity.ts | 7 +++ test/github-issues/8832/issue-8832.ts | 60 +++++++++++++++++++- 5 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 test/github-issues/8832/entity/UuidEntity.ts diff --git a/docs/entities.md b/docs/entities.md index 98b044a339..c061f74ef2 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -371,8 +371,7 @@ or `json`, `binary`, `varbinary`, `geometry`, `point`, `linestring`, `polygon`, `multipoint`, `multilinestring`, `multipolygon`, `geometrycollection`, `uuid`, `inet4`, `inet6` -> Note: UUID, INET4, and INET6 are only available for mariadb and for respective versions that made them available. If provided and -> the current drive/version does not support the data type the default will be varchar +> Note: UUID, INET4, and INET6 are only available for mariadb and for respective versions that made them available. ### Column types for `postgres` diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 3e2dee6f9f..144398bab6 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -335,6 +335,9 @@ export class MysqlDriver implements Driver { update: false, } + /** MariaDB supports uuid type for version 10.7.0 and up */ + private uuidColumnTypeSuported = false + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -425,6 +428,9 @@ export class MysqlDriver implements Driver { if (VersionUtils.isGreaterOrEqual(dbVersion, "10.2.0")) { this.cteCapabilities.enabled = true } + if (VersionUtils.isGreaterOrEqual(dbVersion, "10.7.0")) { + this.uuidColumnTypeSuported = true + } } else if (this.options.type === "mysql") { if (VersionUtils.isGreaterOrEqual(dbVersion, "8.0.0")) { this.cteCapabilities.enabled = true @@ -724,7 +730,7 @@ export class MysqlDriver implements Driver { return "blob" } else if (column.type === Boolean) { return "tinyint" - } else if (column.type === "uuid" && this.options.type === "mysql") { + } else if (column.type === "uuid" && !this.uuidColumnTypeSuported) { return "varchar" } else if (column.type === "json" && this.options.type === "mariadb") { /* @@ -831,7 +837,7 @@ export class MysqlDriver implements Driver { * fix https://github.com/typeorm/typeorm/issues/1139 * note that if the db did support uuid column type it wouldn't have been defaulted to varchar */ - if (column.generationStrategy === "uuid" && column.type !== "uuid") + if (column.generationStrategy === "uuid" && column.type === "varchar") return "36" switch (column.type) { diff --git a/test/github-issues/6540/issue-6540.ts b/test/github-issues/6540/issue-6540.ts index 0f30dc2605..95d44d2cb0 100644 --- a/test/github-issues/6540/issue-6540.ts +++ b/test/github-issues/6540/issue-6540.ts @@ -38,10 +38,6 @@ describe("github issues > #6540 Enum not resolved if it is from an external file const sqlInMemory = await connection.driver .createSchemaBuilder() .log() - console.log( - connection.driver.options.type, - sqlInMemory.upQueries, - ) sqlInMemory.upQueries.length.should.be.equal(0) sqlInMemory.downQueries.length.should.be.equal(0) }), diff --git a/test/github-issues/8832/entity/UuidEntity.ts b/test/github-issues/8832/entity/UuidEntity.ts new file mode 100644 index 0000000000..d887673025 --- /dev/null +++ b/test/github-issues/8832/entity/UuidEntity.ts @@ -0,0 +1,7 @@ +import { Entity, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class UuidEntity { + @PrimaryGeneratedColumn("uuid") + id?: string +} diff --git a/test/github-issues/8832/issue-8832.ts b/test/github-issues/8832/issue-8832.ts index ec64dac51f..214e4f35c1 100644 --- a/test/github-issues/8832/issue-8832.ts +++ b/test/github-issues/8832/issue-8832.ts @@ -10,6 +10,7 @@ import { User } from "../8832/entity/User" import { Address } from "./entity/Address" import { ConnectionMetadataBuilder } from "../../../src/connection/ConnectionMetadataBuilder" import { EntityMetadataValidator } from "../../../src/metadata-builder/EntityMetadataValidator" +import { UuidEntity } from "./entity/UuidEntity" describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => { let connections: DataSource[] @@ -36,7 +37,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( ) beforeEach(() => reloadTestingDatabases(connections)) - it("should create table with uuid type set to column for relevant mariadb versions", () => + it("should create table with uuid, inet4, and inet6 type set to column for relevant mariadb versions", () => Promise.all( connections.map(async (connection) => { const userRepository = connection.getRepository(User) @@ -116,6 +117,63 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", ( )) }) + describe("regression test mysql uuid generation", () => { + const uuidEntity: UuidEntity = { + id: "ceb2897c-a1cf-11ed-8dbd-040300000000", + } + + before( + async () => + (connections = await createTestingConnections({ + entities: [UuidEntity], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql", "mariadb"], + })), + ) + beforeEach(() => reloadTestingDatabases(connections)) + + it("should create table with with varchar with length 36 when version is mysql", () => + Promise.all( + connections.map(async (connection) => { + const uuidRepository = connection.getRepository(UuidEntity) + + // seems there is an issue with the persisting id that crosses over from mysql to mariadb + await uuidRepository.save(uuidEntity) + + const columnTypes: { + DATA_TYPE: string + CHARACTER_MAXIMUM_LENGTH: string + }[] = await connection.query( + ` + SELECT + DATA_TYPE, + CHARACTER_MAXIMUM_LENGTH + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_SCHEMA = ? + AND TABLE_NAME = ? + AND COLUMN_NAME = ? + `, + [connection.driver.database, "UuidEntity", "id"], + ) + + const isMysql = connection.driver.options.type === "mysql" + const expectedType = isMysql ? "varchar" : "uuid" + const expectedLength = isMysql ? "36" : null + + columnTypes.forEach( + ({ DATA_TYPE, CHARACTER_MAXIMUM_LENGTH }) => { + expect(DATA_TYPE).to.equal(expectedType) + expect(CHARACTER_MAXIMUM_LENGTH).to.equal( + expectedLength, + ) + }, + ) + }), + )) + }) + describe("entity-metadata-validator", () => { it("should throw error if mariadb uuid is supported and length is provided to property", async () => { Promise.all(