terpal-sql icon indicating copy to clipboard operation
terpal-sql copied to clipboard

Automatic unwrapping of value classes when they wrap over types that are "automatically wrapped" by terpal-sql

Open cies opened this issue 2 months ago • 3 comments

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.

cies avatar Oct 22 '25 09:10 cies

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,

  \\ ...
)

cies avatar Oct 22 '25 10:10 cies

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"}
}

cies avatar Oct 22 '25 11:10 cies

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)

deusaquilus avatar Nov 13 '25 20:11 deusaquilus