Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mariadb uuid inet4 inet6 column data type support #9845

Merged
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:

# mariadb
mariadb:
image: "mariadb:10.8.4"
image: "mariadb:10.10.3"
container_name: "typeorm-mariadb"
ports:
- "3307:3306"
Expand Down
6 changes: 5 additions & 1 deletion docs/entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
10 changes: 8 additions & 2 deletions src/driver/mysql/MysqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ export class MysqlDriver implements Driver {
"multilinestring",
"multipolygon",
"geometrycollection",
// additional data types for mariadb
"uuid",
"inet4",
"inet6",
]

/**
Expand Down Expand Up @@ -720,7 +724,7 @@ export class MysqlDriver implements Driver {
return "blob"
} else if (column.type === Boolean) {
return "tinyint"
} else if (column.type === "uuid") {
} else if (column.type === "uuid" && this.options.type === "mysql") {
return "varchar"
} else if (column.type === "json" && this.options.type === "mariadb") {
/*
Expand Down Expand Up @@ -825,8 +829,10 @@ 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") return "36"
if (column.generationStrategy === "uuid" && column.type !== "uuid")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct me if I'm wrong, but from what I see for mysql generationStrategy is uuid and column type is uuid as well. But we don't return 36 in such case now, which is different from what we had before? If yes, this can cause issues for those who is using mysql right now.

Copy link
Contributor Author

@smith-xyz smith-xyz Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's correct I believe. It looks like before if the generationStrategy was "uuid" it would default the column type from "uuid" to "varchar". Then here if no length was attributed to the column, it would plug in "36" since mysql needs a length for the varchar.

Yes, in returning I see your point this does cause issues for existing users that need the column type to be a varchar here when they want the generation strategy to be uuid. I'll have to rethink this one. Let me know if you have any suggestions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pleerock my thoughts are that maybe PrimaryGeneratedColumnUUIDOptions should probably add one more property that allows for configuring the actual column type to be used so that this logic isn't tied up in the driver itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to save the scope of this PR only to mariadb. So we just need to add proper checks I avoid any breaking changes for mysql users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes good point.

For this, maybe it makes more sense to do this conditional to make it clear of the exact case its needed:
if (column.generationStrategy === "uuid" && column.type === "varchar") return 36

the reason its needed is because the generation strategy being uuid would default to varchar column type when normalized. Because of that when we get the column length it would wrongly do a length of 255 by default, but should be 36 in this case.

Other than that at line 727 the else if will check if the column type is "uuid" and if its a mysql driver it will default to varchar.

Let me know if that sounds correct and I can make the updates.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, sounds good. But please check again everything before it will be merged, just to make sure we didn't break user use cases.

Copy link
Contributor Author

@smith-xyz smith-xyz Apr 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a private property for seeing if the uuid data type can be used, if false then when generation strategy is uuid or if the column type is uuid and its not supported it will default to varchar as it use to. Also modified the conditional as mentioned. Added a regression test for mysql to the test suite. Let me know if anything else is needed.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we get a merge? @pleerock

return "36"

switch (column.type) {
case String:
Expand Down
4 changes: 3 additions & 1 deletion src/driver/types/ColumnTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/metadata-builder/JunctionEntityMetadataBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand Down
4 changes: 4 additions & 0 deletions src/metadata-builder/RelationJoinColumnBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
6 changes: 5 additions & 1 deletion test/github-issues/6540/entity/order.entity.ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
4 changes: 4 additions & 0 deletions test/github-issues/6540/issue-6540.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +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(
smith-xyz marked this conversation as resolved.
Show resolved Hide resolved
connection.driver.options.type,
sqlInMemory.upQueries,
)
sqlInMemory.upQueries.length.should.be.equal(0)
sqlInMemory.downQueries.length.should.be.equal(0)
}),
Expand Down
10 changes: 10 additions & 0 deletions test/github-issues/8832/badEntity/BadInet4.ts
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions test/github-issues/8832/badEntity/BadInet6.ts
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions test/github-issues/8832/badEntity/BadUuid.ts
Original file line number Diff line number Diff line change
@@ -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
}
22 changes: 22 additions & 0 deletions test/github-issues/8832/entity/Address.ts
Original file line number Diff line number Diff line change
@@ -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
}
30 changes: 30 additions & 0 deletions test/github-issues/8832/entity/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
Column,
Entity,
OneToMany,
PrimaryGeneratedColumn,
} from "../../../../src"
import { Address } from "./Address"

@Entity()
export class User {
@PrimaryGeneratedColumn("uuid")
id?: string

/** can use a default but testing against mysql since they're shared drivers */
@Column({ type: "uuid" })
uuid: string

@Column({ type: "inet4" })
inet4: string

@Column({ type: "inet6" })
inet6: string

/** testing generation */
@Column({ type: "uuid", generated: "uuid" })
another_uuid_field?: string

@OneToMany(() => Address, (address) => address.user)
addresses?: Address[]
}