From 1c83342822f1ceb2756e9bd7855b9b3a75e1e8dc Mon Sep 17 00:00:00 2001 From: huangwenhai Date: Mon, 29 Jan 2024 17:55:35 +0800 Subject: [PATCH 1/2] fix: EXPOSED-270 Respect `Duration.INFINITE` for duration column type Exposed converts Duration to its nanoseconds value when writing to database, and uses the kotlin `Long.nanoseconds` function to convert Long to Duration when reading from database. If inserting the `Duration.INFINITE` value, the saving value in database is 9223372036854775807(`Long.MAX_VALUE`). However, the kotlin `Long.nanoseconds` function checks `Long.MAX_VALUE` exceeding the nanosecond range and then converts it to millisecond unit, causing the ignoring of last few digits of the value. Therefore, the reading value does not equal to `Duration.INFINITE` anymore. This bug can be fixed by first checking the equality of the value and `Duration.INFINITE.inWholeNanoseconds`, then return `Duration.INFINITE` directly if equals. --- .../kotlin/datetime/KotlinDateColumnType.kt | 1 + .../sql/kotlin/datetime/MiscTableTest.kt | 63 +++++++++++++++++++ 2 files changed, 64 insertions(+) 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 a238f42f1b..5b80e1dd08 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 @@ -384,6 +384,7 @@ class KotlinDurationColumnType : ColumnType() { } override fun valueFromDB(value: Any): Duration = when (value) { + Duration.INFINITE.inWholeNanoseconds -> Duration.INFINITE is Long -> value.nanoseconds is Number -> value.toLong().nanoseconds is String -> Duration.parse(value) diff --git a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt index 481f2acdb4..234a5f5946 100644 --- a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt +++ b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt @@ -1224,6 +1224,69 @@ class MiscTableTest : DatabaseTestsBase() { } } + @Test + fun testInfiniteDuration() { + val tbl = Misc + val date = today + val dateTime = now() + val time = dateTime.time + val timestamp = Clock.System.now() + val duration = Duration.INFINITE + val eOne = MiscTable.E.ONE + val dec = BigDecimal("123.45") + withTables(tbl) { + tbl.insert { + it[by] = 7 + it[sm] = -2 + it[n] = 14 + it[c] = "1234" + it[s] = "123456789" + it[d] = date + it[t] = time + it[dt] = dateTime + it[ts] = timestamp + it[dr] = duration + it[e] = eOne + it[es] = eOne + it[dc] = dec + } + + val row = tbl.selectAll().where { tbl.dr eq Duration.INFINITE }.single() + + tbl.checkRowFull( + row, + by = 7, + byn = null, + sm = -2, + smn = null, + n = 14, + nn = null, + d = date, + dn = null, + t = time, + tn = null, + dt = dateTime, + dtn = null, + ts = timestamp, + tsn = null, + dr = duration, + drn = null, + e = eOne, + en = null, + es = eOne, + esn = null, + c = "1234", + cn = null, + s = "123456789", + sn = null, + dc = dec, + dcn = null, + fcn = null, + dblcn = null + ) + } + } + private object ZeroDateTimeTable : Table("zerodatetimetable") { val id = integer("id") From 5bfa0c9e10de28d20ab240071289580ebfbd26b6 Mon Sep 17 00:00:00 2001 From: huangwenhai Date: Tue, 30 Jan 2024 09:58:32 +0800 Subject: [PATCH 2/2] fix: EXPOSED-270 Respect `Duration.INFINITE` for duration column type Simplify test case and move to `KotlinTimeTests.kt`. --- .../sql/kotlin/datetime/KotlinTimeTests.kt | 15 +++++ .../sql/kotlin/datetime/MiscTableTest.kt | 63 ------------------- 2 files changed, 15 insertions(+), 63 deletions(-) diff --git a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinTimeTests.kt b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinTimeTests.kt index 7c10f71155..cfa5fb9bc7 100644 --- a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinTimeTests.kt +++ b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/KotlinTimeTests.kt @@ -26,6 +26,7 @@ import java.time.OffsetDateTime import java.time.ZoneId import java.time.ZoneOffset import kotlin.test.assertEquals +import kotlin.time.Duration open class KotlinTimeBaseTest : DatabaseTestsBase() { @@ -464,6 +465,20 @@ open class KotlinTimeBaseTest : DatabaseTestsBase() { currentDbDateTime() } } + + @Test + fun testInfiniteDuration() { + val tester = object : Table("tester") { + val duration = duration("duration") + } + withTables(tester) { + tester.insert { + it[duration] = Duration.INFINITE + } + val row = tester.selectAll().where { tester.duration eq Duration.INFINITE }.single() + assertEquals(Duration.INFINITE, row[tester.duration]) + } + } } fun assertEqualDateTime(d1: T?, d2: T?) { diff --git a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt index 234a5f5946..481f2acdb4 100644 --- a/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt +++ b/exposed-kotlin-datetime/src/test/kotlin/org/jetbrains/exposed/sql/kotlin/datetime/MiscTableTest.kt @@ -1224,69 +1224,6 @@ class MiscTableTest : DatabaseTestsBase() { } } - @Test - fun testInfiniteDuration() { - val tbl = Misc - val date = today - val dateTime = now() - val time = dateTime.time - val timestamp = Clock.System.now() - val duration = Duration.INFINITE - val eOne = MiscTable.E.ONE - val dec = BigDecimal("123.45") - withTables(tbl) { - tbl.insert { - it[by] = 7 - it[sm] = -2 - it[n] = 14 - it[c] = "1234" - it[s] = "123456789" - it[d] = date - it[t] = time - it[dt] = dateTime - it[ts] = timestamp - it[dr] = duration - it[e] = eOne - it[es] = eOne - it[dc] = dec - } - - val row = tbl.selectAll().where { tbl.dr eq Duration.INFINITE }.single() - - tbl.checkRowFull( - row, - by = 7, - byn = null, - sm = -2, - smn = null, - n = 14, - nn = null, - d = date, - dn = null, - t = time, - tn = null, - dt = dateTime, - dtn = null, - ts = timestamp, - tsn = null, - dr = duration, - drn = null, - e = eOne, - en = null, - es = eOne, - esn = null, - c = "1234", - cn = null, - s = "123456789", - sn = null, - dc = dec, - dcn = null, - fcn = null, - dblcn = null - ) - } - } - private object ZeroDateTimeTable : Table("zerodatetimetable") { val id = integer("id")