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

tech.harmonysoft.oss.sql.match.impl.SqlMatchers.kt Maven / Gradle / Ivy

package tech.harmonysoft.oss.sql.match.impl

import tech.harmonysoft.oss.common.data.ComparisonStrategy
import tech.harmonysoft.oss.common.data.DataProviderStrategy
import tech.harmonysoft.oss.sql.dsl.target.SqlTarget
import tech.harmonysoft.oss.sql.match.SqlKeyValueMatcher
import tech.harmonysoft.oss.sql.match.SqlKeyValueVisitor
import java.util.regex.Pattern
import kotlin.reflect.KClass

object MatchNoneMatcher : SqlKeyValueMatcher {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        return false
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return ""
    }
}

object MatchAllMatcher : SqlKeyValueMatcher {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        return true
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return ""
    }
}

interface SqlKeyValueLeafMatcher : SqlKeyValueMatcher {
    val key: SqlTarget.Column
}

abstract class AbstractLeafMatcher(
    override val key: SqlTarget.Column,
    val value: Any,
    val comparison: ComparisonStrategy,
    _valueType: KClass<*>
) : SqlKeyValueLeafMatcher {

    @Suppress("UNCHECKED_CAST")
    val valueType: KClass = _valueType as KClass

    fun  retrieveComparedValue(
        retrievalStrategy: DataProviderStrategy,
        holder: HOLDER
    ) = if (value is SqlTarget.Column) {
        retrievalStrategy.getData(holder, value)
    } else {
        value
    }

    override fun hashCode(): Int {
        var result = value.hashCode()
        result = 31 * result + key.hashCode()
        result = 31 * result + comparison.hashCode()
        return result
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) {
            return true
        }
        if (javaClass != other?.javaClass) {
            return false
        }
        return (other as? AbstractLeafMatcher)?.let {
            key == it.key && comparison.compare(valueType, value, it.value) == 0
        } ?: false
    }

    override fun toString(): String {
        val valueString = if (value is String) {
            "'$value'"
        } else {
            "$value"
        }
        return "$key ${this::class.simpleName} $valueString"
    }
}

data class Not(
    val delegate: SqlKeyValueMatcher
) : SqlKeyValueMatcher {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        return !delegate.matches(holder, retrivalStrategy)
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return "not ($delegate"
    }
}

class Eq(
    key: SqlTarget.Column,
    valueType: KClass<*>,
    value: Any,
    comparison: ComparisonStrategy
) : AbstractLeafMatcher(key, value, comparison, valueType) {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val actualValue = retrivalStrategy.getData(holder, key)
        val comparedValue = retrieveComparedValue(retrivalStrategy, holder)
        return comparison.compare(valueType, comparedValue, actualValue) == 0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }
}

class Gt(
    key: SqlTarget.Column,
    valueType: KClass<*>,
    value: Any,
    comparison: ComparisonStrategy
) : AbstractLeafMatcher(key, value, comparison, valueType) {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val comparedValue = retrieveComparedValue(retrivalStrategy, holder)
        val cmp = comparison.compare(valueType, retrivalStrategy.getData(holder, key), comparedValue) ?: return false
        return cmp > 0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }
}

class Ge(
    key: SqlTarget.Column,
    valueType: KClass<*>,
    value: Any,
    comparison: ComparisonStrategy
) : AbstractLeafMatcher(key, value, comparison, valueType) {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val comparedValue = retrieveComparedValue(retrivalStrategy, holder)
        val cmp = comparison.compare(valueType, retrivalStrategy.getData(holder, key), comparedValue) ?: return false
        return cmp >= 0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }
}

class Lt(
    key: SqlTarget.Column,
    valueType: KClass<*>,
    value: Any,
    comparison: ComparisonStrategy
) : AbstractLeafMatcher(key, value, comparison, valueType) {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val comparedValue = retrieveComparedValue(retrivalStrategy, holder)
        val cmp = comparison.compare(valueType, retrivalStrategy.getData(holder, key), comparedValue) ?: return false
        return cmp <0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }
}

class Le(
    key: SqlTarget.Column,
    valueType: KClass<*>,
    value: Any,
    comparison: ComparisonStrategy
) : AbstractLeafMatcher(key, value, comparison, valueType) {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val comparedValue = retrieveComparedValue(retrivalStrategy, holder)
        val cmp = comparison.compare(valueType, retrivalStrategy.getData(holder, key), comparedValue) ?: return false
        return cmp <= 0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }
}

data class Like(
    override val key: SqlTarget.Column,
    val value: String
) : SqlKeyValueLeafMatcher {

    private val pattern = Pattern.compile(escapeSpecialRegexSymbols(value).replace("%", ".*"))

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val actualValue = retrivalStrategy.getData(holder, key)?.toString()
        return actualValue != null && pattern.matcher(actualValue).matches()
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return "$key LIKE '$value'"
    }

    companion object {

        val SPECIAL_SYMBOLS = setOf(
            "\\", ".", "[", "]", "{", "}", "(", ")", "<", ">", "*", "+", "-", "=", "?", "^", "$", "|"
        ).associateWith { "\\$it" }

        fun escapeSpecialRegexSymbols(s: String): String {
            return SPECIAL_SYMBOLS.entries.fold(s) { current, entry ->
                current.replace(entry.key, entry.value)
            }
        }
    }
}

data class In(
    override val key: SqlTarget.Column,
    val valueType: KClass<*>,
    val values: Set,
    val comparison: ComparisonStrategy
) : SqlKeyValueLeafMatcher {

    @Suppress("UNCHECKED_CAST")
    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val actualValue = retrivalStrategy.getData(holder, key)
        return values.any {
            comparison.compare(valueType as KClass, actualValue, it) == 0
        }
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return "$key IN (${values.joinToString()})"
    }
}

data class Between(
    override val key: SqlTarget.Column,
    val valueType: KClass<*>,
    val startValue: Any,
    val endValue: Any,
    val comparison: ComparisonStrategy
) : SqlKeyValueLeafMatcher {

    @Suppress("UNCHECKED_CAST")
    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val actualValue = retrivalStrategy.getData(holder, key) ?: return false

        val startCmp = comparison.compare(valueType as KClass, actualValue, startValue)
        if (startCmp == null || startCmp < 0) {
            return false
        }

        val endCmp = comparison.compare(valueType, actualValue, endValue)
        return endCmp != null && endCmp <= 0
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return "$key BETWEEN $startValue AND $endValue"
    }
}

data class IsNull(
    override val key: SqlTarget.Column
) : SqlKeyValueLeafMatcher {

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        val actualValue = retrivalStrategy.getData(holder, key)
        return actualValue == null
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return "$key IS NULL"
    }
}

data class Or(
    val _matchers: Collection
) : SqlKeyValueMatcher {

    private val matchers = _matchers.toTypedArray()

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        return matchers.any {
            it.matches(holder, retrivalStrategy)
        }
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return matchers.joinToString(prefix = "(", separator = ") or (", postfix = ")")
    }
}

data class And(
    val _matchers: Collection
) : SqlKeyValueMatcher {

    private val matchers = _matchers.toTypedArray()

    override fun  matches(
        holder: HOLDER,
        retrivalStrategy: DataProviderStrategy
    ): Boolean {
        return matchers.all {
            it.matches(holder, retrivalStrategy)
        }
    }

    override fun accept(visitor: SqlKeyValueVisitor) {
        visitor.visit(this)
    }

    override fun toString(): String {
        return matchers.joinToString(prefix = "(", separator = ") and (", postfix = ")")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy