From db8410d099ff14845b944ea5bc91c5072ece2129 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sun, 21 Mar 2021 14:53:47 +0900 Subject: [PATCH] Fix timestamptz response (#110) --- .../com/koxudaxi/localDataApi/LocalDataApi.kt | 22 +++++++------- .../koxudaxi/localDataApi/ApplicationTest.kt | 29 +++++++++++++++++++ .../koxudaxi/localDataApi/LocalDataApiTest.kt | 14 ++++++++- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/kotlin/local-data-api/src/com/koxudaxi/localDataApi/LocalDataApi.kt b/kotlin/local-data-api/src/com/koxudaxi/localDataApi/LocalDataApi.kt index 2b55dc6..3bcffea 100644 --- a/kotlin/local-data-api/src/com/koxudaxi/localDataApi/LocalDataApi.kt +++ b/kotlin/local-data-api/src/com/koxudaxi/localDataApi/LocalDataApi.kt @@ -9,21 +9,23 @@ val DOUBLE = listOf(Types.FLOAT, Types.REAL, Types.DOUBLE) //val STRING = listOf(Types.DECIMAL, Types.CLOB) val BOOLEAN = listOf(Types.BOOLEAN, Types.BIT) val BLOB = listOf(Types.BLOB, Types.BINARY, Types.LONGVARBINARY, Types.VARBINARY) -val DATETIME = listOf(Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE) +val DATETIME = listOf(Types.TIMESTAMP) +val DATETIME_TZ = listOf(Types.TIMESTAMP_WITH_TIMEZONE) fun createField(resultSet: ResultSet, index: Int): Field { if (resultSet.getObject(index) == null) { return Field(isNull = true) } - return when (resultSet.metaData.getColumnType(index)) { - in LONG -> Field(longValue = resultSet.getLong(index)) - in DOUBLE -> Field(doubleValue = resultSet.getDouble(index)) - in BOOLEAN -> Field(booleanValue = resultSet.getBoolean(index)) - in BLOB -> Field(blobValue = Base64.getEncoder().encodeToString(resultSet.getBytes(index))) - in DATETIME -> Field(stringValue = Regex("^[^.]+\\.\\d{3}|^[^.]+").find(resultSet.getString(index))!!.value) - else -> { - Field(stringValue = resultSet.getString(index)) - } + val value = resultSet.metaData.getColumnType(index) + return when { + value in LONG -> Field(longValue = resultSet.getLong(index)) + value in DOUBLE -> Field(doubleValue = resultSet.getDouble(index)) + value in BOOLEAN -> Field(booleanValue = resultSet.getBoolean(index)) + value in BLOB -> Field(blobValue = Base64.getEncoder().encodeToString(resultSet.getBytes(index))) + value in DATETIME_TZ || (value in DATETIME && resultSet.metaData.getColumnTypeName(index) == "timestamptz") + -> Field(stringValue = Regex("^.+ [^.]+\\.\\d{6}|^.+ [^.+\\-]+").find(resultSet.getString(index))!!.value) + value in DATETIME -> Field(stringValue = Regex("^[^.]+\\.\\d{3}|^[^.]+").find(resultSet.getString(index))!!.value) + else -> Field(stringValue = resultSet.getString(index)) } } diff --git a/kotlin/local-data-api/test/com/koxudaxi/localDataApi/ApplicationTest.kt b/kotlin/local-data-api/test/com/koxudaxi/localDataApi/ApplicationTest.kt index 6994792..969b8a0 100644 --- a/kotlin/local-data-api/test/com/koxudaxi/localDataApi/ApplicationTest.kt +++ b/kotlin/local-data-api/test/com/koxudaxi/localDataApi/ApplicationTest.kt @@ -223,6 +223,35 @@ class ApplicationTest { } } + @Test + fun testExecuteSelectTIMESTAMP_WITH_TZ() { + ResourceManager.INSTANCE.setResource("h2:./test;MODE=PostgreSQL", dummyResourceArn, null, null, emptyMap()) + + withTestApplication({ module(testing = true) }) { + handleRequest(HttpMethod.Post, "/Execute") { + addHeader(HttpHeaders.ContentType, "*/*") + setBody(Json.encodeToString(ExecuteStatementRequest(dummyResourceArn, dummySecretArn, + "SELECT CAST('2021-03-10 22:41:04.968123' AS TIMESTAMP(6) WITH TIME ZONE) as value"))) + }.apply { + assertEquals( + "{\"numberOfRecordsUpdated\":0,\"generatedFields\":null,\"records\":[[{\"blobValue\":null,\"booleanValue\":null,\"doubleValue\":null,\"isNull\":null,\"longValue\":null,\"stringValue\":\"2021-03-10 22:41:04.968123\"}]],\"columnMetadata\":null}", + response.content) + assertEquals(HttpStatusCode.OK, response.status()) + } + + handleRequest(HttpMethod.Post, "/Execute") { + addHeader(HttpHeaders.ContentType, "*/*") + setBody(Json.encodeToString(ExecuteStatementRequest(dummyResourceArn, dummySecretArn, + "SELECT CAST('2021-03-10 22:41:04' AS TIMESTAMP(6) WITH TIME ZONE) AS value"))) + }.apply { + assertEquals( + "{\"numberOfRecordsUpdated\":0,\"generatedFields\":null,\"records\":[[{\"blobValue\":null,\"booleanValue\":null,\"doubleValue\":null,\"isNull\":null,\"longValue\":null,\"stringValue\":\"2021-03-10 22:41:04\"}]],\"columnMetadata\":null}", + response.content) + assertEquals(HttpStatusCode.OK, response.status()) + } + } + } + @Test fun testExecuteSelectNull() { withTestApplication({ module(testing = true) }) { diff --git a/kotlin/local-data-api/test/com/koxudaxi/localDataApi/LocalDataApiTest.kt b/kotlin/local-data-api/test/com/koxudaxi/localDataApi/LocalDataApiTest.kt index f7bf02b..0797b6e 100644 --- a/kotlin/local-data-api/test/com/koxudaxi/localDataApi/LocalDataApiTest.kt +++ b/kotlin/local-data-api/test/com/koxudaxi/localDataApi/LocalDataApiTest.kt @@ -5,6 +5,7 @@ import io.mockk.* import io.mockk.mockk import org.junit.After import java.sql.Connection +import java.sql.ResultSet import java.sql.Types class LocalDataApiTest { @@ -19,7 +20,18 @@ class LocalDataApiTest { assertEquals(listOf(Types.FLOAT, Types.REAL, Types.DOUBLE), DOUBLE) assertEquals(listOf(Types.BOOLEAN, Types.BIT), BOOLEAN) assertEquals(listOf(Types.BLOB, Types.BINARY, Types.LONGVARBINARY, Types.VARBINARY), BLOB) - assertEquals(listOf(Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE), DATETIME) + assertEquals(listOf(Types.TIMESTAMP), DATETIME) + assertEquals(listOf(Types.TIMESTAMP_WITH_TIMEZONE), DATETIME_TZ) + } + + @Test + fun testCreateField() { + // For PostgreSQL + val mock = mockk(relaxed = true) + every {mock.metaData.getColumnType(1) } returns Types.TIMESTAMP + every {mock.metaData.getColumnTypeName(1) } returns "timestamptz" + every {mock.getString(1) } returns "2021-03-10 22:41:04.123456+02" + assertEquals(createField(mock, 1).stringValue, "2021-03-10 22:41:04.123456") } @Test