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

Emil Kantis

06/07/2021, 8:36 PM
I'm kinda new with delegates.. I'd like to create one to help me store json in a varchar column.. My gut feeling tells me I'm overcomplicating things here.. Any feedback on better approaches? 🙏
Copy code
// Entity
class Client(id: EntityID<Int>) : IntEntity(id) {
   companion object : IntEntityClass<Client>(Clients)
   // Some code omitted
   var tags2: List<String> by jsonStore(Clients.tags)
}

// Delegate provider
inline fun <reified S, T : Comparable<T>> Entity<T>.jsonStore(column: Column<String>) = JsonStore<T, S>(
   serializer(),
   column,
   { column.lookup() },
   { thisRef, property, value -> column.setValue(thisRef, property, value) }
)

// Delegate
class JsonStore<T : Comparable<T>, S>(
   val serializer: KSerializer<S>,
   val column: Column<String>,
   val lookup: (Column<String>) -> String,
   val write: (Entity<T>, KProperty<*>, String) -> Unit
) {
   
   operator fun getValue(thisRef: Any?, property: KProperty<*>): S = 
      json.decodeFromString(serializer, lookup(column))
   
   operator fun setValue(thisRef: Entity<T>, property: KProperty<*>, value: S) = 
      write(thisRef, property, json.encodeToString(serializer, value))
}
r

rnett

06/08/2021, 2:01 AM
Seems pretty good, you can move both of the lambdas into JsonStore I think, you should have everything you need (you'll need to make `getValue`'s thisRef
Entity
, but that's going to be the case anyways).
Also wouldn't hurt to make JsonStore's constructor internal
You might be able to use Exposed's caching to avoid repeating serialization/deserialization, but I'm not sure how you would do that. Depends on how performant you need it to be, it shouldn't be that bad. Also if this isn't just something for internal use considering making the
Json
instance a
TextFormat
parameter.
e

Emil Kantis

06/08/2021, 12:25 PM
Thanks! Using Exposed's caching would be interesting 🙂 I don't believe I can move the lambdas from
jsonStore
to
JsonStore
since the
column.lookup()
function is defined in
Entity
, not accessible outside.. likewise with
setValue
r

rnett

06/08/2021, 8:53 PM
Yeah, but you get the Entity as
thisRef
in the get/setValue functions. You have it now in
setValue
, you would just have to change `getValue`'s
thisRef
type (which isn't an issue since you can only create the delegate inside of an Entity anyways).
💡 1
e

Emil Kantis

06/08/2021, 9:03 PM
good point.. updated version:
Copy code
class JsonStore<T : Comparable<T>, S>(
   private val json: Json,
   private val serializer: KSerializer<S>,
   private val column: Column<String>,
) {

   operator fun getValue(thisRef: Entity<T>, property: KProperty<*>): S =
      json.decodeFromString(serializer, with(thisRef) { column.lookup() })

   operator fun setValue(thisRef: Entity<T>, property: KProperty<*>, value: S) =
      with(thisRef) { column.setValue(this, property, json.encodeToString(serializer, value)) }
}


inline fun <T : Comparable<T>, reified S> jsonStore(column: Column<String>, json: Json = Json.Default) = JsonStore<T, S>(
   json,
   serializer(),
   column,
)
much simpler, thanks!
2 Views