All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lightningkite.lightningdb.Mask.kt Maven / Gradle / Ivy

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy