From 480472d01290846d90dacbb3848fdce944359867 Mon Sep 17 00:00:00 2001 From: "rummaan.ahmad" Date: Fri, 31 May 2024 13:36:36 +0530 Subject: [PATCH] Case Insensitive check feature added for multiple operator stages --- EvaluableExpression.go | 8 +++- evaluationStage.go | 88 +++++++++++++++++++++++++----------------- stagePlanner.go | 6 +-- 3 files changed, 63 insertions(+), 39 deletions(-) diff --git a/EvaluableExpression.go b/EvaluableExpression.go index a5fe50d..54ca897 100644 --- a/EvaluableExpression.go +++ b/EvaluableExpression.go @@ -35,6 +35,12 @@ type EvaluableExpression struct { tokens []ExpressionToken evaluationStages *evaluationStage inputExpression string + + /* + This flag will be used to set the case sensitivity of the expression. + If set to true, the expression will be evaluated using case insensitive comparison. + */ + CaseInsensitive bool } /* @@ -229,7 +235,7 @@ func (this EvaluableExpression) evaluateStage(stage *evaluationStage, parameters } } - return stage.operator(left, right, parameters) + return stage.operator(left, right, parameters, this.CaseInsensitive) } func typeCheck(check stageTypeCheck, value interface{}, symbol OperatorSymbol, format string) error { diff --git a/evaluationStage.go b/evaluationStage.go index 11ea587..701b0be 100644 --- a/evaluationStage.go +++ b/evaluationStage.go @@ -17,7 +17,7 @@ const ( prefixErrorFormat string = "Value '%v' cannot be used with the prefix '%v'" ) -type evaluationOperator func(left interface{}, right interface{}, parameters Parameters) (interface{}, error) +type evaluationOperator func(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) type stageTypeCheck func(value interface{}) bool type stageCombinedTypeCheck func(left interface{}, right interface{}) bool @@ -82,11 +82,11 @@ func (this *evaluationStage) isShortCircuitable() bool { return false } -func noopStageRight(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func noopStageRight(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return right, nil } -func addStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func addStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { // string concat if either are strings if isString(left) || isString(right) { @@ -95,80 +95,98 @@ func addStage(left interface{}, right interface{}, parameters Parameters) (inter return left.(float64) + right.(float64), nil } -func subtractStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func subtractStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return left.(float64) - right.(float64), nil } -func multiplyStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func multiplyStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return left.(float64) * right.(float64), nil } -func divideStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func divideStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return left.(float64) / right.(float64), nil } -func exponentStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func exponentStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return math.Pow(left.(float64), right.(float64)), nil } -func modulusStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func modulusStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return math.Mod(left.(float64), right.(float64)), nil } -func gteStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func gteStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if isString(left) && isString(right) { + if caseInsensitive { + return boolIface(strings.ToLower(left.(string)) >= strings.ToLower(right.(string))), nil + } return boolIface(left.(string) >= right.(string)), nil } return boolIface(left.(float64) >= right.(float64)), nil } -func gtStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func gtStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if isString(left) && isString(right) { + if caseInsensitive { + return boolIface(strings.ToLower(left.(string)) > strings.ToLower(right.(string))), nil + } return boolIface(left.(string) > right.(string)), nil } return boolIface(left.(float64) > right.(float64)), nil } -func lteStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func lteStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if isString(left) && isString(right) { + if caseInsensitive { + return boolIface(strings.ToLower(left.(string)) <= strings.ToLower(right.(string))), nil + } return boolIface(left.(string) <= right.(string)), nil } return boolIface(left.(float64) <= right.(float64)), nil } -func ltStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func ltStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if isString(left) && isString(right) { + if caseInsensitive { + return boolIface(strings.ToLower(left.(string)) < strings.ToLower(right.(string))), nil + } return boolIface(left.(string) < right.(string)), nil } return boolIface(left.(float64) < right.(float64)), nil } -func equalStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func equalStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { + if caseInsensitive && isString(left) && isString(right) { + return boolIface(strings.EqualFold(left.(string), right.(string))), nil + } return boolIface(reflect.DeepEqual(left, right)), nil } -func notEqualStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func notEqualStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { + if caseInsensitive && isString(left) && isString(right) { + return boolIface(!strings.EqualFold(left.(string), right.(string))), nil + } return boolIface(!reflect.DeepEqual(left, right)), nil } -func andStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func andStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return boolIface(left.(bool) && right.(bool)), nil } -func orStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func orStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return boolIface(left.(bool) || right.(bool)), nil } -func negateStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func negateStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return -right.(float64), nil } -func invertStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func invertStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return boolIface(!right.(bool)), nil } -func bitwiseNotStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func bitwiseNotStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(^int64(right.(float64))), nil } -func ternaryIfStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func ternaryIfStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if left.(bool) { return right, nil } return nil, nil } -func ternaryElseStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func ternaryElseStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if left != nil { return left, nil } return right, nil } -func regexStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func regexStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { var pattern *regexp.Regexp var err error @@ -186,9 +204,9 @@ func regexStage(left interface{}, right interface{}, parameters Parameters) (int return pattern.Match([]byte(left.(string))), nil } -func notRegexStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func notRegexStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { - ret, err := regexStage(left, right, parameters) + ret, err := regexStage(left, right, parameters, caseInsensitive) if err != nil { return nil, err } @@ -196,25 +214,25 @@ func notRegexStage(left interface{}, right interface{}, parameters Parameters) ( return !(ret.(bool)), nil } -func bitwiseOrStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func bitwiseOrStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(int64(left.(float64)) | int64(right.(float64))), nil } -func bitwiseAndStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func bitwiseAndStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(int64(left.(float64)) & int64(right.(float64))), nil } -func bitwiseXORStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func bitwiseXORStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(int64(left.(float64)) ^ int64(right.(float64))), nil } -func leftShiftStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func leftShiftStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(uint64(left.(float64)) << uint64(right.(float64))), nil } -func rightShiftStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func rightShiftStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return float64(uint64(left.(float64)) >> uint64(right.(float64))), nil } func makeParameterStage(parameterName string) evaluationOperator { - return func(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { + return func(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { value, err := parameters.Get(parameterName) if err != nil { return nil, err @@ -225,14 +243,14 @@ func makeParameterStage(parameterName string) evaluationOperator { } func makeLiteralStage(literal interface{}) evaluationOperator { - return func(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { + return func(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { return literal, nil } } func makeFunctionStage(function ExpressionFunction) evaluationOperator { - return func(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { + return func(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { if right == nil { return function() @@ -293,7 +311,7 @@ func makeAccessorStage(pair []string) evaluationOperator { reconstructed := strings.Join(pair, ".") - return func(left interface{}, right interface{}, parameters Parameters) (ret interface{}, err error) { + return func(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (ret interface{}, err error) { var params []reflect.Value @@ -404,7 +422,7 @@ func makeAccessorStage(pair []string) evaluationOperator { } } -func separatorStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func separatorStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { var ret []interface{} @@ -418,7 +436,7 @@ func separatorStage(left interface{}, right interface{}, parameters Parameters) return ret, nil } -func inStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { +func inStage(left interface{}, right interface{}, parameters Parameters, caseInsensitive bool) (interface{}, error) { for _, value := range right.([]interface{}) { if left == value { diff --git a/stagePlanner.go b/stagePlanner.go index d71ed12..8430a10 100644 --- a/stagePlanner.go +++ b/stagePlanner.go @@ -686,12 +686,12 @@ func elideStage(root *evaluationStage) *evaluationStage { // both sides are values, get their actual values. // errors should be near-impossible here. If we encounter them, just abort this optimization. - leftValue, err = root.leftStage.operator(nil, nil, nil) + leftValue, err = root.leftStage.operator(nil, nil, nil, false) if err != nil { return root } - rightValue, err = root.rightStage.operator(nil, nil, nil) + rightValue, err = root.rightStage.operator(nil, nil, nil, false) if err != nil { return root } @@ -712,7 +712,7 @@ func elideStage(root *evaluationStage) *evaluationStage { } // pre-calculate, and return a new stage representing the result. - result, err = root.operator(leftValue, rightValue, nil) + result, err = root.operator(leftValue, rightValue, nil, false) if err != nil { return root }