From 35b054b34cff59648844aa83d3acc32f05629cd6 Mon Sep 17 00:00:00 2001 From: Jocelyne Date: Thu, 1 Feb 2024 14:25:42 +0100 Subject: [PATCH] fix!: EXPOSED-285 Time default falsely triggers ALTER statement -`KotlinLocalTimeColumnType` now overrides `nonNullValueAsDefaultString` to match the default value obtained from the metadata for PostgreSQL. -In `nonNullValueToString` for `KotlinLocalTimeColumnType`, the formatted String for MySQL did not match the format received from the metadata, so a new formatter specific to MySQL is now used. --- .../api/exposed-kotlin-datetime.api | 1 + .../kotlin/datetime/KotlinDateColumnType.kt | 20 +++++++++++++++---- .../sql/kotlin/datetime/DefaultsTest.kt | 14 +++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/exposed-kotlin-datetime/api/exposed-kotlin-datetime.api b/exposed-kotlin-datetime/api/exposed-kotlin-datetime.api index a97c4641c1..08d5f0afc8 100644 --- a/exposed-kotlin-datetime/api/exposed-kotlin-datetime.api +++ b/exposed-kotlin-datetime/api/exposed-kotlin-datetime.api @@ -151,6 +151,7 @@ public final class org/jetbrains/exposed/sql/kotlin/datetime/KotlinLocalTimeColu public static final field Companion Lorg/jetbrains/exposed/sql/kotlin/datetime/KotlinLocalTimeColumnType$Companion; public fun ()V public fun getHasTimePart ()Z + public fun nonNullValueAsDefaultString (Ljava/lang/Object;)Ljava/lang/String; public fun nonNullValueToString (Ljava/lang/Object;)Ljava/lang/String; public fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/Object; public fun sqlType ()Ljava/lang/String; diff --git a/exposed-kotlin-datetime/src/main/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinDateColumnType.kt b/exposed-kotlin-datetime/src/main/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinDateColumnType.kt index 5ab588ea89..72cf1813f3 100644 --- a/exposed-kotlin-datetime/src/main/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinDateColumnType.kt +++ b/exposed-kotlin-datetime/src/main/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinDateColumnType.kt @@ -53,6 +53,13 @@ private val ORACLE_TIME_STRING_FORMATTER by lazy { ).withZone(ZoneId.of("UTC")) } +private val MYSQL_TIME_STRING_FORMATTER by lazy { + DateTimeFormatter.ofPattern( + "HH:mm:ss", + Locale.ROOT + ).withZone(ZoneId.systemDefault()) +} + private val DEFAULT_TIME_STRING_FORMATTER by lazy { DateTimeFormatter.ISO_LOCAL_TIME.withLocale(Locale.ROOT).withZone(ZoneId.systemDefault()) } @@ -237,10 +244,10 @@ class KotlinLocalTimeColumnType : ColumnType(), IDateColumnType { override fun sqlType(): String = currentDialect.dataTypeProvider.timeType() override fun nonNullValueToString(value: Any): String { - val formatter = if (currentDialect is OracleDialect || currentDialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle) { - ORACLE_TIME_STRING_FORMATTER - } else { - DEFAULT_TIME_STRING_FORMATTER + val formatter = when { + currentDialect is OracleDialect || currentDialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle -> ORACLE_TIME_STRING_FORMATTER + currentDialect is MysqlDialect -> MYSQL_TIME_STRING_FORMATTER + else -> DEFAULT_TIME_STRING_FORMATTER } val instant = when (value) { @@ -275,6 +282,11 @@ class KotlinLocalTimeColumnType : ColumnType(), IDateColumnType { else -> value } + override fun nonNullValueAsDefaultString(value: Any): String = when (currentDialect) { + is PostgreSQLDialect -> "${nonNullValueToString(value)}::time without time zone" + else -> super.nonNullValueAsDefaultString(value) + } + private fun longToLocalTime(millis: Long) = Instant.fromEpochMilliseconds(millis).toLocalDateTime(DEFAULT_TIME_ZONE).time companion object { diff --git a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/DefaultsTest.kt b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/DefaultsTest.kt index 507567b538..4fb58ac0a2 100644 --- a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/DefaultsTest.kt +++ b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/DefaultsTest.kt @@ -515,6 +515,20 @@ class DefaultsTest : DatabaseTestsBase() { } } + @Test + fun testTimeDefaultDoesNotTriggerAlterStatement() { + val time = Clock.System.now().toLocalDateTime(TimeZone.of("Japan")).time + + val tester = object : Table("tester") { + val timeWithDefault = time("timeWithDefault").default(time) + } + + withTables(tester) { + val statements = SchemaUtils.addMissingColumnsStatements(tester) + assertEquals(0, statements.size) + } + } + @Test fun testTimestampDefaultDoesNotTriggerAlterStatement() { val instant = Clock.System.now() // In UTC