From 3cfca913393a08009692773b80fb4cd044b065ab Mon Sep 17 00:00:00 2001 From: Jocelyne Date: Wed, 18 Dec 2024 19:08:13 +0100 Subject: [PATCH] feat: EXPOSED-654 Allow customizing the check constraint names of columns with check constraints --- exposed-core/api/exposed-core.api | 18 ++++++--- .../kotlin/org/jetbrains/exposed/sql/Table.kt | 39 ++++++++++++------- .../shared/types/NumericColumnTypesTests.kt | 31 +++++++++++++++ 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api index fa6f0174e8..30280279f2 100644 --- a/exposed-core/api/exposed-core.api +++ b/exposed-core/api/exposed-core.api @@ -2532,7 +2532,8 @@ public class org/jetbrains/exposed/sql/Table : org/jetbrains/exposed/sql/ColumnS public final fun blob (Ljava/lang/String;Z)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun blob$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun bool (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; - public final fun byte (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public final fun byte (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun byte$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun char (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; public final fun char (Ljava/lang/String;ILjava/lang/String;)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun char$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;ILjava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; @@ -2582,7 +2583,8 @@ public class org/jetbrains/exposed/sql/Table : org/jetbrains/exposed/sql/ColumnS public static synthetic fun index$default (Lorg/jetbrains/exposed/sql/Table;Lorg/jetbrains/exposed/sql/Column;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun index$default (Lorg/jetbrains/exposed/sql/Table;Z[Lorg/jetbrains/exposed/sql/Column;ILjava/lang/Object;)V public fun innerJoin (Lorg/jetbrains/exposed/sql/ColumnSet;)Lorg/jetbrains/exposed/sql/Join; - public final fun integer (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public final fun integer (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun integer$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public fun join (Lorg/jetbrains/exposed/sql/ColumnSet;Lorg/jetbrains/exposed/sql/JoinType;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;ZLkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Join; public final fun largeText (Ljava/lang/String;Ljava/lang/String;Z)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun largeText$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; @@ -2618,15 +2620,18 @@ public class org/jetbrains/exposed/sql/Table : org/jetbrains/exposed/sql/ColumnS public final fun registerCompositeColumn (Lorg/jetbrains/exposed/sql/CompositeColumn;)Lorg/jetbrains/exposed/sql/CompositeColumn; public final fun replaceColumn (Lorg/jetbrains/exposed/sql/Column;Lorg/jetbrains/exposed/sql/Column;)Lorg/jetbrains/exposed/sql/Column; public fun rightJoin (Lorg/jetbrains/exposed/sql/ColumnSet;)Lorg/jetbrains/exposed/sql/Join; - public final fun short (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public final fun short (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun short$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun text (Ljava/lang/String;Ljava/lang/String;Z)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun text$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun transform (Lorg/jetbrains/exposed/sql/Column;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Column; public final fun transform (Lorg/jetbrains/exposed/sql/Column;Lorg/jetbrains/exposed/sql/ColumnTransformer;)Lorg/jetbrains/exposed/sql/Column; public final fun transformNullable (Lorg/jetbrains/exposed/sql/Column;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Column; public final fun transformNullable (Lorg/jetbrains/exposed/sql/Column;Lorg/jetbrains/exposed/sql/ColumnTransformer;)Lorg/jetbrains/exposed/sql/Column; - public final fun ubyte (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; - public final fun uinteger (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public final fun ubyte (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun ubyte$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; + public final fun uinteger (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun uinteger$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun ulong (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; public final fun uniqueIndex (Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Lkotlin/jvm/functions/Function1;)V public final fun uniqueIndex (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; @@ -2634,7 +2639,8 @@ public class org/jetbrains/exposed/sql/Table : org/jetbrains/exposed/sql/ColumnS public static synthetic fun uniqueIndex$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public static synthetic fun uniqueIndex$default (Lorg/jetbrains/exposed/sql/Table;Lorg/jetbrains/exposed/sql/Column;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun uniqueIndex$default (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public final fun ushort (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public final fun ushort (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; + public static synthetic fun ushort$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; public final fun uuid (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column; public final fun varchar (Ljava/lang/String;ILjava/lang/String;)Lorg/jetbrains/exposed/sql/Column; public static synthetic fun varchar$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;ILjava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column; diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt index 11171dac14..0f63e07ac1 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt @@ -708,48 +708,57 @@ open class Table(name: String = "") : ColumnSet(), DdlAware { // Numeric columns - /** Creates a numeric column, with the specified [name], for storing 1-byte integers. */ - fun byte(name: String): Column = registerColumn(name, ByteColumnType()).apply { - check("${generatedSignedCheckPrefix}byte_${this.unquotedName()}") { it.between(Byte.MIN_VALUE, Byte.MAX_VALUE) } + /** Creates a numeric column, with the specified [name], for storing 1-byte integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. + */ + fun byte(name: String, checkConstraintName: String? = null): Column = registerColumn(name, ByteColumnType()).apply { + check(checkConstraintName ?: "${generatedSignedCheckPrefix}byte_${this.unquotedName()}") { it.between(Byte.MIN_VALUE, Byte.MAX_VALUE) } } /** Creates a numeric column, with the specified [name], for storing 1-byte unsigned integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. * * **Note:** If the database being used is not MySQL, MariaDB, or SQL Server, this column will use the * database's 2-byte integer type with a check constraint that ensures storage of only values * between 0 and [UByte.MAX_VALUE] inclusive. */ - fun ubyte(name: String): Column = registerColumn(name, UByteColumnType()).apply { - check("${generatedUnsignedCheckPrefix}byte_${this.unquotedName()}") { it.between(0u, UByte.MAX_VALUE) } + fun ubyte(name: String, checkConstraintName: String? = null): Column = registerColumn(name, UByteColumnType()).apply { + check(checkConstraintName ?: "${generatedUnsignedCheckPrefix}byte_${this.unquotedName()}") { it.between(0u, UByte.MAX_VALUE) } } - /** Creates a numeric column, with the specified [name], for storing 2-byte integers. */ - fun short(name: String): Column = registerColumn(name, ShortColumnType()).apply { - check("${generatedSignedCheckPrefix}short_${this.unquotedName()}") { it.between(Short.MIN_VALUE, Short.MAX_VALUE) } + /** Creates a numeric column, with the specified [name], for storing 2-byte integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. + */ + fun short(name: String, checkConstraintName: String? = null): Column = registerColumn(name, ShortColumnType()).apply { + check(checkConstraintName ?: "${generatedSignedCheckPrefix}short_${this.unquotedName()}") { it.between(Short.MIN_VALUE, Short.MAX_VALUE) } } /** Creates a numeric column, with the specified [name], for storing 2-byte unsigned integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. * * **Note:** If the database being used is not MySQL or MariaDB, this column will use the database's 4-byte * integer type with a check constraint that ensures storage of only values between 0 and [UShort.MAX_VALUE] inclusive. */ - fun ushort(name: String): Column = registerColumn(name, UShortColumnType()).apply { - check("$generatedUnsignedCheckPrefix${this.unquotedName()}") { it.between(0u, UShort.MAX_VALUE) } + fun ushort(name: String, checkConstraintName: String? = null): Column = registerColumn(name, UShortColumnType()).apply { + check(checkConstraintName ?: "$generatedUnsignedCheckPrefix${this.unquotedName()}") { it.between(0u, UShort.MAX_VALUE) } } - /** Creates a numeric column, with the specified [name], for storing 4-byte integers. */ - fun integer(name: String): Column = registerColumn(name, IntegerColumnType()).apply { - check("${generatedSignedCheckPrefix}integer_${this.unquotedName()}") { it.between(Int.MIN_VALUE, Int.MAX_VALUE) } + /** Creates a numeric column, with the specified [name], for storing 4-byte integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. + */ + fun integer(name: String, checkConstraintName: String? = null): Column = registerColumn(name, IntegerColumnType()).apply { + check(checkConstraintName ?: "${generatedSignedCheckPrefix}integer_${this.unquotedName()}") { it.between(Int.MIN_VALUE, Int.MAX_VALUE) } } /** Creates a numeric column, with the specified [name], for storing 4-byte unsigned integers. + * An optional [checkConstraintName] can be passed to allow customizing the check constraint name when needed. * * **Note:** If the database being used is not MySQL or MariaDB, this column will use the database's * 8-byte integer type with a check constraint that ensures storage of only values * between 0 and [UInt.MAX_VALUE] inclusive. */ - fun uinteger(name: String): Column = registerColumn(name, UIntegerColumnType()).apply { - check("$generatedUnsignedCheckPrefix${this.unquotedName()}") { it.between(0u, UInt.MAX_VALUE) } + fun uinteger(name: String, checkConstraintName: String? = null): Column = registerColumn(name, UIntegerColumnType()).apply { + check(checkConstraintName ?: "$generatedUnsignedCheckPrefix${this.unquotedName()}") { it.between(0u, UInt.MAX_VALUE) } } /** Creates a numeric column, with the specified [name], for storing 8-byte integers. */ diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/types/NumericColumnTypesTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/types/NumericColumnTypesTests.kt index 10dcaeaaeb..99b7714721 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/types/NumericColumnTypesTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/types/NumericColumnTypesTests.kt @@ -161,4 +161,35 @@ class NumericColumnTypesTests : DatabaseTestsBase() { ) } } + + @Test + fun testCustomCheckConstraintName() { + val tester = object : Table("tester") { + val byte = byte("byte_column", checkConstraintName = "custom_byte_check") + val ubyte = ubyte("ubyte_column", checkConstraintName = "custom_ubyte_check") + val short = short("short_column", checkConstraintName = "custom_short_check") + val ushort = ushort("ushort_column", checkConstraintName = "custom_ushort_check") + val integer = integer("integer_column", checkConstraintName = "custom_integer_check") + val uinteger = uinteger("uinteger_column", checkConstraintName = "custom_uinteger_check") + } + + withTables(tester) { + assertEquals( + "CREATE TABLE ${addIfNotExistsIfSupported()}${tester.nameInDatabaseCase()} (" + + "${tester.byte.nameInDatabaseCase()} ${tester.byte.columnType} NOT NULL, " + + "${tester.ubyte.nameInDatabaseCase()} ${tester.ubyte.columnType} NOT NULL, " + + "${tester.short.nameInDatabaseCase()} ${tester.short.columnType} NOT NULL, " + + "${tester.ushort.nameInDatabaseCase()} ${tester.ushort.columnType} NOT NULL, " + + "${tester.integer.nameInDatabaseCase()} ${tester.integer.columnType} NOT NULL, " + + "${tester.uinteger.nameInDatabaseCase()} ${tester.uinteger.columnType} NOT NULL, " + + "CONSTRAINT custom_byte_check CHECK (${tester.byte.nameInDatabaseCase()} BETWEEN ${Byte.MIN_VALUE} AND ${Byte.MAX_VALUE}), " + + "CONSTRAINT custom_ubyte_check CHECK (${tester.ubyte.nameInDatabaseCase()} BETWEEN 0 AND ${UByte.MAX_VALUE}), " + + "CONSTRAINT custom_short_check CHECK (${tester.short.nameInDatabaseCase()} BETWEEN ${Short.MIN_VALUE} AND ${Short.MAX_VALUE}), " + + "CONSTRAINT custom_ushort_check CHECK (${tester.ushort.nameInDatabaseCase()} BETWEEN 0 AND ${UShort.MAX_VALUE}), " + + "CONSTRAINT custom_integer_check CHECK (${tester.integer.nameInDatabaseCase()} BETWEEN ${Int.MIN_VALUE} AND ${Int.MAX_VALUE}), " + + "CONSTRAINT custom_uinteger_check CHECK (${tester.uinteger.nameInDatabaseCase()} BETWEEN 0 AND ${UInt.MAX_VALUE}))", + tester.ddl + ) + } + } }