diff --git a/exposed-java-time/src/main/kotlin/org/jetbrains/exposed/sql/javatime/JavaDateColumnType.kt b/exposed-java-time/src/main/kotlin/org/jetbrains/exposed/sql/javatime/JavaDateColumnType.kt index 135e7fda22..3d1ed568fb 100644 --- a/exposed-java-time/src/main/kotlin/org/jetbrains/exposed/sql/javatime/JavaDateColumnType.kt +++ b/exposed-java-time/src/main/kotlin/org/jetbrains/exposed/sql/javatime/JavaDateColumnType.kt @@ -180,7 +180,9 @@ class JavaLocalDateTimeColumnType : ColumnType(), IDateColumnType val dialect = currentDialect return when { dialect is SQLiteDialect -> "'${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(instant)}'" - dialect is OracleDialect || dialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle -> "'${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(instant)}'" + dialect is OracleDialect || dialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle -> + "TO_TIMESTAMP('${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(instant)}', 'YYYY-MM-DD HH24:MI:SS.FF3')" + dialect is MysqlDialect -> { val formatter = if (dialect.isFractionDateTimeSupported()) MYSQL_FRACTION_DATE_TIME_STRING_FORMATTER else MYSQL_DATE_TIME_STRING_FORMATTER "'${formatter.format(instant)}'" @@ -248,13 +250,11 @@ class JavaLocalTimeColumnType : ColumnType(), IDateColumnType { override fun sqlType(): String = currentDialect.dataTypeProvider.timeType() override fun nonNullValueToString(value: LocalTime): String { - val dialect = currentDialect - val formatter = if (dialect is OracleDialect || dialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle) { - ORACLE_TIME_STRING_FORMATTER - } else { - DEFAULT_TIME_STRING_FORMATTER + if (currentDialect is OracleDialect || currentDialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle) { + return "TO_TIMESTAMP('${ORACLE_TIME_STRING_FORMATTER.format(value)}', 'YYYY-MM-DD HH24:MI:SS')" } - return "'${formatter.format(value)}'" + + return "'${DEFAULT_TIME_STRING_FORMATTER.format(value)}'" } override fun valueFromDB(value: Any): LocalTime = when (value) { @@ -302,8 +302,10 @@ class JavaInstantColumnType : ColumnType(), IDateColumnType { override fun nonNullValueToString(value: Instant): String { val dialect = currentDialect return when { + dialect is SQLiteDialect -> "'${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(value)}'" dialect is OracleDialect || dialect.h2Mode == H2Dialect.H2CompatibilityMode.Oracle -> - "'${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(value)}'" + "TO_TIMESTAMP('${SQLITE_AND_ORACLE_DATE_TIME_STRING_FORMATTER.format(value)}', 'YYYY-MM-DD HH24:MI:SS.FF3')" + dialect is MysqlDialect -> { val formatter = if (dialect.isFractionDateTimeSupported()) MYSQL_FRACTION_DATE_TIME_STRING_FORMATTER else MYSQL_DATE_TIME_STRING_FORMATTER "'${formatter.format(value)}'" diff --git a/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateLiteralTest.kt b/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateLiteralTest.kt deleted file mode 100644 index eca8ec1330..0000000000 --- a/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateLiteralTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -package org.jetbrains.exposed - -import junit.framework.TestCase.assertNull -import org.jetbrains.exposed.DateLiteralTest.TableWithDate.date -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.javatime.date -import org.jetbrains.exposed.sql.javatime.dateLiteral -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.tests.DatabaseTestsBase -import org.jetbrains.exposed.sql.tests.shared.assertEquals -import org.junit.Test -import java.time.LocalDate - -class DateLiteralTest : DatabaseTestsBase() { - object TableWithDate : IntIdTable() { - val date = date("date") - } - - @Test - fun testDateLiteralInQuery() { - withTables(TableWithDate) { - val future = LocalDate.of(3000, 1, 1) - val past = LocalDate.of(1500, 1, 1) - - TableWithDate.insert { - it[date] = future - } - - assertEquals(future, TableWithDate.selectAll().first()[date]) - - assertEquals(future, TableWithDate.selectAll().where { date greater past }.first()[date]) - - assertEquals(future, TableWithDate.selectAll().where { date greater dateLiteral(past) }.first()[date]) - - assertNull(TableWithDate.selectAll().where { date less dateLiteral(past) }.firstOrNull()) - } - } -} diff --git a/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateTimeLiteralTest.kt b/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateTimeLiteralTest.kt new file mode 100644 index 0000000000..ff1ce63bc8 --- /dev/null +++ b/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DateTimeLiteralTest.kt @@ -0,0 +1,208 @@ +package org.jetbrains.exposed + +import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.insert +import org.jetbrains.exposed.sql.javatime.* +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.tests.DatabaseTestsBase +import org.jetbrains.exposed.sql.tests.shared.assertEquals +import org.jetbrains.exposed.sql.update +import org.junit.Ignore +import org.junit.Test +import java.time.Instant +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import kotlin.test.assertNotNull + +class DateTimeLiteralTest : DatabaseTestsBase() { + private val defaultDate = LocalDate.of(2000, 1, 1) + private val futureDate = LocalDate.of(3000, 1, 1) + + object TableWithDate : IntIdTable() { + val date = date("date") + } + + private val defaultDatetime = LocalDateTime.of(2000, 1, 1, 8, 0, 0, 100000000) + private val futureDatetime = LocalDateTime.of(3000, 1, 1, 8, 0, 0, 100000000) + + object TableWithDatetime : IntIdTable() { + val datetime = datetime("datetime") + } + + private val defaultTimestamp = Instant.parse("2000-01-01T01:00:00.00Z") + private val futureTimestamp = Instant.parse("3000-01-01T01:00:00.00Z") + + object TableWithTimestamp : IntIdTable() { + val timestamp = timestamp("timestamp") + } + + private val defaultLocalTime = LocalTime.of(1, 0, 0) + private val futureLocalTime = LocalTime.of(18, 0, 0) + + object TableWithTime : IntIdTable() { + val time = time("time") + } + + @Test + fun testInsertWithDateLiteral() { + withTables(TableWithDate) { + TableWithDate.insert { + it[date] = dateLiteral(defaultDate) + } + assertEquals(defaultDate, TableWithDate.selectAll().first()[TableWithDate.date]) + } + } + + @Test + fun testUpdateWithDateLiteral() { + withTables(TableWithDate) { + TableWithDate.insert { + it[date] = defaultDate + } + + TableWithDate.update { it[date] = dateLiteral(futureDate) } + assertEquals(futureDate, TableWithDate.selectAll().first()[TableWithDate.date]) + } + } + + @Test + fun testSelectByDateLiteralEquality() { + withTables(TableWithDate) { + TableWithDate.insert { + it[date] = defaultDate + } + + val query = TableWithDate.select(TableWithDate.date).where { TableWithDate.date eq dateLiteral(defaultDate) } + assertEquals(defaultDate, query.single()[TableWithDate.date]) + } + } + + @Test + fun testSelectByDateLiteralComparison() { + withTables(TableWithDate) { + TableWithDate.insert { + it[date] = defaultDate + } + val query = TableWithDate.selectAll().where { TableWithDate.date less dateLiteral(futureDate) } + assertNotNull(query.firstOrNull()) + } + } + + @Test + fun testInsertDatetimeLiteral() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = dateTimeLiteral(defaultDatetime) + } + assertEquals(defaultDatetime, TableWithDatetime.selectAll().first()[TableWithDatetime.datetime]) + } + } + + @Test + fun testUpdateWithDatetimeLiteral() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + + TableWithDatetime.update { it[datetime] = dateTimeLiteral(futureDatetime) } + assertEquals(futureDatetime, TableWithDatetime.selectAll().first()[TableWithDatetime.datetime]) + } + } + + @Test + fun testSelectByDatetimeLiteralEquality() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + + val query = TableWithDatetime.select(TableWithDatetime.datetime).where { TableWithDatetime.datetime eq dateTimeLiteral(defaultDatetime) } + assertEquals(defaultDatetime, query.single()[TableWithDatetime.datetime]) + } + } + + @Test + fun testSelectByDatetimeLiteralComparison() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + val query = TableWithDatetime.selectAll().where { TableWithDatetime.datetime less dateTimeLiteral(futureDatetime) } + assertNotNull(query.firstOrNull()) + } + } + + @Test + fun testInsertWithTimestampLiteral() { + withTables(TableWithTimestamp) { + TableWithTimestamp.insert { + it[timestamp] = timestampLiteral(defaultTimestamp) + } + assertEquals(defaultTimestamp, TableWithTimestamp.selectAll().first()[TableWithTimestamp.timestamp]) + } + } + + @Test + fun testUpdateWithTimestampLiteral() { + withTables(TableWithTimestamp) { + TableWithTimestamp.insert { + it[timestamp] = defaultTimestamp + } + + TableWithTimestamp.update { it[timestamp] = timestampLiteral(futureTimestamp) } + assertEquals(futureTimestamp, TableWithTimestamp.selectAll().first()[TableWithTimestamp.timestamp]) + } + } + + @Test + fun testSelectByTimestampLiteralEquality() { + withTables(TableWithTimestamp) { + TableWithTimestamp.insert { + it[timestamp] = defaultTimestamp + } + + val query = TableWithTimestamp.select(TableWithTimestamp.timestamp).where { TableWithTimestamp.timestamp eq timestampLiteral(defaultTimestamp) } + assertEquals(defaultTimestamp, query.single()[TableWithTimestamp.timestamp]) + } + } + + @Test + fun testInsertTimeLiteral() { + withTables(TableWithTime) { + TableWithTime.insert { + it[time] = timeLiteral(defaultLocalTime) + } + assertEquals(defaultLocalTime, TableWithTime.selectAll().first()[TableWithTime.time]) + } + } + + @Test + fun testUpdateWithTimeLiteral() { + withTables(TableWithTime) { + TableWithTime.insert { + it[time] = defaultLocalTime + } + + TableWithTime.update { it[time] = timeLiteral(futureLocalTime) } + assertEquals(futureLocalTime, TableWithTime.selectAll().first()[TableWithTime.time]) + } + } + + @Test + @Ignore( + "Test fails with 'Collection is empty.' message. It can not find anything in db after insert. " + + "But SQL requests looks correct, and work well manually applied." + ) + fun testSelectByTimeLiteralEquality() { + withTables(TableWithTime) { + TableWithTime.insert { + it[time] = defaultLocalTime + } + + val query = TableWithTime.select(TableWithTime.id, TableWithTime.time).where { TableWithTime.time eq timeLiteral(defaultLocalTime) } + assertEquals(defaultLocalTime, query.single()[TableWithTime.time]) + } + } +} diff --git a/exposed-jodatime/src/main/kotlin/org/jetbrains/exposed/sql/jodatime/DateColumnType.kt b/exposed-jodatime/src/main/kotlin/org/jetbrains/exposed/sql/jodatime/DateColumnType.kt index b85c1fb84d..564bdcbad1 100644 --- a/exposed-jodatime/src/main/kotlin/org/jetbrains/exposed/sql/jodatime/DateColumnType.kt +++ b/exposed-jodatime/src/main/kotlin/org/jetbrains/exposed/sql/jodatime/DateColumnType.kt @@ -66,12 +66,18 @@ class DateColumnType(val time: Boolean) : ColumnType(), IDateColumnTyp override fun nonNullValueToString(value: DateTime): String { return if (time) { when { + currentDialect is OracleDialect -> + "TO_TIMESTAMP('${DEFAULT_DATE_TIME_STRING_FORMATTER.print(value.toDateTime(DateTimeZone.getDefault()))}', 'YYYY-MM-DD HH24:MI:SS.FF3')" (currentDialect as? MysqlDialect)?.isFractionDateTimeSupported() == false -> "'${MYSQL_DATE_TIME_STRING_FORMATTER.print(value.toDateTime(DateTimeZone.getDefault()))}'" else -> "'${DEFAULT_DATE_TIME_STRING_FORMATTER.print(value.toDateTime(DateTimeZone.getDefault()))}'" } } else { - "'${DEFAULT_DATE_STRING_FORMATTER.print(value)}'" + val formatted = DEFAULT_DATE_STRING_FORMATTER.print(value) + if (currentDialect is OracleDialect) { + return "TO_DATE('$formatted', 'YYYY-MM-DD')" + } + return "'$formatted'" } } diff --git a/exposed-jodatime/src/test/kotlin/org/jetbrains/exposed/JodaDateTimeLiteralTest.kt b/exposed-jodatime/src/test/kotlin/org/jetbrains/exposed/JodaDateTimeLiteralTest.kt new file mode 100644 index 0000000000..6babc9bf7f --- /dev/null +++ b/exposed-jodatime/src/test/kotlin/org/jetbrains/exposed/JodaDateTimeLiteralTest.kt @@ -0,0 +1,70 @@ +package org.jetbrains.exposed + +import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.insert +import org.jetbrains.exposed.sql.jodatime.dateTimeLiteral +import org.jetbrains.exposed.sql.jodatime.datetime +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.tests.DatabaseTestsBase +import org.jetbrains.exposed.sql.tests.shared.assertEquals +import org.jetbrains.exposed.sql.update +import org.joda.time.DateTime +import org.joda.time.format.DateTimeFormat +import org.junit.Test +import kotlin.test.assertNotNull + +class JodaDateTimeLiteralTest : DatabaseTestsBase() { + private val pattern = "dd-mm-yyyy hh.mm.ss" + + private val defaultDatetime: DateTime = DateTime.parse("01-01-2000 01.00.00", DateTimeFormat.forPattern(pattern)) + private val futureDatetime: DateTime = DateTime.parse("01-01-3000 01.00.00", DateTimeFormat.forPattern(pattern)) + + object TableWithDatetime : IntIdTable() { + val datetime = datetime("datetime") + } + + @Test + fun testInsertWithDateLiteral() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = dateTimeLiteral(defaultDatetime) + } + assertEquals(defaultDatetime, TableWithDatetime.selectAll().first()[TableWithDatetime.datetime]) + } + } + + @Test + fun testUpdateWithDatetimeLiteral() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + + TableWithDatetime.update { it[datetime] = dateTimeLiteral(futureDatetime) } + assertEquals(futureDatetime, TableWithDatetime.selectAll().first()[TableWithDatetime.datetime]) + } + } + + @Test + fun testSelectByDatetimeLiteralEquality() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + + val query = TableWithDatetime.select(TableWithDatetime.datetime).where { TableWithDatetime.datetime eq dateTimeLiteral(defaultDatetime) } + assertEquals(defaultDatetime, query.single()[TableWithDatetime.datetime]) + } + } + + @Test + fun testSelectByDatetimeLiteralComparison() { + withTables(TableWithDatetime) { + TableWithDatetime.insert { + it[datetime] = defaultDatetime + } + val query = TableWithDatetime.selectAll().where { TableWithDatetime.datetime less dateTimeLiteral(futureDatetime) } + assertNotNull(query.firstOrNull()) + } + } +}