Skip to content

Implement operation interfaces, because KMP can't generate correct code for iOS #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/src/commonMain/kotlin/JsonLogicEngine.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import evaluation.CommonLogicEvaluator
import evaluation.LogicOperations
import operation.FunctionalLogicOperation
import operation.StandardLogicOperation
import operations.In
import operations.Log
import operations.array.Filter
Expand Down
11 changes: 6 additions & 5 deletions core/src/commonMain/kotlin/evaluation/CommonLogicEvaluator.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package evaluation

import LogicEvaluator
import JsonLogicException
import LogicEvaluator
import operation.StandardLogicOperation
import utils.asList

internal class CommonLogicEvaluator(private val operations: LogicOperations) : LogicEvaluator {
Expand All @@ -21,16 +22,16 @@ internal class CommonLogicEvaluator(private val operations: LogicOperations) : L
val operator = logic.keys.firstOrNull()
val values = logic[operator]
return if (operations.functionalOperations.keys.contains(operator)) {
operations.functionalOperations[operator]?.invoke(values.asList, data, this)
operations.functionalOperations[operator]?.evaluateLogic(values.asList, data, this)
} else {
operations.standardOperations.getOperation(operator).invoke(when (values) {
operations.standardOperations.getOperation(operator).evaluateLogic(when (values) {
is List<*> -> values.map { executeExpression(it, data) }
is Map<*, *> -> executeExpression(values, data)
else -> executeExpression(listOf(values), data)
}.asList, data)
}.asList,data)
}
}

private fun Map<String, (Any?, Any?) -> Any?>.getOperation(operator: Any?) =
private fun Map<String, StandardLogicOperation>.getOperation(operator: Any?) =
get(operator) ?: throw JsonLogicException("Operation $operator not found.")
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/evaluation/LogicOperations.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package evaluation

import FunctionalLogicOperation
import StandardLogicOperation
import operation.FunctionalLogicOperation
import operation.StandardLogicOperation

internal data class LogicOperations(
val standardOperations: Map<String, StandardLogicOperation> = emptyMap(),
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/In.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package operations

import StandardLogicOperation
import operation.StandardLogicOperation
import utils.asList
import utils.secondOrNull

internal object In : StandardLogicOperation {
override fun invoke(expression: Any?, data: Any?): Boolean {
override fun evaluateLogic(expression: Any?, data: Any?): Boolean? {
val first = expression.asList.firstOrNull()
return when (val second = expression.asList.secondOrNull()) {
is String -> second.contains(first.toString())
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/Log.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package operations

import StandardLogicOperation
import operation.StandardLogicOperation
import utils.asList

internal class Log(private val logger: ((Any?) -> Unit)? = null) : StandardLogicOperation {
override fun invoke(expression: Any?, data: Any?): Any? {
override fun evaluateLogic(expression: Any?, data: Any?): Any? {
val loggedValue = expression.asList.firstOrNull()
logger?.let { log -> log(loggedValue) }
return loggedValue
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/Filter.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package operations.array

import LogicEvaluator
import FunctionalLogicOperation
import operation.FunctionalLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import kotlin.collections.Map

internal object Filter : FunctionalLogicOperation, NoInitialValueOperation, TruthyUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
invokeArrayOperation(expression, data, evaluator, ::filterOrEmptyList)

private fun filterOrEmptyList(
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/Map.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package operations.array

import LogicEvaluator
import FunctionalLogicOperation
import operation.FunctionalLogicOperation
import kotlin.collections.Map

internal object Map : FunctionalLogicOperation, NoInitialValueOperation {
override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
invokeArrayOperation(expression, data, evaluator, ::mapOrEmptyList)

private fun mapOrEmptyList(
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/Merge.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package operations.array

import StandardLogicOperation
import operation.StandardLogicOperation
import utils.asList

internal object Merge : StandardLogicOperation {
override fun invoke(expression: Any?, data: Any?): Any = expression.asList.mergeOrAdd()
override fun evaluateLogic(expression: Any?, data: Any?): Any = expression.asList.mergeOrAdd()

private fun List<Any?>.mergeOrAdd(): List<Any?> = flatMap {
when (it) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/Reduce.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package operations.array

import LogicEvaluator
import FunctionalLogicOperation
import operation.FunctionalLogicOperation
import utils.asList
import utils.thirdOrNull
import kotlin.collections.Map
Expand All @@ -10,7 +10,7 @@ internal object Reduce : FunctionalLogicOperation, ArrayOperation {
private const val CURRENT_DATA_KEY = "current"
private const val ACCUMULATOR_DATA_KEY = "accumulator"

override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
expression.asList.let { expressionValues ->
val input = createOperationInput(expressionValues, data, evaluator)
val initialValue = expressionValues.thirdOrNull()
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/occurence/All.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package operations.array.occurence

import LogicEvaluator
import FunctionalLogicOperation
import operation.FunctionalLogicOperation

internal object All : FunctionalLogicOperation, OccurrenceCheckOperation {
override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
checkOccurrence(expression, data, evaluator)

override fun check(
Expand Down
5 changes: 2 additions & 3 deletions core/src/commonMain/kotlin/operations/array/occurence/None.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package operations.array.occurence

import LogicEvaluator
import FunctionalLogicOperation
import kotlin.collections.Map
import operation.FunctionalLogicOperation

internal object None : FunctionalLogicOperation, OccurrenceCheckOperation {
override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
checkOccurrence(expression, data, evaluator)

override fun getOperationDefault(mappingOperation: Map<String, Any>?, expressionValues: List<Any?>) = true
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/array/occurence/Some.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package operations.array.occurence

import LogicEvaluator
import FunctionalLogicOperation
import operation.FunctionalLogicOperation

internal object Some : FunctionalLogicOperation, OccurrenceCheckOperation {
override fun invoke(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
override fun evaluateLogic(expression: Any?, data: Any?, evaluator: LogicEvaluator): Any? =
checkOccurrence(expression, data, evaluator)

override fun check(
Expand Down
6 changes: 3 additions & 3 deletions core/src/commonMain/kotlin/operations/data/Missing.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package operations.data

import StandardLogicOperation
import operation.StandardLogicOperation

internal object Missing : StandardLogicOperation {
override fun invoke(expression: Any?, data: Any?): List<Any?> {
override fun evaluateLogic(expression: Any?, data: Any?): List<Any?> {
return (expression as? List<Any?>)?.mapNotNull {
it.takeIf { Var(it, data).isNullOrEmptyString() }
it.takeIf { Var.evaluateLogic(it, data).isNullOrEmptyString() }
}.orEmpty()
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/commonMain/kotlin/operations/data/MissingSome.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package operations.data

import StandardLogicOperation
import operation.StandardLogicOperation
import utils.longOrZero
import utils.secondOrNull

internal object MissingSome : StandardLogicOperation {
override fun invoke(expression: Any?, data: Any?): Any {
override fun evaluateLogic(expression: Any?, data: Any?): Any {
val min = (expression as? List<Any?>?)?.firstOrNull()?.toString()?.longOrZero ?: 0
val keys = ((expression as? List<Any?>?)?.secondOrNull() as? List<Any?>).orEmpty()
val missing = Missing(keys, data)
val missing = Missing.evaluateLogic(keys, data)
return missing.takeIf { keys.size - missing.size < min }.orEmpty()
}
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/data/Var.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package operations.data

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.data.unwrap.ValueFetchingUnwrapStrategy
import utils.intOrZero
import utils.secondOrNull

internal object Var : StandardLogicOperation, ValueFetchingUnwrapStrategy {
override operator fun invoke(expression: Any?, data: Any?): Any? =
override fun evaluateLogic(expression: Any?, data: Any?): Any? =
unwrapDataKeys(expression)?.fetchValueOrDefault(expression, data)

private fun List<String>.fetchValueOrDefault(expression: Any?, data: Any?): Any? {
Expand Down
5 changes: 2 additions & 3 deletions core/src/commonMain/kotlin/operations/logic/And.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import utils.asList

internal object And : StandardLogicOperation, TruthyUnwrapStrategy {

override fun invoke(expression: Any?, data: Any?) = with(expression.asList) {
override fun evaluateLogic(expression: Any?, data: Any?) = with(expression.asList) {
if (all { it is Boolean }) {
all { unwrapValueAsBoolean(it) }
} else {
Expand Down
7 changes: 5 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/DoubleNegation.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import utils.asList

internal object DoubleNegation : StandardLogicOperation, TruthyUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?): Boolean = unwrapValueAsBoolean(expression.asList.firstOrNull())
override fun evaluateLogic(
expression: Any?,
data: Any?
): Boolean = unwrapValueAsBoolean(expression.asList.firstOrNull())
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/Equals.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation

internal object Equals : StandardLogicOperation, EqualsOperation {
override fun invoke(
override fun evaluateLogic(
expression: Any?,
data: Any?
): Boolean = compare(expression) { first, second -> first == second }
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/If.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import utils.asList
import utils.secondOrNull
import utils.thirdOrNull

@Suppress("MagicNumber")
internal object If : StandardLogicOperation, TruthyUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?): Any? = expression.asList.recursiveIf()
override fun evaluateLogic(expression: Any?, data: Any?): Any? = expression.asList.recursiveIf()

private fun List<Any?>.recursiveIf(): Any? = when (size) {
0 -> null
Expand Down
7 changes: 5 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/Negation.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import utils.asList

internal object Negation : StandardLogicOperation, TruthyUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?): Boolean = !unwrapValueAsBoolean(expression.asList.firstOrNull())
override fun evaluateLogic(
expression: Any?,
data: Any?
): Boolean = !unwrapValueAsBoolean(expression.asList.firstOrNull())
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/NotEquals.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation

internal object NotEquals : StandardLogicOperation, EqualsOperation {
override fun invoke(
override fun evaluateLogic(
expression: Any?,
data: Any?
): Boolean = !compare(expression) { first, second -> first == second }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation

internal object NotStrictEquals : StandardLogicOperation, StrictEqualsOperation {
override fun invoke(expression: Any?, data: Any?): Boolean =
override fun evaluateLogic(expression: Any?, data: Any?): Boolean =
!compare(expression) { first, second -> first == second }
}

4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/logic/Or.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.logic.unwrap.TruthyUnwrapStrategy
import utils.asList

internal object Or : StandardLogicOperation, TruthyUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?) = with(expression.asList) {
override fun evaluateLogic(expression: Any?, data: Any?) = with(expression.asList) {
if (all { it is Boolean }) {
firstOrNull { unwrapValueAsBoolean(it) } != null
} else {
Expand Down
8 changes: 3 additions & 5 deletions core/src/commonMain/kotlin/operations/logic/StrictEquals.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package operations.logic

import StandardLogicOperation
import operation.StandardLogicOperation

internal object StrictEquals : StandardLogicOperation, StrictEqualsOperation {
override fun invoke(
expression: Any?,
data: Any?
): Boolean = compare(expression) { first, second -> first == second }
override fun evaluateLogic(expression: Any?, data: Any?): Boolean =
compare(expression) { first, second -> first == second }
}


8 changes: 5 additions & 3 deletions core/src/commonMain/kotlin/operations/numeric/Addition.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package operations.numeric

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.numeric.unwrap.StrictUnwrapStrategy

internal object Addition : StandardLogicOperation, DoubleTypeSensitiveOperation, StrictUnwrapStrategy {

override fun invoke(expression: Any?, data: Any?): Any? = doubleResultOrNull(unwrapValue(expression)) { it.sum() }
override fun evaluateLogic(
expression: Any?,
data: Any?
): Any? = doubleResultOrNull(unwrapValue(expression)) { it.sum() }
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/numeric/Division.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package operations.numeric

import StandardLogicOperation
import operation.StandardLogicOperation
import operations.numeric.unwrap.LenientUnwrapStrategy

internal object Division : StandardLogicOperation, LenientUnwrapStrategy {
override fun invoke(expression: Any?, data: Any?) =
override fun evaluateLogic(expression: Any?, data: Any?) =
unwrapValueAsDouble(expression).takeIf { it.size >= 2 }?.let {
val second = it[1]
val first = it.first()
Expand Down
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/numeric/Max.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package operations.numeric

import StandardLogicOperation
import operation.StandardLogicOperation

internal object Max : StandardLogicOperation, DoubleTypeSensitiveOperation {
override fun invoke(expression: Any?, data: Any?): Any? = doubleResultOrNull(expression) { it.maxOrNull() }
override fun evaluateLogic(expression: Any?, data: Any?): Any? = doubleResultOrNull(expression) { it.maxOrNull() }
}
4 changes: 2 additions & 2 deletions core/src/commonMain/kotlin/operations/numeric/Min.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package operations.numeric

import StandardLogicOperation
import operation.StandardLogicOperation

internal object Min : StandardLogicOperation, DoubleTypeSensitiveOperation {
override fun invoke(expression: Any?, data: Any?): Any? = doubleResultOrNull(expression) { it.minOrNull() }
override fun evaluateLogic(expression: Any?, data: Any?): Any? = doubleResultOrNull(expression) { it.minOrNull() }
}
Loading