https://kotlinlang.org logo
#exposed
Title
# exposed
p

phldavies

07/26/2022, 11:06 AM
Is there a nice way to extend an existing column type? For example, if I have a
value class Id(id: String)
I’d like to have a column
Column<Id>
that wraps a
varchar(12)
.
r

Robert Kempton

07/29/2022, 5:02 AM
I'm trying to do exactly this as well. For TextColumnType and VarCharColumnType you can extend those classes and add whatever custom functionality you'd like. for instance,
Copy code
class AlwaysBlue : VarCharColumnType(colLength = 4) {
  override fun valueFromDB(value: Any): Any = "blue"
  override fun valueToDB(value: Any?): Any? = "blue"
  override fun notNullValueToDB(value: Any): Any = "blue"
  override fun nonNullValueToString(value: Any): String = "blue"
}
After creating your custom class, you can attach it to the Table type using an extension function
Copy code
fun <T> Table.alwaysBlue(name: String): Column<String> = 
    registerColumn(name, AlwaysBlue())
Unfortunately, most of the ColumnType implementations are final, and can't be extended this way. To get around this, I'd recommend the delegate pattern.
Copy code
open class DelegatingColumnType(private val delegate: ColumnType, nullable: Boolean = false) : ColumnType(nullable) {
    override fun sqlType(): String = delegate.sqlType()

    override fun valueFromDB(value: Any): Any = delegate.valueFromDB(value)

    override fun valueToString(value: Any?): String = delegate.valueToString(value)

    override fun valueToDB(value: Any?): Any? = delegate.valueToDB(value)

    override fun notNullValueToDB(value: Any): Any = delegate.notNullValueToDB(value)

    override fun nonNullValueToString(value: Any): String = delegate.nonNullValueToString(value)

    override fun readObject(rs: ResultSet, index: Int): Any? = delegate.readObject(rs, index)

    override fun setParameter(stmt: PreparedStatement, index: Int, value: Any?) =
        delegate.setParameter(stmt, index, value)
}
Using this you can extend any column type like so
Copy code
class AlwaysFour : DelegatingColumnType(IntegerColumnType()) {
  override fun valueFromDB(value: Any): Any = 4
  override fun valueToDB(value: Any?): Any? = 4
  override fun notNullValueToDB(value: Any): Any = 4
  override fun nonNullValueToString(value: Any): String = 4
}
Instead of the delegate class, I think you can use the built in delegation like so:
Copy code
class AlwaysFour(ct: IntegerColumnType) : IColumnType by ct {
    override fun valueFromDB(value: Any): Any = 4
    override fun valueToDB(value: Any?): Any = 4
    override fun notNullValueToDB(value: Any): Any = 4
    override fun nonNullValueToString(value: Any): String = "4"
}
But I'm not 100% sure that's right, as I'm not super familiar with how delegation works...
p

phldavies

07/29/2022, 7:48 AM
I've had some luck using a single column CompositeColumn to act as a mapper to my business objects. I'll add the snippet here once I'm at my desk.
5 Views