From 29867d95182bdfd4c96ec58dd0c5f25b625bb1bf Mon Sep 17 00:00:00 2001 From: fan Date: Wed, 5 Jun 2024 10:31:07 +0800 Subject: [PATCH] Add OffsetDateTime support for PostgreSQL. --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++ .../support/postgresql/OffsetDateTimeTest.kt | 42 +++++++++++++++++++ .../test/resources/drop-postgresql-data.sql | 1 + .../test/resources/init-postgresql-data.sql | 7 +++- 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/OffsetDateTimeTest.kt diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index 2ddb7081..83bb640d 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -22,7 +22,11 @@ import org.ktorm.schema.SqlType import java.lang.reflect.InvocationTargetException import java.sql.PreparedStatement import java.sql.ResultSet +import java.sql.Timestamp import java.sql.Types +import java.time.OffsetDateTime +import java.time.ZoneId +import java.time.ZoneOffset /** * Define a column typed [ShortArraySqlType]. @@ -366,3 +370,27 @@ public object EarthSqlType : SqlType(Types.OTHER, "earth") { } } } + +/** + * Define a column typed [OffsetDateTime]. + */ +public fun BaseTable<*>.datetimeOffset(name: String): Column { + return registerColumn(name, OffsetDateTimeSqlType) +} + +public object OffsetDateTimeSqlType : SqlType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamptz") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: OffsetDateTime) { + ps.setTimestamp(index, Timestamp.from(parameter.toInstant())) + } + + override fun doGetResult(rs: ResultSet, index: Int): OffsetDateTime? { + val value = rs.getTimestamp(index) + if (rs.wasNull()) { + return null + } + val systemZoneId = ZoneId.systemDefault() + val systemZoneOffset = systemZoneId.rules.getOffset(value.toInstant()) + return value.toInstant().atOffset(systemZoneOffset) + } +} diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/OffsetDateTimeTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/OffsetDateTimeTest.kt new file mode 100644 index 00000000..476375ed --- /dev/null +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/OffsetDateTimeTest.kt @@ -0,0 +1,42 @@ +package org.ktorm.support.postgresql + +import org.junit.Test +import org.ktorm.dsl.* +import org.ktorm.schema.Table +import org.ktorm.schema.int +import java.time.OffsetDateTime +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class OffsetDateTimeTest : BasePostgreSqlTest() { + + object OffsetDatetimes : Table("t_offset_datetime") { + val id = int("id").primaryKey() + val createdAt = datetimeOffset("created_at") + } + + @Test + fun test() { + val value = OffsetDateTime.now() + database.insert(OffsetDatetimes) { + set(OffsetDatetimes.createdAt, value) + } + val results = database + .from(OffsetDatetimes) + .select(OffsetDatetimes.createdAt) + .where(OffsetDatetimes.id eq 1) + .map { row -> + row[OffsetDatetimes.createdAt] + } + val offsetDateTime = results[0] + assertNotNull(offsetDateTime) + assertEquals(value.year, offsetDateTime.year) + assertEquals(value.month, offsetDateTime.month) + assertEquals(value.dayOfMonth, offsetDateTime.dayOfMonth) + assertEquals(value.hour, offsetDateTime.hour) + assertEquals(value.minute, offsetDateTime.minute) + assertEquals(value.second, offsetDateTime.second) + assertEquals(value.offset, offsetDateTime.offset) + } + +} diff --git a/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql b/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql index 0bfc34ec..16d993a8 100644 --- a/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql +++ b/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql @@ -8,3 +8,4 @@ drop type if exists mood; drop table if exists t_json; drop table t_earthdistance; drop table if exists t_user; +drop table if exists t_offset_datetime; diff --git a/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql b/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql index d627581a..c72bc5b1 100644 --- a/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql +++ b/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql @@ -74,4 +74,9 @@ insert into t_metadata(attrs) values ('a=>1, b=>2, c=>NULL'::hstore); insert into t_enum(current_mood) -values ('HAPPY') +values ('HAPPY'); + +create table t_offset_datetime( + id serial primary key, + created_at timestamptz not null +);