-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make conditions work properly for every case (#8)
- Loading branch information
Showing
9 changed files
with
712 additions
and
413 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,84 +1,129 @@ | ||
package com.featurevisor.sdk | ||
|
||
import com.featurevisor.types.AttributeValue | ||
import com.featurevisor.types.Condition | ||
import com.featurevisor.types.Condition.And | ||
import com.featurevisor.types.Condition.Not | ||
import com.featurevisor.types.Condition.Or | ||
import com.featurevisor.types.Condition.Plain | ||
import com.featurevisor.types.ConditionValue | ||
import com.featurevisor.types.Context | ||
import com.featurevisor.types.Operator | ||
import com.featurevisor.types.PlainCondition | ||
import com.featurevisor.types.Operator.AFTER | ||
import com.featurevisor.types.Operator.BEFORE | ||
import com.featurevisor.types.Operator.CONTAINS | ||
import com.featurevisor.types.Operator.ENDS_WITH | ||
import com.featurevisor.types.Operator.EQUALS | ||
import com.featurevisor.types.Operator.GREATER_THAN | ||
import com.featurevisor.types.Operator.GREATER_THAN_OR_EQUAL | ||
import com.featurevisor.types.Operator.IN_ARRAY | ||
import com.featurevisor.types.Operator.LESS_THAN | ||
import com.featurevisor.types.Operator.LESS_THAN_OR_EQUAL | ||
import com.featurevisor.types.Operator.NOT_CONTAINS | ||
import com.featurevisor.types.Operator.NOT_EQUALS | ||
import com.featurevisor.types.Operator.NOT_IN_ARRAY | ||
import com.featurevisor.types.Operator.SEMVER_EQUALS | ||
import com.featurevisor.types.Operator.SEMVER_GREATER_THAN | ||
import com.featurevisor.types.Operator.SEMVER_GREATER_THAN_OR_EQUAL | ||
import com.featurevisor.types.Operator.SEMVER_LESS_THAN | ||
import com.featurevisor.types.Operator.SEMVER_LESS_THAN_OR_EQUAL | ||
import com.featurevisor.types.Operator.SEMVER_NOT_EQUALS | ||
import com.featurevisor.types.Operator.STARTS_WITH | ||
import net.swiftzer.semver.SemVer | ||
|
||
object Conditions { | ||
fun conditionIsMatched(condition: PlainCondition, context: Context): Boolean { | ||
val (attribute, operator, value) = condition | ||
fun conditionIsMatched(condition: Plain, context: Context): Boolean { | ||
val (attributeKey, operator, conditionValue) = condition | ||
val attributeValue = context.getOrDefault(attributeKey, null) ?: return false | ||
|
||
val contextValue = context[attribute] | ||
val conditionValue = value | ||
return when { | ||
attributeValue is AttributeValue.StringValue && conditionValue is ConditionValue.StringValue -> { | ||
when (operator) { | ||
EQUALS -> attributeValue.value == conditionValue.value | ||
NOT_EQUALS -> attributeValue.value != conditionValue.value | ||
CONTAINS -> attributeValue.value.contains(conditionValue.value) | ||
NOT_CONTAINS -> attributeValue.value.contains(conditionValue.value).not() | ||
STARTS_WITH -> attributeValue.value.startsWith(conditionValue.value) | ||
ENDS_WITH -> attributeValue.value.endsWith(conditionValue.value) | ||
SEMVER_EQUALS -> compareVersions(attributeValue.value, conditionValue.value) == 0 | ||
SEMVER_NOT_EQUALS -> compareVersions(attributeValue.value, conditionValue.value) != 0 | ||
SEMVER_GREATER_THAN -> compareVersions(attributeValue.value, conditionValue.value) == 1 | ||
SEMVER_GREATER_THAN_OR_EQUAL -> compareVersions(attributeValue.value, conditionValue.value) >= 0 | ||
SEMVER_LESS_THAN -> compareVersions(attributeValue.value, conditionValue.value) == -1 | ||
SEMVER_LESS_THAN_OR_EQUAL -> compareVersions(attributeValue.value, conditionValue.value) <= 0 | ||
else -> false | ||
} | ||
} | ||
|
||
// string | ||
if (contextValue is AttributeValue.StringValue) { | ||
// string / string | ||
if (conditionValue is ConditionValue.StringValue) { | ||
attributeValue is AttributeValue.IntValue && conditionValue is ConditionValue.IntValue -> { | ||
when (operator) { | ||
Operator.equals -> return contextValue.value == conditionValue.value | ||
Operator.notEquals -> return contextValue.value != conditionValue.value | ||
Operator.contains -> return contextValue.value.contains(conditionValue.value) | ||
Operator.notContains -> | ||
return !contextValue.value.contains(conditionValue.value) | ||
EQUALS -> attributeValue.value == conditionValue.value | ||
NOT_EQUALS -> attributeValue.value != conditionValue.value | ||
GREATER_THAN -> attributeValue.value > conditionValue.value | ||
GREATER_THAN_OR_EQUAL -> attributeValue.value >= conditionValue.value | ||
LESS_THAN -> attributeValue.value < conditionValue.value | ||
LESS_THAN_OR_EQUAL -> attributeValue.value <= conditionValue.value | ||
else -> false | ||
} | ||
} | ||
|
||
Operator.startsWith -> | ||
return contextValue.value.startsWith(conditionValue.value) | ||
attributeValue is AttributeValue.DoubleValue && conditionValue is ConditionValue.DoubleValue -> { | ||
when (operator) { | ||
EQUALS -> attributeValue.value == conditionValue.value | ||
NOT_EQUALS -> attributeValue.value != conditionValue.value | ||
GREATER_THAN -> attributeValue.value > conditionValue.value | ||
GREATER_THAN_OR_EQUAL -> attributeValue.value >= conditionValue.value | ||
LESS_THAN -> attributeValue.value < conditionValue.value | ||
LESS_THAN_OR_EQUAL -> attributeValue.value <= conditionValue.value | ||
else -> false | ||
} | ||
} | ||
|
||
Operator.endsWith -> return contextValue.value.endsWith(conditionValue.value) | ||
else -> return false | ||
attributeValue is AttributeValue.BooleanValue && conditionValue is ConditionValue.BooleanValue -> { | ||
when (operator) { | ||
EQUALS -> attributeValue.value == conditionValue.value | ||
NOT_EQUALS -> attributeValue.value != conditionValue.value | ||
else -> false | ||
} | ||
} | ||
|
||
// @TODO: string / array of strings for in/notIn operators | ||
attributeValue is AttributeValue.StringValue && conditionValue is ConditionValue.ArrayValue -> { | ||
when (operator) { | ||
IN_ARRAY -> attributeValue.value in conditionValue.values | ||
NOT_IN_ARRAY -> (attributeValue.value in conditionValue.values).not() | ||
else -> false | ||
} | ||
} | ||
|
||
// @TODO: handle semvers | ||
attributeValue is AttributeValue.DateValue && conditionValue is ConditionValue.DateTimeValue -> { | ||
when (operator) { | ||
EQUALS -> attributeValue.value == conditionValue.value | ||
BEFORE -> attributeValue.value < conditionValue.value | ||
AFTER -> attributeValue.value > conditionValue.value | ||
else -> false | ||
} | ||
} | ||
|
||
return false | ||
else -> false | ||
} | ||
} | ||
|
||
// int | ||
if (contextValue is AttributeValue.IntValue && value is ConditionValue.IntValue) { | ||
// int / int | ||
when (operator) { | ||
Operator.equals -> return contextValue.value == value.value | ||
Operator.notEquals -> return contextValue.value != value.value | ||
Operator.greaterThan -> return contextValue.value > value.value | ||
Operator.greaterThanOrEquals -> return contextValue.value >= value.value | ||
Operator.lessThan -> return contextValue.value < value.value | ||
Operator.lessThanOrEquals -> return contextValue.value <= value.value | ||
else -> return false | ||
} | ||
} | ||
fun allConditionsAreMatched(condition: Condition, context: Context): Boolean = | ||
when (condition) { | ||
is Plain -> conditionIsMatched(condition, context) | ||
|
||
// double | ||
if (contextValue is AttributeValue.DoubleValue && value is ConditionValue.DoubleValue) { | ||
// double / double | ||
when (operator) { | ||
Operator.equals -> return contextValue.value == value.value | ||
Operator.notEquals -> return contextValue.value != value.value | ||
Operator.greaterThan -> return contextValue.value > value.value | ||
Operator.greaterThanOrEquals -> return contextValue.value >= value.value | ||
Operator.lessThan -> return contextValue.value < value.value | ||
Operator.lessThanOrEquals -> return contextValue.value <= value.value | ||
else -> return false | ||
is And -> condition.and.all { | ||
allConditionsAreMatched(it, context) | ||
} | ||
} | ||
|
||
// boolean | ||
if (contextValue is AttributeValue.BooleanValue && value is ConditionValue.BooleanValue) { | ||
// boolean / boolean | ||
when (operator) { | ||
Operator.equals -> return contextValue.value == value.value | ||
Operator.notEquals -> return contextValue.value != value.value | ||
else -> return false | ||
is Or -> condition.or.any { | ||
allConditionsAreMatched(it, context) | ||
} | ||
} | ||
|
||
// @TODO: handle dates | ||
is Not -> condition.not.all { | ||
allConditionsAreMatched(it, context) | ||
}.not() | ||
} | ||
|
||
return false | ||
} | ||
private fun compareVersions(actual: String, condition: String): Int = | ||
SemVer.parse(actual).compareTo(SemVer.parse(condition)) | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.