Automatic unwrapping of value classes when they wrap over types that are "automatically wrapped" by terpal-sql
Would it be possible (without using kotlin-reflect)?
All the manual unwrapping (outside of the SQL query string) or adding ${Param.withSer(productId, ProductIdSerializer)} look overly boilerplaty.
Also when deserializing I now do the very verbose:
object ProductIdSerializer : KSerializer<ProductId> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ProductId", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: ProductId) = encoder.encodeLong(value.value)
override fun deserialize(decoder: Decoder) = ProductId(decoder.decodeLong())
}
@Serializable
data class Product(
@Serializable(with = ProductIdSerializer::class)
val id: ProductId,
val createdAt: DbInstant,
val updatedAt: DbInstant,
\\ ...
)
It seems that kotlinx.serialization handles this well (at least with JSON it does):
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@JvmInline
@Serializable
value class ProductId(val value: Long)
@Serializable
data class ProductDto(
val id: ProductId,
val name: String
)
fun main() {
val d = Json.decodeFromString<ProductDto>("""{"id": 1000, "name": "qweqw"}""")
println(d) // ProductDto(id=ProductId(value=1000), name=qweqw)
val s = Json.encodeToString(d)
println(s) // {"id":1000,"name":"qweqw"}
}
There a a few ways to get rid of the boilerplate here. The first way is to use contextual serialization and use Param.contextual. If you want even less boilerplate you can define a param-wrapper inside of the package (io.exoquery.sql). So something like:
package io.exoquery.sql
fun SqlInterpolator.wrap(value: ProductId?): Param<ProductId> = Param.withSer(productId, ProductIdSerializer)
Give that a shot and see if it works.
(P.S. io.exoquery.sql will eventually be renamed to io.exoquery.lang)