I have an example with some uncommon approach to use context, but it was working in 1.9.24. In 2.0 is failing and I don’t know how to solve it. The code is:
import kotlin.reflect.*
open class Property<T, V: Any>(val name: String)
class NullableProperty<T, V: Any>(name: String): Property<T, V>(name)
open class Field<T, V: Any>(name: String): Property<T, V>(name)
class NullableField<T, V: Any>(name: String): Field<T, V>(name)
open class Reference<T, V: Any>(name: String): Property<T, V>(name)
class NullableReference<T, V: Any>(name: String): Reference<T, V>(name)
interface Model<T: Model<T>> {
fun string(name: String) = Field<T, String>(name)
fun stringList(name: String) = Field<T, List<String>>(name)
fun boolean(name: String) = Field<T, Boolean>(name)
fun booleanList(name: String) = Field<T, List<Boolean>>(name)
fun <V: Model<*>> ref(name: String) = Reference<T, V>(name)
fun <V: Model<*>> refList(name: String) = Reference<T, List<V>>(name)
fun <V: Any> computed(name: String, result: Dependency<T>.() -> V) = Property<T, V>(name)
}
class Dependency<T> {
operator fun <V: Any> Property<T, V>.invoke() = "DEP" as V
}
typealias OnChange<K> = context(K) Change<K>.() -> Unit
@DslMarker
annotation class MyDsl
@MyDsl
class Change<T>(private val id: String? = null, private val parent: Change<*>? = null) {
private val changes = mutableMapOf<Field<T, *>, Any>()
private val childs = mutableMapOf<Reference<T, *>, Change<*>>()
infix fun <V: Any> Field<T, V>.set(value: V) =
changes.put(this@Field, value)
infix fun <V: Model<*>> Reference<T, V>.set(onChange: OnChange<V>): Unit {
val item = AddressView as V // get from store
val result = Change<V>(null, this@Change)
onChange(item, result)
childs.put(this@Reference, result)
}
infix fun <V: Model<*>> Reference<T, List<V>>.on(id: String): Reference<T, V> {
return Reference<T, V>("$name:$id")
}
override fun toString() = """
| id: ${id}
| changes: ${changes}
| childs: ${childs}
""".trimMargin()
}
fun <T: Model<*>> change(id: String, onChange: OnChange<T>): Change<T> {
val item = UserView as T // get from store
val result = Change<T>(id)
onChange(item, result)
return result
}
//----------------------------------------------------------------------------------
object UserView: Model<UserView> {
val name = string("name")
val email = string("email")
val isActive = boolean("isActive")
val someList = stringList("someList")
val address = ref<AddressView>("address")
val manyAddress = refList<AddressView>("manyAddress")
}
object AddressView: Model<AddressView> {
val country = string("country")
val city = string("city")
val address = computed("address") {
"${country()} from ${city()}"
}
}
fun main() {
val changes = change<UserView>("user-id") {
name set "Alex"
isActive set true
someList set listOf("One", "Two")
address set {
country set "Portugal"
}
for (id in listOf("one", "two"))
manyAddress on id set {
city set "$id-Aveiro"
}
}
println(changes)
}