Java time tests and code fixes

This commit is contained in:
Tapac
2019-08-25 01:06:50 +03:00
parent 0b04d068a0
commit c3d931b682
8 changed files with 679 additions and 59 deletions

View File

@@ -12,6 +12,8 @@ repositories {
dependencies {
api(project(":exposed-core"))
testImplementation(project(":exposed-tests"))
testImplementation("junit", "junit", "4.12")
testImplementation(kotlin("test-junit"))
}
tasks.withType<KotlinJvmCompile> {

View File

@@ -9,20 +9,19 @@ import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.*
private val DEFAULT_DATE_STRING_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd").withLocale(Locale.ROOT)
private val DEFAULT_DATE_TIME_STRING_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSSSSS").withLocale(Locale.ROOT)
private val SQLITE_DATE_TIME_STRING_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss")
private val SQLITE_DATE_STRING_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE
private val DEFAULT_DATE_STRING_FORMATTER by lazy { DateTimeFormatter.ofPattern("YYYY-MM-d").withLocale(Locale.ROOT).withZone(ZoneId.systemDefault()) }
private val DEFAULT_DATE_TIME_STRING_FORMATTER by lazy { DateTimeFormatter.ofPattern("yyyy-MM-d HH:mm:ss.SSSSSS").withLocale(Locale.ROOT).withZone(ZoneId.systemDefault()) }
private val SQLITE_DATE_TIME_STRING_FORMATTER by lazy { DateTimeFormatter.ofPattern("yyyy-MM-d HH:mm:ss").withZone(ZoneId.systemDefault()) }
private val LocalDate.millis get() = atStartOfDay(ZoneId.systemDefault()).toEpochSecond()
private val LocalDate.millis get() = atStartOfDay(ZoneId.systemDefault()).toEpochSecond() * 1000
class LocalDateColumnType : ColumnType(), IDateColumnType {
class JavaLocalDateColumnType : ColumnType(), IDateColumnType {
override fun sqlType(): String = "DATE"
override fun nonNullValueToString(value: Any): String {
val instant = when (value) {
is String -> return value
is LocalDate -> Instant.from(value)
is LocalDate -> Instant.from(value.atStartOfDay(ZoneId.systemDefault()))
is java.sql.Date -> value.toInstant()
is java.sql.Timestamp -> value.toInstant()
else -> error("Unexpected value: $value of ${value::class.qualifiedName}")
@@ -35,13 +34,13 @@ class LocalDateColumnType : ColumnType(), IDateColumnType {
is LocalDate -> value
is java.sql.Date -> value.toLocalDate()
is java.sql.Timestamp -> value.toLocalDateTime().toLocalDate()
is Int -> LocalDate.from(Instant.ofEpochMilli(value.toLong()))
is Long -> LocalDate.from(Instant.ofEpochMilli(value.toLong()))
is Int -> Instant.ofEpochMilli(value.toLong()).atZone(ZoneId.systemDefault()).toLocalDate() //LocalDateTime.ofInstant(Instant.ofEpochMilli(value.toLong()), ZoneId.systemDefault()).toLocalDate()
is Long -> Instant.ofEpochMilli(value).atZone(ZoneId.systemDefault()).toLocalDate() //LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneId.systemDefault()).toLocalDate()
is String -> when (currentDialect) {
is SQLiteDialect -> SQLITE_DATE_STRING_FORMATTER.parse(value)
is SQLiteDialect -> LocalDate.parse(value)
else -> value
}
else -> DEFAULT_DATE_STRING_FORMATTER.parse(value.toString())
else -> LocalDate.parse(value.toString())
}
override fun notNullValueToDB(value: Any) = when {
@@ -50,17 +49,17 @@ class LocalDateColumnType : ColumnType(), IDateColumnType {
}
companion object {
internal val INSTANSE = LocalDateColumnType()
internal val INSTANCE = JavaLocalDateColumnType()
}
}
class LocalDateTimeColumnType : ColumnType(), IDateColumnType {
class JavaLocalDateTimeColumnType : ColumnType(), IDateColumnType {
override fun sqlType(): String = currentDialect.dataTypeProvider.dateTimeType()
override fun nonNullValueToString(value: Any): String {
val instant = when (value) {
is String -> return value
is LocalDateTime -> Instant.from(value)
is LocalDateTime -> Instant.from(value.atZone(ZoneId.systemDefault()))
is java.sql.Date -> Instant.ofEpochMilli(value.time)
is java.sql.Timestamp -> Instant.ofEpochMilli(value.time)
else -> error("Unexpected value: $value of ${value::class.qualifiedName}")
@@ -76,10 +75,10 @@ class LocalDateTimeColumnType : ColumnType(), IDateColumnType {
is Int -> LocalDateTime.ofInstant(Instant.ofEpochMilli(value.toLong()), ZoneId.systemDefault())
is Long -> LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneId.systemDefault())
is String -> when (currentDialect) {
is SQLiteDialect -> SQLITE_DATE_TIME_STRING_FORMATTER.parse(value)
is SQLiteDialect -> LocalDateTime.parse(value, SQLITE_DATE_TIME_STRING_FORMATTER)
else -> value
}
else -> DEFAULT_DATE_TIME_STRING_FORMATTER.parse(value.toString())
else -> LocalDateTime.parse(value.toString(), DEFAULT_DATE_TIME_STRING_FORMATTER)
}
override fun notNullValueToDB(value: Any): Any {
@@ -90,7 +89,7 @@ class LocalDateTimeColumnType : ColumnType(), IDateColumnType {
}
companion object {
internal val INSTANSE = LocalDateTimeColumnType()
internal val INSTANCE = JavaLocalDateTimeColumnType()
}
}
@@ -100,11 +99,11 @@ class LocalDateTimeColumnType : ColumnType(), IDateColumnType {
*
* @param name The column name
*/
fun Table.date(name: String): Column<LocalDate> = registerColumn(name, LocalDateColumnType())
fun Table.date(name: String): Column<LocalDate> = registerColumn(name, JavaLocalDateColumnType())
/**
* A datetime column to store both a date and a time.
*
* @param name The column name
*/
fun Table.datetime(name: String): Column<LocalDateTime> = registerColumn(name, LocalDateTimeColumnType())
fun Table.datetime(name: String): Column<LocalDateTime> = registerColumn(name, JavaLocalDateTimeColumnType())

View File

@@ -6,11 +6,11 @@ import java.time.LocalDate
import java.time.LocalDateTime
import java.time.temporal.Temporal
class Date<T:Temporal?>(val expr: Expression<T>): Function<LocalDate>(LocalDateColumnType.INSTANSE) {
class Date<T:Temporal?>(val expr: Expression<T>): Function<LocalDate>(JavaLocalDateColumnType.INSTANCE) {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append("DATE(", expr,")") }
}
class CurrentDateTime : Function<LocalDateTime>(LocalDateTimeColumnType.INSTANSE) {
class CurrentDateTime : Function<LocalDateTime>(JavaLocalDateTimeColumnType.INSTANCE) {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
+when {
(currentDialect as? MysqlDialect)?.isFractionDateTimeSupported() == true -> "CURRENT_TIMESTAMP(6)"
@@ -28,11 +28,11 @@ fun <T: Temporal?> Expression<T>.date() = Date(this)
fun <T: Temporal?> Expression<T>.month() = Month(this)
fun dateParam(value: LocalDate): Expression<LocalDate> = QueryParameter(value, LocalDateColumnType.INSTANSE)
fun dateTimeParam(value: LocalDateTime): Expression<LocalDateTime> = QueryParameter(value, LocalDateTimeColumnType.INSTANSE)
fun dateParam(value: LocalDate): Expression<LocalDate> = QueryParameter(value, JavaLocalDateColumnType.INSTANCE)
fun dateTimeParam(value: LocalDateTime): Expression<LocalDateTime> = QueryParameter(value, JavaLocalDateTimeColumnType.INSTANCE)
fun dateLiteral(value: LocalDate): LiteralOp<LocalDate> = LiteralOp(LocalDateColumnType.INSTANSE, value)
fun dateTimeLiteral(value: LocalDateTime): LiteralOp<LocalDateTime> = LiteralOp(LocalDateTimeColumnType.INSTANSE, value)
fun dateLiteral(value: LocalDate): LiteralOp<LocalDate> = LiteralOp(JavaLocalDateColumnType.INSTANCE, value)
fun dateTimeLiteral(value: LocalDateTime): LiteralOp<LocalDateTime> = LiteralOp(JavaLocalDateTimeColumnType.INSTANCE, value)
fun CustomDateFunction(functionName: String, vararg params: Expression<*>) = CustomFunction<LocalDate?>(functionName, LocalDateColumnType.INSTANSE, *params)
fun CustomDateTimeFunction(functionName: String, vararg params: Expression<*>) = CustomFunction<LocalDateTime?>(functionName, LocalDateTimeColumnType.INSTANSE, *params)
fun CustomDateFunction(functionName: String, vararg params: Expression<*>) = CustomFunction<LocalDate?>(functionName, JavaLocalDateColumnType.INSTANCE, *params)
fun CustomDateTimeFunction(functionName: String, vararg params: Expression<*>) = CustomFunction<LocalDateTime?>(functionName, JavaLocalDateTimeColumnType.INSTANCE, *params)

View File

@@ -7,6 +7,7 @@ import org.jetbrains.exposed.dao.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.BatchDataInconsistentException
import org.jetbrains.exposed.sql.statements.BatchInsertStatement
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.currentDialectTest
import org.jetbrains.exposed.sql.tests.inProperCase
@@ -16,11 +17,11 @@ import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.jetbrains.exposed.sql.tests.shared.expectException
import org.jetbrains.exposed.sql.vendors.OracleDialect
import org.jetbrains.exposed.sql.vendors.SQLServerDialect
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.junit.Test
import java.time.LocalDate
import java.time.LocalDateTime
class DefaultsTest : JodaTimeBaseTest() {
class DefaultsTest : DatabaseTestsBase() {
object TableWithDBDefault : IntIdTable() {
var cIndex = 0
val field = varchar("field", 100)
@@ -49,7 +50,7 @@ class DefaultsTest : JodaTimeBaseTest() {
DBDefault.new { field = "1" },
DBDefault.new {
field = "2"
t1 = DateTime.now().minusDays(5)
t1 = LocalDateTime.now().minusDays(5)
})
flushCache()
created.forEach {
@@ -67,7 +68,7 @@ class DefaultsTest : JodaTimeBaseTest() {
val created = listOf(
DBDefault.new{
field = "2"
t1 = DateTime.now().minusDays(5)
t1 = LocalDateTime.now().minusDays(5)
}, DBDefault.new{ field = "1" })
flushCache()
@@ -96,7 +97,7 @@ class DefaultsTest : JodaTimeBaseTest() {
it[TableWithDBDefault.field] = "1"
}, {
it[TableWithDBDefault.field] = "2"
it[TableWithDBDefault.t1] = DateTime.now()
it[TableWithDBDefault.t1] = LocalDateTime.now()
})
@Test
@@ -125,7 +126,7 @@ class DefaultsTest : JodaTimeBaseTest() {
@Test
fun testDefaults01() {
val currentDT = CurrentDateTime()
val nowExpression = object : Expression<DateTime>() {
val nowExpression = object : Expression<LocalDateTime>() {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
+when (currentDialectTest) {
is OracleDialect -> "SYSDATE"
@@ -134,8 +135,8 @@ class DefaultsTest : JodaTimeBaseTest() {
}
}
}
val dtConstValue = DateTime.parse("2010-01-01").withZone(DateTimeZone.UTC)
val dtLiteral = dateLiteral(dtConstValue)
val dtConstValue = LocalDate.of(2010, 1, 1)
val dtLiteral = dateTimeLiteral(dtConstValue.atStartOfDay())
val TestTable = object : IntIdTable("t") {
val s = varchar("s", 100).default("test")
val sn = varchar("sn", 100).default("testNullable").nullable()
@@ -183,8 +184,8 @@ class DefaultsTest : JodaTimeBaseTest() {
assertEquals("testNullable", row1[TestTable.sn])
assertEquals(42, row1[TestTable.l])
assertEquals('X', row1[TestTable.c])
assertEqualDateTime(dtConstValue.withTimeAtStartOfDay(), row1[TestTable.t3].withTimeAtStartOfDay())
assertEqualDateTime(dtConstValue.withTimeAtStartOfDay(), row1[TestTable.t4].withTimeAtStartOfDay())
assertEqualDateTime(dtConstValue.atStartOfDay(), row1[TestTable.t3])
assertEqualDateTime(dtConstValue.atStartOfDay(), row1[TestTable.t4])
val id2 = TestTable.insertAndGetId { it[TestTable.sn] = null }
@@ -213,7 +214,7 @@ class DefaultsTest : JodaTimeBaseTest() {
}
val result = foo.select { foo.id eq id }.single()
assertEquals(today, result[foo.defaultDateTime].withTimeAtStartOfDay())
assertEquals(today, result[foo.defaultDateTime].toLocalDate())
assertEquals(100, result[foo.defaultInt])
}
}
@@ -225,7 +226,7 @@ class DefaultsTest : JodaTimeBaseTest() {
val defaultDateTime = datetime("defaultDateTime").defaultExpression(CurrentDateTime())
}
val nonDefaultDate = DateTime.parse("2000-01-01")
val nonDefaultDate = LocalDate.of(2000, 1, 1).atStartOfDay()
withTables(foo) {
val id = foo.insertAndGetId {

View File

@@ -0,0 +1,31 @@
package org.jetbrains.exposed
import org.jetbrains.exposed.sql.tests.currentDialectTest
import org.jetbrains.exposed.sql.vendors.MysqlDialect
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.temporal.Temporal
import kotlin.test.assertEquals
fun <T:Temporal> assertEqualDateTime(d1: T?, d2: T?) {
when{
d1 == null && d2 == null -> return
d1 == null && d2 != null -> error("d1 is null while d2 is not on ${currentDialectTest.name}")
d2 == null -> error ("d1 is not null while d2 is null on ${currentDialectTest.name}")
d1 == null -> error("Impossible")
d1 is LocalDateTime && d2 is LocalDateTime && (currentDialectTest as? MysqlDialect)?.isFractionDateTimeSupported() == false ->
assertEquals(d1.toInstant(ZoneOffset.UTC).toEpochMilli() / 1000, d2.toInstant(ZoneOffset.UTC).toEpochMilli() / 1000, "Failed on ${currentDialectTest.name}")
else -> assertEquals(d1, d2, "Failed on ${currentDialectTest.name}")
}
}
fun equalDateTime(d1: Temporal?, d2: Temporal?) = try {
assertEqualDateTime(d1, d2)
true
} catch (e: Exception) {
false
}
val today: LocalDate = LocalDate.now()

View File

@@ -1,13 +1,15 @@
package org.jetbrains.exposed
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.shared.MiscTable
import org.jetbrains.exposed.sql.tests.shared.checkInsert
import org.jetbrains.exposed.sql.tests.shared.checkRow
import org.joda.time.DateTime
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
import kotlin.test.assertEquals
object Misc : MiscTable() {
@@ -18,12 +20,12 @@ object Misc : MiscTable() {
val tn = datetime("tn").nullable()
}
class MiscTableTest : JodaTimeBaseTest() {
class MiscTableTest : DatabaseTestsBase() {
@Test
fun testInsert01() {
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
withTables(tbl) {
tbl.insert {
@@ -49,7 +51,7 @@ class MiscTableTest : JodaTimeBaseTest() {
fun testInsert02() {
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
withTables(tbl) {
tbl.insert {
@@ -81,7 +83,7 @@ class MiscTableTest : JodaTimeBaseTest() {
fun testInsert03() {
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
withTables(tbl) {
tbl.insert {
@@ -115,7 +117,7 @@ class MiscTableTest : JodaTimeBaseTest() {
val stringThatNeedsEscaping = "A'braham Barakhyahu"
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
withTables(tbl) {
tbl.insert {
it[n] = 42
@@ -138,7 +140,7 @@ class MiscTableTest : JodaTimeBaseTest() {
fun testInsertGet01() {
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
withTables(tbl) {
val row = tbl.insert {
@@ -164,7 +166,7 @@ class MiscTableTest : JodaTimeBaseTest() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
val sTest = "test"
val dec = BigDecimal("239.42")
tbl.insert {
@@ -183,11 +185,11 @@ class MiscTableTest : JodaTimeBaseTest() {
tbl.checkRowFull(tbl.select { tbl.d.eq(date) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.dn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.dn.eq(null as DateTime?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.dn.eq(null as LocalDate?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.t.eq(time) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.tn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.tn.eq(null as DateTime?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.tn.eq(null as LocalDateTime?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.e.eq(MiscTable.E.ONE) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.en.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
@@ -204,7 +206,7 @@ class MiscTableTest : JodaTimeBaseTest() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
val sTest = "test"
val eOne = MiscTable.E.ONE
val dec = BigDecimal("239.42")
@@ -249,7 +251,7 @@ class MiscTableTest : JodaTimeBaseTest() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
val eOne = MiscTable.E.ONE
val sTest = "test"
val dec = BigDecimal("239.42")
@@ -291,7 +293,7 @@ class MiscTableTest : JodaTimeBaseTest() {
fun testUpdate03() {
val tbl = Misc
val date = today
val time = DateTime.now()
val time = LocalDateTime.now()
val eOne = MiscTable.E.ONE
val dec = BigDecimal("239.42")
withTables(excludeSettings = listOf(TestDB.MYSQL, TestDB.MARIADB), tables = *arrayOf(tbl)) {
@@ -318,7 +320,7 @@ class MiscTableTest : JodaTimeBaseTest() {
}
fun Misc.checkRowFull(row: ResultRow, n: Int, nn: Int?,
d: DateTime, dn: DateTime?, t: DateTime, tn: DateTime?,
d: LocalDate, dn: LocalDate?, t: LocalDateTime, tn: LocalDateTime?,
e: MiscTable.E, en: MiscTable.E?,
es: MiscTable.E, esn: MiscTable.E?, s: String, sn: String?,
dc: BigDecimal, dcn: BigDecimal?, fcn: Float?, dblcn: Double?) {
@@ -326,10 +328,10 @@ fun Misc.checkRowFull(row: ResultRow, n: Int, nn: Int?,
checkRowDates(row, d, dn, t, tn)
}
fun Misc.checkRowDates(row: ResultRow, d: DateTime, dn: DateTime?, t: DateTime, tn: DateTime?) {
assertEqualDateTime(row[this.d], d)
assertEqualDateTime(row[this.dn], dn)
assertEqualDateTime(row[this.t], t)
assertEqualDateTime(row[this.tn], tn)
fun Misc.checkRowDates(row: ResultRow, d: LocalDate, dn: LocalDate?, t: LocalDateTime, tn: LocalDateTime?) {
assertEqualDateTime(d, row[this.d])
assertEqualDateTime(dn, row[this.dn])
assertEqualDateTime(t, row[this.t])
assertEqualDateTime(tn, row[this.tn])
}

View File

@@ -0,0 +1,250 @@
package org.jetbrains.exposed
import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.BatchDataInconsistentException
import org.jetbrains.exposed.sql.statements.BatchInsertStatement
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.currentDialectTest
import org.jetbrains.exposed.sql.tests.inProperCase
import org.jetbrains.exposed.sql.tests.shared.assertEqualCollections
import org.jetbrains.exposed.sql.tests.shared.assertEqualLists
import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.jetbrains.exposed.sql.tests.shared.expectException
import org.jetbrains.exposed.sql.vendors.OracleDialect
import org.jetbrains.exposed.sql.vendors.SQLServerDialect
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.junit.Test
class JodaTimeDefaultsTest : JodaTimeBaseTest() {
object TableWithDBDefault : IntIdTable() {
var cIndex = 0
val field = varchar("field", 100)
val t1 = datetime("t1").defaultExpression(CurrentDateTime())
val clientDefault = integer("clientDefault").clientDefault { cIndex++ }
}
class DBDefault(id: EntityID<Int>): IntEntity(id) {
var field by TableWithDBDefault.field
var t1 by TableWithDBDefault.t1
val clientDefault by TableWithDBDefault.clientDefault
override fun equals(other: Any?): Boolean {
return (other as? DBDefault)?.let { id == it.id && field == it.field && equalDateTime(t1, it.t1) } ?: false
}
override fun hashCode(): Int = id.value.hashCode()
companion object : IntEntityClass<DBDefault>(TableWithDBDefault)
}
@Test
fun testDefaultsWithExplicit01() {
withTables(TableWithDBDefault) {
val created = listOf(
DBDefault.new { field = "1" },
DBDefault.new {
field = "2"
t1 = DateTime.now().minusDays(5)
})
flushCache()
created.forEach {
DBDefault.removeFromCache(it)
}
val entities = DBDefault.all().toList()
assertEqualCollections(created.map { it.id }, entities.map { it.id })
}
}
@Test
fun testDefaultsWithExplicit02() {
withTables(TableWithDBDefault) {
val created = listOf(
DBDefault.new{
field = "2"
t1 = DateTime.now().minusDays(5)
}, DBDefault.new{ field = "1" })
flushCache()
created.forEach {
DBDefault.removeFromCache(it)
}
val entities = DBDefault.all().toList()
assertEqualCollections(created, entities)
}
}
@Test
fun testDefaultsInvokedOnlyOncePerEntity() {
withTables(TableWithDBDefault) {
TableWithDBDefault.cIndex = 0
val db1 = DBDefault.new{ field = "1" }
val db2 = DBDefault.new{ field = "2" }
flushCache()
assertEquals(0, db1.clientDefault)
assertEquals(1, db2.clientDefault)
assertEquals(2, TableWithDBDefault.cIndex)
}
}
private val initBatch = listOf<(BatchInsertStatement) -> Unit>({
it[TableWithDBDefault.field] = "1"
}, {
it[TableWithDBDefault.field] = "2"
it[TableWithDBDefault.t1] = DateTime.now()
})
@Test
fun testRawBatchInsertFails01() {
withTables(TableWithDBDefault) {
expectException<BatchDataInconsistentException> {
BatchInsertStatement(TableWithDBDefault).run {
initBatch.forEach {
addBatch()
it(this)
}
}
}
}
}
@Test
fun testRawBatchInsertFails02() {
withTables(TableWithDBDefault) {
TableWithDBDefault.batchInsert(initBatch) { foo ->
foo(this)
}
}
}
@Test
fun testDefaults01() {
val currentDT = CurrentDateTime()
val nowExpression = object : Expression<DateTime>() {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
+when (currentDialectTest) {
is OracleDialect -> "SYSDATE"
is SQLServerDialect -> "GETDATE()"
else -> "NOW()"
}
}
}
val dtConstValue = DateTime.parse("2010-01-01").withZone(DateTimeZone.UTC)
val dtLiteral = dateLiteral(dtConstValue)
val TestTable = object : IntIdTable("t") {
val s = varchar("s", 100).default("test")
val sn = varchar("sn", 100).default("testNullable").nullable()
val l = long("l").default(42)
val c = char("c").default('X')
val t1 = datetime("t1").defaultExpression(currentDT)
val t2 = datetime("t2").defaultExpression(nowExpression)
val t3 = datetime("t3").defaultExpression(dtLiteral)
val t4 = date("t4").default(dtConstValue)
}
fun Expression<*>.itOrNull() = when {
currentDialectTest.isAllowedAsColumnDefault(this) ->
"DEFAULT ${currentDialectTest.dataTypeProvider.processForDefaultValue(this)} NOT NULL"
else -> "NULL"
}
withTables(listOf(TestDB.SQLITE), TestTable) {
val dtType = currentDialectTest.dataTypeProvider.dateTimeType()
val q = db.identifierManager.quoteString
val baseExpression = "CREATE TABLE " + addIfNotExistsIfSupported() +
"${"t".inProperCase()} (" +
"${"id".inProperCase()} ${currentDialectTest.dataTypeProvider.shortAutoincType()} PRIMARY KEY, " +
"${"s".inProperCase()} VARCHAR(100) DEFAULT 'test' NOT NULL, " +
"${"sn".inProperCase()} VARCHAR(100) DEFAULT 'testNullable' NULL, " +
"${"l".inProperCase()} ${currentDialectTest.dataTypeProvider.longType()} DEFAULT 42 NOT NULL, " +
"$q${"c".inProperCase()}$q CHAR DEFAULT 'X' NOT NULL, " +
"${"t1".inProperCase()} $dtType ${currentDT.itOrNull()}, " +
"${"t2".inProperCase()} $dtType ${nowExpression.itOrNull()}, " +
"${"t3".inProperCase()} $dtType ${dtLiteral.itOrNull()}, " +
"${"t4".inProperCase()} DATE ${dtLiteral.itOrNull()}" +
")"
val expected = if (currentDialectTest is OracleDialect)
arrayListOf("CREATE SEQUENCE t_id_seq", baseExpression)
else
arrayListOf(baseExpression)
assertEqualLists(expected, TestTable.ddl)
val id1 = TestTable.insertAndGetId { }
val row1 = TestTable.select { TestTable.id eq id1 }.single()
assertEquals("test", row1[TestTable.s])
assertEquals("testNullable", row1[TestTable.sn])
assertEquals(42, row1[TestTable.l])
assertEquals('X', row1[TestTable.c])
assertEqualDateTime(dtConstValue.withTimeAtStartOfDay(), row1[TestTable.t3].withTimeAtStartOfDay())
assertEqualDateTime(dtConstValue.withTimeAtStartOfDay(), row1[TestTable.t4].withTimeAtStartOfDay())
val id2 = TestTable.insertAndGetId { it[TestTable.sn] = null }
val row2 = TestTable.select { TestTable.id eq id2 }.single()
}
}
@Test
fun testDefaultExpressions01() {
fun abs(value: Int) = object : ExpressionWithColumnType<Int>() {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append("ABS($value)") }
override val columnType: IColumnType = IntegerColumnType()
}
val foo = object : IntIdTable("foo") {
val name = text("name")
val defaultDateTime = datetime("defaultDateTime").defaultExpression(CurrentDateTime())
val defaultInt = integer("defaultInteger").defaultExpression(abs(-100))
}
withTables(foo) {
val id = foo.insertAndGetId {
it[foo.name] = "bar"
}
val result = foo.select { foo.id eq id }.single()
assertEquals(today, result[foo.defaultDateTime].withTimeAtStartOfDay())
assertEquals(100, result[foo.defaultInt])
}
}
@Test
fun testDefaultExpressions02() {
val foo = object : IntIdTable("foo") {
val name = text("name")
val defaultDateTime = datetime("defaultDateTime").defaultExpression(CurrentDateTime())
}
val nonDefaultDate = DateTime.parse("2000-01-01")
withTables(foo) {
val id = foo.insertAndGetId {
it[foo.name] = "bar"
it[foo.defaultDateTime] = nonDefaultDate
}
val result = foo.select { foo.id eq id }.single()
assertEquals("bar", result[foo.name])
assertEqualDateTime(nonDefaultDate, result[foo.defaultDateTime])
foo.update({foo.id eq id}) {
it[foo.name] = "baz"
}
val result2 = foo.select { foo.id eq id }.single()
assertEquals("baz", result2[foo.name])
assertEqualDateTime(nonDefaultDate, result2[foo.defaultDateTime])
}
}
}

View File

@@ -0,0 +1,335 @@
package org.jetbrains.exposed
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.shared.MiscTable
import org.jetbrains.exposed.sql.tests.shared.checkInsert
import org.jetbrains.exposed.sql.tests.shared.checkRow
import org.joda.time.DateTime
import org.junit.Test
import java.math.BigDecimal
import kotlin.test.assertEquals
object Misc : MiscTable() {
val d = date("d")
val dn = date("dn").nullable()
val t = datetime("t")
val tn = datetime("tn").nullable()
}
class JodaTimeMiscTableTest : JodaTimeBaseTest() {
@Test
fun testInsert01() {
val tbl = Misc
val date = today
val time = DateTime.now()
withTables(tbl) {
tbl.insert {
it[n] = 42
it[d] = date
it[t] = time
it[e] = MiscTable.E.ONE
it[es] = MiscTable.E.ONE
it[s] = "test"
it[dc] = BigDecimal("239.42")
it[char] = '('
}
val row = tbl.selectAll().single()
tbl.checkRow(row, 42, null, MiscTable.E.ONE, null, MiscTable.E.ONE,
null, "test", null, BigDecimal("239.42"), null, null, null)
tbl.checkRowDates(row, date, null, time, null)
assertEquals('(', row[tbl.char])
}
}
@Test
fun testInsert02() {
val tbl = Misc
val date = today
val time = DateTime.now()
withTables(tbl) {
tbl.insert {
it[n] = 42
it[nn] = null
it[d] = date
it[dn] = null
it[t] = time
it[tn] = null
it[e] = MiscTable.E.ONE
it[en] = null
it[es] = MiscTable.E.ONE
it[esn] = null
it[s] = "test"
it[sn] = null
it[dc] = BigDecimal("239.42")
it[dcn] = null
it[fcn] = null
}
val row = tbl.selectAll().single()
tbl.checkRow(row, 42, null, MiscTable.E.ONE, null, MiscTable.E.ONE,
null, "test", null, BigDecimal("239.42"), null, null, null)
tbl.checkRowDates(row, date, null, time, null)
}
}
@Test
fun testInsert03() {
val tbl = Misc
val date = today
val time = DateTime.now()
withTables(tbl) {
tbl.insert {
it[n] = 42
it[nn] = 42
it[d] = date
it[dn] = date
it[t] = time
it[tn] = time
it[e] = MiscTable.E.ONE
it[en] = MiscTable.E.ONE
it[es] = MiscTable.E.ONE
it[esn] = MiscTable.E.ONE
it[s] = "test"
it[sn] = "test"
it[dc] = BigDecimal("239.42")
it[dcn] = BigDecimal("239.42")
it[fcn] = 239.42f
it[dblcn] = 567.89
}
val row = tbl.selectAll().single()
tbl.checkRow(row, 42, 42, MiscTable.E.ONE, MiscTable.E.ONE, MiscTable.E.ONE, MiscTable.E.ONE,
"test", "test", BigDecimal("239.42"), BigDecimal("239.42"), 239.42f, 567.89)
tbl.checkRowDates(row, date, date, time, time)
}
}
@Test
fun testInsert04() {
val stringThatNeedsEscaping = "A'braham Barakhyahu"
val tbl = Misc
val date = today
val time = DateTime.now()
withTables(tbl) {
tbl.insert {
it[n] = 42
it[d] = date
it[t] = time
it[e] = MiscTable.E.ONE
it[es] = MiscTable.E.ONE
it[s] = stringThatNeedsEscaping
it[dc] = BigDecimal("239.42")
}
val row = tbl.selectAll().single()
tbl.checkRow(row, 42, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, stringThatNeedsEscaping, null,
BigDecimal("239.42"), null, null, null)
tbl.checkRowDates(row, date, null, time, null)
}
}
@Test
fun testInsertGet01() {
val tbl = Misc
val date = today
val time = DateTime.now()
withTables(tbl) {
val row = tbl.insert {
it[n] = 42
it[d] = date
it[t] = time
it[e] = MiscTable.E.ONE
it[es] = MiscTable.E.ONE
it[s] = "test"
it[dc] = BigDecimal("239.42")
it[char] = '('
}
tbl.checkInsert(row, 42, null, MiscTable.E.ONE, null, MiscTable.E.ONE,
null, "test", null, BigDecimal("239.42"), null, null, null)
tbl.checkRowDates(row.resultedValues!!.single(), date, null, time, null)
assertEquals('(', row[tbl.char])
}
}
@Test
fun testSelect01() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val sTest = "test"
val dec = BigDecimal("239.42")
tbl.insert {
it[n] = 42
it[d] = date
it[t] = time
it[e] = MiscTable.E.ONE
it[es] = MiscTable.E.ONE
it[s] = sTest
it[dc] = dec
}
tbl.checkRowFull(tbl.select { tbl.n.eq(42) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.nn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.nn.eq(null as Int?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.d.eq(date) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.dn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.dn.eq(null as DateTime?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.t.eq(time) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.tn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.tn.eq(null as DateTime?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.e.eq(MiscTable.E.ONE) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.en.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.en.eq(null as MiscTable.E?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.s.eq(sTest) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.sn.isNull() }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
tbl.checkRowFull(tbl.select { tbl.sn.eq(null as String?) }.single(), 42, null, date, null, time, null, MiscTable.E.ONE, null, MiscTable.E.ONE, null, sTest, null, dec, null, null, null)
}
}
@Test
fun testSelect02() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val sTest = "test"
val eOne = MiscTable.E.ONE
val dec = BigDecimal("239.42")
tbl.insert {
it[n] = 42
it[nn] = 42
it[d] = date
it[dn] = date
it[t] = time
it[tn] = time
it[e] = eOne
it[en] = eOne
it[es] = eOne
it[esn] = eOne
it[s] = sTest
it[sn] = sTest
it[dc] = dec
it[dcn] = dec
it[fcn] = 239.42f
it[dblcn] = 567.89
}
tbl.checkRowFull(tbl.select { tbl.nn.eq(42) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.nn.neq<Int?>(null) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.dn.eq(date) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.dn.isNotNull() }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.t.eq(time) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.tn.isNotNull() }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.en.eq(eOne) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.en.isNotNull() }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.sn.eq(sTest) }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
tbl.checkRowFull(tbl.select { tbl.sn.isNotNull() }.single(), 42, 42, date, date, time, time, eOne, eOne, eOne, eOne, sTest, sTest, dec, dec, 239.42f, 567.89)
}
}
@Test
fun testUpdate02() {
val tbl = Misc
withTables(tbl) {
val date = today
val time = DateTime.now()
val eOne = MiscTable.E.ONE
val sTest = "test"
val dec = BigDecimal("239.42")
tbl.insert {
it[n] = 42
it[nn] = 42
it[d] = date
it[dn] = date
it[t] = time
it[tn] = time
it[e] = eOne
it[en] = eOne
it[es] = eOne
it[esn] = eOne
it[s] = sTest
it[sn] = sTest
it[dc] = dec
it[dcn] = dec
it[fcn] = 239.42f
}
tbl.update({ tbl.n.eq(42) }) {
it[nn] = null
it[dn] = null
it[tn] = null
it[en] = null
it[esn] = null
it[sn] = null
it[dcn] = null
it[fcn] = null
}
val row = tbl.selectAll().single()
tbl.checkRowFull(row, 42, null, date, null, time, null, eOne, null, eOne, null, sTest, null, dec, null, null, null)
}
}
@Test
fun testUpdate03() {
val tbl = Misc
val date = today
val time = DateTime.now()
val eOne = MiscTable.E.ONE
val dec = BigDecimal("239.42")
withTables(excludeSettings = listOf(TestDB.MYSQL, TestDB.MARIADB), tables = *arrayOf(tbl)) {
tbl.insert {
it[n] = 101
it[s] = "123456789"
it[sn] = "123456789"
it[d] = date
it[t] = time
it[e] = eOne
it[es] = eOne
it[dc] = dec
}
tbl.update({ tbl.n.eq(101) }) {
it.update(s, tbl.s.substring(2, 255))
it.update(sn, tbl.s.substring(3, 255))
}
val row = tbl.select { tbl.n eq 101 }.single()
tbl.checkRowFull(row, 101, null, date, null, time, null, eOne, null, eOne, null, "23456789", "3456789", dec, null, null, null)
}
}
}
fun Misc.checkRowFull(row: ResultRow, n: Int, nn: Int?,
d: DateTime, dn: DateTime?, t: DateTime, tn: DateTime?,
e: MiscTable.E, en: MiscTable.E?,
es: MiscTable.E, esn: MiscTable.E?, s: String, sn: String?,
dc: BigDecimal, dcn: BigDecimal?, fcn: Float?, dblcn: Double?) {
checkRow(row, n, nn, e, en, es, esn, s, sn, dc, dcn, fcn, dblcn)
checkRowDates(row, d, dn, t, tn)
}
fun Misc.checkRowDates(row: ResultRow, d: DateTime, dn: DateTime?, t: DateTime, tn: DateTime?) {
assertEqualDateTime(row[this.d], d)
assertEqualDateTime(row[this.dn], dn)
assertEqualDateTime(row[this.t], t)
assertEqualDateTime(row[this.tn], tn)
}