com.lightningkite.lightningdb.Mask.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of server-core Show documentation
Show all versions of server-core Show documentation
A set of tools to fill in/replace what Ktor is lacking in.
The newest version!
package com.lightningkite.lightningdb
import com.lightningkite.khrysalis.IsCodableAndHashable
import kotlinx.serialization.Serializable
import org.slf4j.LoggerFactory
@Serializable
data class Mask(
/**
* If the condition does not pass, then the modification will be applied to mask the values.
*/
val pairs: List, Modification>> = listOf()
) {
companion object {
val logger = LoggerFactory.getLogger("com.lightningkite.lightningdb.Mask")
}
operator fun invoke(on: T): T {
var value = on
for(pair in pairs) {
if(!pair.first(on)) value = pair.second(value)
}
return value
}
operator fun invoke(on: Partial): Partial {
var value = on
for(pair in pairs) {
val evaluated = pair.first(on)
if(evaluated != true) value = pair.second(value)
}
return value
}
fun permitSort(on: List>): Condition {
val totalConditions = ArrayList>()
for(pair in pairs) {
if(on.any { pair.second.affects(it.field) }) totalConditions.add(pair.first)
}
return when(totalConditions.size) {
0 -> Condition.Always()
1 -> totalConditions[0]
else -> Condition.And(totalConditions)
}
}
operator fun invoke(on: DataClassPathPartial): Condition {
val totalConditions = ArrayList>()
for(pair in pairs) {
if(pair.second.affects(on)) totalConditions.add(pair.first)
}
return when(totalConditions.size) {
0 -> Condition.Always()
1 -> totalConditions[0]
else -> Condition.And(totalConditions)
}
}
operator fun invoke(condition: Condition): Condition {
val totalConditions = ArrayList>()
for(pair in pairs) {
if(condition.readsResultOf(pair.second)) totalConditions.add(pair.first)
}
return when(totalConditions.size) {
0 -> Condition.Always()
1 -> totalConditions[0]
else -> Condition.And(totalConditions)
}
}
class Builder(
val pairs: ArrayList, Modification>> = ArrayList()
) {
val it = path()
fun DataClassPath.mask(value: V, unless: Condition = Condition.Never()) {
pairs.add(unless to mapModification(Modification.Assign(value)))
}
infix fun DataClassPath.maskedTo(value: V) = mapModification(Modification.Assign(value))
infix fun Modification.unless(condition: Condition) {
pairs.add(condition to this)
}
fun always(modification: Modification) {
pairs.add(Condition.Never() to modification)
}
fun build() = Mask(pairs)
fun include(mask: Mask) { pairs.addAll(mask.pairs) }
}
}
inline fun mask(builder: Mask.Builder.()->Unit): Mask {
return Mask.Builder().apply(builder).build()
}
operator fun Condition.invoke(map: Partial): Boolean? {
return when(this) {
is Condition.Always -> true
is Condition.Never -> false
is Condition.And -> {
val results = this.conditions.map { it(map) }
if(results.any { it == false }) false
else if(results.any { it == null }) null
else true
}
is Condition.Or -> {
val results = this.conditions.map { it(map) }
if(results.any { it == true }) true
else if(results.any { it == null }) null
else true
}
is Condition.Not -> condition(map)?.not()
is Condition.OnField<*, *> -> if(map.parts.containsKey(key.name)) map.parts[key.name].let {
if(it is Partial<*>) (condition as Condition).invoke(map = it as Partial)
else (condition as Condition)(it)
} else null
else -> null
}
}
operator fun Modification.invoke(map: Partial): Partial {
return when(this) {
is Modification.OnField<*, *> -> if(map.parts.containsKey(key.name)) {
val newPartial = Partial(map.parts.toMutableMap())
newPartial.parts[key.name] = map.parts[key.name].let {
if (it is Partial<*>) (modification as Modification)(it as Partial)
else (modification as Modification)(it)
}
newPartial
} else map
else -> map
}
}