Hey I just wrote this and wonder if there is an ea...
# exposed
h
Hey I just wrote this and wonder if there is an easier way to achieve the same thing. Background is that the
value: String
comes from an API call over HTTP. So I want to always compare against a given
String
in the where clause. I can't filter after the fact in Kotlin, because it's part of a paging scheme. I tried poking AI about a better way, but they were no help in this case.
Copy code
fun <T : Any, V: T?> Column<V>.compareWithString(value: String): Op<Boolean> {
    if(columnType is EntityIDColumnType<*>){
        val checkType = (columnType as EntityIDColumnType<T>).idColumn.columnType
        val typedValue = when (checkType) {
            is IntegerColumnType -> value.toInt() as T
            is LongColumnType -> value.toLong() as T
            is UUIDColumnType -> UUID.fromString(value) as T
            is StringColumnType -> value as T
            is BooleanColumnType -> value.toBooleanStrictOrNull() as T
            else -> error("Unsupported column type for comparison: $columnType")
        }
        return (this as Column<EntityID<T>>) eq typedValue
    } else {
        val typedValue = when (columnType) {
            is IntegerColumnType -> value.toInt() as V
            is LongColumnType -> value.toLong() as V
            is UUIDColumnType -> UUID.fromString(value) as V
            is StringColumnType -> value as V
            is BooleanColumnType -> value.toBooleanStrictOrNull() as V
            else -> error("Unsupported column type for comparison: $columnType")
        }
        return this eq typedValue
    }
}
Okay in between I went with this:
Copy code
data class ExposedMapper<T>(
    val column: Column<T>,
    val castFn: (String) -> Any?
)

val exposedMapper = mapOf(
    TableField.DEVICE_DEVICE_ID to ExposedMapper(DeviceIdentificationTable.deviceId) { it.toIntOrNull() }, // assuming String
    TableField.DEVICE_SERIAL_NUMBER to ExposedMapper(DeviceIdentificationTable.serialNumber) { it.toIntOrNull() },
    TableField.DEVICE_CPU_ID to ExposedMapper(DeviceIdentificationTable.cpuId) { it },
    TableField.DEVICE_HARDWARE_ID to ExposedMapper(DeviceHardwareIdTable.hardwareId) { it.toIntOrNull() },
    TableField.DEVICE_VEHICLE_ID to ExposedMapper(DeviceIdentificationTable.vehicleId) { it },
    TableField.DEVICE_COMPANY_ID to ExposedMapper(DeviceIdentificationTable.companyId) { it },
    TableField.DEVICE_PRODUCT to ExposedMapper(DeviceIdentificationTable.product) { Product.findNameIncomplete(it) },
)

fun <T : Any, E: EntityID<T>, V: T?>ExposedMapper<V>.compareToString(value: String): Op<Boolean> {
    val castResult = this.castFn(value) ?: return Op.FALSE
    return if(this.column.columnType is EntityIDColumnType<*>){
        (this.column as Column<E>) eq castResult as T
    } else {
        this.column eq castResult as V
    }
}
But then I hit a snag that I couldn't really search for incomplete filter with
like
So I looked again and found
.castTo
and rewrote it to this:
Copy code
data class ExposedMapper<T>(
    val column: Column<T>,
    val filterTransform: (String) -> String?
)

val exposedMapper = mapOf(
    TableField.DEVICE_DEVICE_ID to ExposedMapper(DeviceIdentificationTable.deviceId) { it }, // assuming String
    TableField.DEVICE_SERIAL_NUMBER to ExposedMapper(DeviceIdentificationTable.serialNumber) { it },
    TableField.DEVICE_CPU_ID to ExposedMapper(DeviceIdentificationTable.cpuId) { it },
    TableField.DEVICE_HARDWARE_ID to ExposedMapper(DeviceHardwareIdTable.hardwareId) { it },
    TableField.DEVICE_VEHICLE_ID to ExposedMapper(DeviceIdentificationTable.vehicleId) { it },
    TableField.DEVICE_COMPANY_ID to ExposedMapper(DeviceIdentificationTable.companyId) { it },
    TableField.DEVICE_PRODUCT to ExposedMapper(DeviceIdentificationTable.product) { Product.findNameIncomplete(it)?.name },
)

// usage with surrounding code omitted:
window.filtering.forEach {
        exposedMapper[it.filterField]?.let { (keySelector, transform) ->
            val filter = transform(it.filterValue) ?: return@forEach
            query = try {
                query.andWhere { keySelector.castTo(TextColumnType()) like "%$filter%" }
            } catch (e: SQLException) {
                query
            }
        }
    }
Which works quite well.