Custom Type Encoding
Using custom encoders and decoders for domain-specific types
ExoQuery supports custom encoders and decoders for domain-specific types, allowing you to map custom Kotlin types to database columns seamlessly.
JDBC Custom Encoding
For JDBC, you can add custom encoders and decoders to your database controller:
import io.exoquery.controller.JdbcControllers
import io.exoquery.controller.jdbc.JdbcEncoderAny
import io.exoquery.controller.jdbc.JdbcDecoderAny
import java.sql.Types
// Define a custom type
data class PersonId(val value: Int)
// Create a controller with custom encoding
val myDatabase = object : JdbcControllers.Postgres(dataSource) {
override val additionalDecoders =
super.additionalDecoders + JdbcDecoderAny { ctx, i -> PersonId(ctx.row.getInt(i)) }
override val additionalEncoders =
super.additionalEncoders + JdbcEncoderAny(Types.INTEGER) { ctx, v: PersonId, i ->
ctx.stmt.setInt(i, v.value)
}
}
R2DBC Custom Encoding
For R2DBC, you can configure custom encoders and decoders through the encoding config:
import io.exoquery.controller.r2dbc.R2dbcControllers
import io.exoquery.controller.r2dbc.R2dbcEncodingConfig
import io.exoquery.controller.r2dbc.R2dbcBasicEncoding
// Define a custom type
data class PersonId(val value: Int)
// Create a controller with custom encoding
val controller = R2dbcControllers.Postgres(
encodingConfig = R2dbcEncodingConfig.Default(
encoders = setOf(
R2dbcBasicEncoding.IntEncoder.contramap { id: PersonId -> id.value }
),
decoders = setOf(
R2dbcBasicEncoding.IntDecoder.map { PersonId(it) }
)
),
connectionFactory = connectionFactory
)
Using Custom Types in Queries
Once youโve configured custom encoding, you can use your custom types in queries with paramCtx:
val personId = PersonId(123)
val q = sql {
Table<Person>().filter { p -> p.id == paramCtx(personId) }
}
q.buildFor.Postgres().runOn(myDatabase)
//> SELECT p.id, p.name, p.age FROM Person p WHERE p.id = ?
Remember that for custom types used in entity classes, youโll need to mark the field with @Contextual:
@Serializable
data class Person(
@Contextual val id: PersonId,
val name: String,
val age: Int
)