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

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

The newest version!
package com.lightningkite.lightningdb

import kotlin.reflect.KProperty1

// Sink properties, reduce within properties, reduce all

fun  Condition.simplify(): Condition {
    return when(this) {
        is Condition.And -> {
//            println("AND simplifying $this")
            conditions.asSequence().flatMap { it.andByField() }
                .groupBy { it.first }
                .mapNotNull {
//                    println("AND key ${it.key.map { it.name }}: merging parts ${it.value.map { it.second }}")
                    val keyCond = it.value.map { it.second as Condition }.reduce(::reduceAnd).finalSimplify()
//                    println("AND reduced to $keyCond")
                    when (keyCond) {
                        is Condition.Always -> return@mapNotNull null
                        is Condition.Never -> return Condition.Never()
                        else -> make(it.key, keyCond) as Condition
                    }
                }
                .let {
//                    println("AND total simplification list: $it")
                    if (it.isEmpty()) Condition.Always()
                    else if (it.size == 1) it.first()
                    else Condition.And(it)
                }
//                .also { println("AND final is $it") }
        }
        is Condition.Or -> {
//            println("OR simplifying $this")
            conditions.asSequence().flatMap { it.orByField() }
                .groupBy { it.first }
                .mapNotNull {
//                    println("OR key ${it.key.map { it.name }}: merging parts ${it.value.map { it.second }}")
                    val keyCond = it.value.map { it.second as Condition }.reduce(::reduceOr).finalSimplify()
//                    println("OR reduced to $keyCond")
                    when (keyCond) {
                        is Condition.Always -> return Condition.Always()
                        is Condition.Never -> return@mapNotNull null
                        else -> make(it.key, keyCond) as Condition
                    }
                }
                .let {
//                    println("OR total simplification list: $it")
                    if (it.isEmpty()) Condition.Never()
                    else if (it.size == 1) it.first()
                    else Condition.Or(it)
                }
//                .also { println("OR final is $it") }
        }
        else -> finalSimplify()
    }
}

private fun  Condition.finalSimplify(): Condition = when(this) {
    is Condition.Inside -> if(values.isEmpty()) Condition.Never() else this
    is Condition.NotInside -> if(values.isEmpty()) Condition.Always() else this
    else -> this
}

private fun Condition<*>.andByField(): Sequence>, Condition<*>>> {
    return when (this) {
        is Condition.And -> conditions.asSequence().flatMap { it.andByField() }
        is Condition.OnField<*, *> -> condition.andByField().map {
            (listOf(key) + it.first) to it.second
        }
        else -> {
            val s = this.simplify()
            if(s is Condition.OnField<*, *>) s.condition.andByField().map {
                (listOf(s.key) + it.first) to it.second
            } else sequenceOf(listOf>() to s)
        }
    }
}

private fun Condition<*>.orByField(): Sequence>, Condition<*>>> {
    return when (this) {
        is Condition.Or -> conditions.asSequence().flatMap { it.orByField() }
        is Condition.OnField<*, *> -> condition.orByField().map {
            (listOf(key) + it.first) to it.second
        }
        else -> {
            val s = this.simplify()
            if(s is Condition.OnField<*, *>) s.condition.orByField().map {
                (listOf(s.key) + it.first) to it.second
            } else sequenceOf(listOf>() to s)
        }
    }
}

private fun make(prop: List>, cond: Condition<*>): Condition<*> {
    @Suppress("UNCHECKED_CAST")
    (return if (prop.isEmpty()) cond
    else Condition.OnField(
        prop.first() as KProperty1,
        make(prop.subList(1, prop.size), cond) as Condition
    ))
}

private fun  reduceAnd(a: Condition, b: Condition): Condition {
    return when (a) {
        is Condition.Always -> b
        is Condition.Never -> a
        is Condition.And -> when (b) {
            is Condition.And -> Condition.And(a.conditions + b.conditions)
            else -> Condition.And(a.conditions + b)
        }

        is Condition.Equal -> when (b) {
            is Condition.Equal -> if (a.value == b.value) a else Condition.Never()
            is Condition.GreaterThan -> if (a.value.let { it as Comparable } > b.value.let { it as Comparable }) a else Condition.Never()
            is Condition.LessThan -> if (a.value.let { it as Comparable } < b.value.let { it as Comparable }) a else Condition.Never()
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) a else Condition.Never()
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) a else Condition.Never()
            is Condition.NotEqual -> if (a.value != b.value) a else Condition.Never()
            is Condition.Inside -> if (a.value in b.values) a else Condition.Never()
            is Condition.NotInside -> if (a.value !in b.values) a else Condition.Never()
            is Condition.And -> Condition.And(b.conditions + a)
            else -> Condition.And(listOf(a, b))
        }

        is Condition.GreaterThan -> when (b) {
            is Condition.GreaterThan -> if (a.value.let { it as Comparable } > b.value.let { it as Comparable }) a else b
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) a else b
            is Condition.LessThan -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) Condition.Never() else Condition.And(listOf(a, b))
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) Condition.Never() else Condition.And(listOf(a, b))
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        is Condition.LessThan -> when (b) {
            is Condition.LessThan -> if (a.value.let { it as Comparable } < b.value.let { it as Comparable }) a else b
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) a else b
            is Condition.GreaterThan,
            is Condition.GreaterThanOrEqual,
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        is Condition.GreaterThanOrEqual -> when (b) {
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) a else b
            is Condition.LessThan -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) Condition.Never() else Condition.And(listOf(a, b))
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } > b.value.let { it as Comparable }) Condition.Never() else Condition.And(listOf(a, b))
            is Condition.GreaterThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        is Condition.LessThanOrEqual -> when (b) {
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) a else b
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        is Condition.Inside -> when (b) {
            is Condition.Inside -> Condition.Inside(a.values.toSet().intersect(b.values.toSet()).toList())
            is Condition.NotInside -> Condition.Inside(a.values.toSet().minus(b.values.toSet()).toList())
            is Condition.GreaterThan,
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        is Condition.NotInside -> when (b) {
            is Condition.NotInside -> Condition.NotInside(a.values.toSet().union(b.values.toSet()).toList())
            is Condition.Inside,
            is Condition.GreaterThan,
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.And,
            is Condition.Equal -> reduceAnd(b, a)

            else -> Condition.And(listOf(a, b))
        }

        else -> Condition.And(listOf(a, b))
    }
}
private fun  reduceOr(a: Condition, b: Condition): Condition {
    return when (a) {
        is Condition.Always -> a
        is Condition.Never -> b
        is Condition.Or -> when (b) {
            is Condition.Or -> Condition.Or(a.conditions + b.conditions)
            else -> Condition.Or(a.conditions + b)
        }

        is Condition.Equal -> when (b) {
            is Condition.Equal -> if (a.value == b.value) a else Condition.Inside(listOf(a.value, b.value))
            is Condition.GreaterThan -> if (a.value.let { it as Comparable } > b.value.let { it as Comparable }) b else Condition.Or(listOf(a, b))
            is Condition.LessThan -> if (a.value.let { it as Comparable } < b.value.let { it as Comparable }) b else Condition.Or(listOf(a, b))
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) b else Condition.Or(listOf(a, b))
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) b else Condition.Or(listOf(a, b))
            is Condition.NotEqual -> if (a.value != b.value) b else Condition.Always()
            is Condition.Inside -> if (a.value in b.values) b else Condition.Inside(b.values + a.value)
            is Condition.NotInside -> if (a.value !in b.values) b else Condition.NotInside(b.values - a.value)
            is Condition.Or -> Condition.Or(b.conditions + a)
            else -> Condition.Or(listOf(a, b))
        }

        is Condition.GreaterThan -> when (b) {
            is Condition.GreaterThan -> if (a.value.let { it as Comparable } > b.value.let { it as Comparable }) b else a
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) b else a
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        is Condition.LessThan -> when (b) {
            is Condition.LessThan -> if (a.value.let { it as Comparable } < b.value.let { it as Comparable }) b else a
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) b else a
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        is Condition.GreaterThanOrEqual -> when (b) {
            is Condition.GreaterThanOrEqual -> if (a.value.let { it as Comparable } >= b.value.let { it as Comparable }) b else a
            is Condition.GreaterThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        is Condition.LessThanOrEqual -> when (b) {
            is Condition.LessThanOrEqual -> if (a.value.let { it as Comparable } <= b.value.let { it as Comparable }) b else a
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        is Condition.Inside -> when (b) {
            is Condition.Inside -> Condition.Inside(a.values.toSet().union(b.values.toSet()).toList())
            is Condition.NotInside -> Condition.NotInside(b.values.toSet().minus(a.values.toSet()).toList())
            is Condition.GreaterThan,
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        is Condition.NotInside -> when (b) {
            is Condition.NotInside -> Condition.NotInside(a.values.toSet().intersect(b.values.toSet()).toList())
            is Condition.Inside,
            is Condition.GreaterThan,
            is Condition.LessThan,
            is Condition.Always,
            is Condition.Never,
            is Condition.Or,
            is Condition.Equal -> reduceOr(b, a)

            else -> Condition.Or(listOf(a, b))
        }

        else -> Condition.Or(listOf(a, b))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy