Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provided Column Type Not Included In Operators For Primitive Value Types #1720

Open
baswerc opened this issue Apr 6, 2023 · 7 comments
Open
Assignees

Comments

@baswerc
Copy link

baswerc commented Apr 6, 2023

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?

@AlexeySoshin
Copy link
Contributor

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

@baswerc
Copy link
Author

baswerc commented Apr 8, 2023

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?

@AlexeySoshin
Copy link
Contributor

I assume that your column is defined as:

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

Something like that?

@baswerc
Copy link
Author

baswerc commented Apr 8, 2023

That's correct. Just like that.

@baswerc
Copy link
Author

baswerc commented Apr 15, 2023

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

@joc-a
Copy link
Collaborator

joc-a commented Jul 25, 2023

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 joc-a self-assigned this Jul 25, 2023
@baswerc
Copy link
Author

baswerc commented Jul 27, 2023

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants