Exposed icon indicating copy to clipboard operation
Exposed copied to clipboard

Provided Column Type Not Included In Operators For Primitive Value Types

Open baswerc opened this issue 1 year ago • 7 comments

I'm trying to understand why the provided column type is not included in the wrap function of SQLExpressionBuilder for the primitive data types below?

    fun <T, S : T?> ExpressionWithColumnType<in S>.wrap(value: T): QueryParameter<T> = when (value) {
        is Boolean -> booleanParam(value)
        is Byte -> byteParam(value)
        is UByte -> ubyteParam(value)
        is Short -> shortParam(value)
        is UShort -> ushortParam(value)
        is Int -> intParam(value)
        is UInt -> uintParam(value)
        is Long -> longParam(value)
        is ULong -> ulongParam(value)
        is Float -> floatParam(value)
        is Double -> doubleParam(value)
        is String -> QueryParameter(value, columnType) // String value should inherit from column
        else -> QueryParameter(value, columnType)
    } as QueryParameter<T>

This seems to limit custom column types of any of these primitive types. Is that intended?

baswerc avatar Apr 06 '23 14:04 baswerc

Hi @baswerc , Could you please elaborate a bit more on what the issue is?

AlexeySoshin avatar Apr 08 '23 19:04 AlexeySoshin

Sure thing @AlexeySoshin . Let's say I want to create a long column type that actually stores the value as timezoneless timestamp type in the database. Something like this:

fun Table.timestampMilliseconds(name: String): Column<Long> = registerColumn(name, TimestampMilliseconds())

class TimestampMilliseconds() : ColumnType() {
    override fun sqlType(): String = "TIMESTAMP"

    override fun valueFromDB(value: Any): Long {
        return if (value is Timestamp) {
            value.time
        } else {
            throw IllegalArgumentException("Unsupported timestamp milliseconds value of type ${value.javaClass}.")
        }
    }

    override fun valueToDB(value: Any?): Any? {
        return if (value == null) {
            null
        } else if (value is Long) {
            Timestamp(value)
        } else if (value is Timestamp) {
            value
        } else {
            throw IllegalArgumentException("Unsupported timestamp milliseconds value of type ${value.javaClass}.")
        }
    }

    override fun setParameter(stmt: PreparedStatementApi, index: Int, value: Any?) {
        if (value == null) {
            super.setParameter(stmt, index, value)
        } else if (value is Long) {
            super.setParameter(stmt, index, Timestamp(value))
        } else if (value is Timestamp) {
            super.setParameter(stmt, index, value)
            value
        } else {
            throw IllegalArgumentException("Unsupported timestamp milliseconds value of type ${value.javaClass}.")
        }
    }
}

This seems to work fine except when I'm doing a query something like this:

MyTable.select { MyTable.createdAt lessEq System.currentTimeMillis() }

In this case the TimestampMilliseconds.setParameters isn't called for the query statement because a LongColumnType is used from the wrap function.

Maybe I'm just going about this the wrong way?

baswerc avatar Apr 08 '23 19:04 baswerc

I assume that your column is defined as:

object MyTable {
   val createdAt = timestampMilliseconds("created_at")
}

Something like that?

AlexeySoshin avatar Apr 08 '23 19:04 AlexeySoshin

That's correct. Just like that.

baswerc avatar Apr 08 '23 19:04 baswerc

@AlexeySoshin Anymore thoughts on this? Should I be using a different approach for this?

baswerc avatar Apr 15 '23 14:04 baswerc

Hey @baswerc. Thank you for filing this issue. Just to better understand what you're trying to do, why create a custom type instead of using any of the other available datetime/timestamp types?

joc-a avatar Jul 25 '23 12:07 joc-a

@joc-a We use an Oracle database with some Timestamp columns and we'd like to to work with those as long representing milliseconds from the epoch. We're able to work around it it would just be a little cleaner if we could define our column as type long.

baswerc avatar Jul 27 '23 17:07 baswerc

Thanks for this update @joc-a!

baswerc avatar May 30 '24 14:05 baswerc