Skip to content

Commit

Permalink
fix: EXPOSED-19 Max timestamp in SQLite not working
Browse files Browse the repository at this point in the history
In the `create` function in `ResultRow.kt`, `columnType` is null because `(field as? Column<*>)` is null. This causes the object read from the DB to be of type String instead of Timestamp, which results in failing to parse the date because it is not in the proper format for `Instant.parse`.

`field` is of type `org.jetbrains.exposed.sql.Max` when we run the test. This is the relationship between the classes (-> means "is a subclass of"):
Max -> Function -> ExpressionWithColumnType -> Expression
Column -> ExpressionWithColumnType -> Expression

We attempt to cast `Max` to `Column` and that fails because there is no relationship between them. So I created a marker interface `WithColumnType` for anything with a column type and cast to that instead.
  • Loading branch information
joc-a committed Apr 18, 2023
1 parent a13ac1e commit 0f21cfe
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Column<T>(
val name: String,
/** Data type of the column. */
override val columnType: IColumnType
) : ExpressionWithColumnType<T>(), DdlAware, Comparable<Column<*>> {
) : ExpressionWithColumnType<T>(), DdlAware, Comparable<Column<*>>, WithColumnType {
var foreignKey: ForeignKeyConstraint? = null

/** Returns the column that this column references. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -914,3 +914,10 @@ class EnumerationNameColumnType<T : Enum<T>>(
interface IDateColumnType {
val hasTimePart: Boolean
}

/**
* Marker interface for columns/expressions with a column type
*/
interface WithColumnType {
val columnType: IColumnType
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ class Min<T : Comparable<T>, in S : T?>(
/** Returns the expression from which the minimum value is obtained. */
val expr: Expression<in S>,
columnType: IColumnType
) : Function<T?>(columnType) {
) : Function<T?>(columnType), WithColumnType {

override val columnType: IColumnType
get() = super.columnType

override fun toQueryBuilder(queryBuilder: QueryBuilder): Unit = queryBuilder { append("MIN(", expr, ")") }
}

Expand All @@ -157,7 +161,10 @@ class Max<T : Comparable<T>, in S : T?>(
/** Returns the expression from which the maximum value is obtained. */
val expr: Expression<in S>,
columnType: IColumnType
) : Function<T?>(columnType) {
) : Function<T?>(columnType), WithColumnType {
override val columnType: IColumnType
get() = super.columnType

override fun toQueryBuilder(queryBuilder: QueryBuilder): Unit = queryBuilder { append("MAX(", expr, ")") }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class ResultRow(
fun create(rs: ResultSet, fieldsIndex: Map<Expression<*>, Int>): ResultRow {
return ResultRow(fieldsIndex).apply {
fieldsIndex.forEach { (field, index) ->
val columnType = (field as? ExpressionWithColumnType<*>)?.columnType
val columnType = (field as? WithColumnType)?.columnType
val value = if (columnType != null)
columnType.readObject(rs, index + 1)
else rs.getObject(index + 1)
Expand Down

0 comments on commit 0f21cfe

Please sign in to comment.