DSL template #
A template module for the :dsl module.
Do NOT modify the production code of the :dsl module directly.
Instead, modify this template module.
Tests, however, are written in the :dsl module and not in :dsl-template.
This module is not published.
The problem #
The :dsl module contains the 'meat' of the KtMongo project: the entire operator DSL, including aggregation support.
To be convenient for users, we regularly need to provide multiple overloads of each operator. For example, the type Field<T, V> represents a path to a field:
users.find {
User::profile / Profile::age eq 20
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// Field("profile.age")
}
The Field interface allows complex path generation. However, top-level properties inherently are typed as KProperty1<T, V>, as they are a Kotlin feature. We cannot control that type.
users.find {
User::name eq "Bob"
// ^^^^^^^
// KProperty1<User, String>("name")
}
Therefore, we need an overload:
infix fun <V> KProperty1<T, V>.eq(value: V) {
this.field eq value
}
where KProperty1<T, V>.field is the conversion function.
All regular operators (filters, updates, projections, indexes…) need both Field and KProperty1 overloads.
However, aggregation operators go even further, requiring four overloads:
opensavvy.ktmongo.dsl.aggregation.Value<T, V>(the actual type of aggregation expressions)opensavvy.ktmongo.dsl.path.Field<T, V>kotlin.reflect.KProperty1<T, V>T
Note that the last two are not our types, so it isn't possible to create a supertype. T isn't even a known type.
Additionally, KotlinX.Serialization must know the compile-time type of any serialized value. This can only be accessed in an inline function, so all of these require additional inline overloads.
The solution #
Instead of developing the DSL module directly, all production code is written in this template module.
On each build, the :dsl module is regenerated by copying this template module, adding all the necessary overloads in the process.
The templating engine is implemented in the dsl-templator Gradle plugin.
It is executed by running ./gradlew :dsl:applyTemplate.