Skip to content
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

Add new function SWITCH #469

Merged
merged 2 commits into from
May 5, 2024
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
37 changes: 19 additions & 18 deletions docs/references/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,25 @@ Available through the _ExpressionConfiguration.StandardFunctionsDictionary_ cons

### Basic Functions

| Name | Description |
|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
| ABS(value) | Absolute (non-negative) value |
| AVERAGE(value, ...) | Returns the average (arithmetic mean) of all parameters. |
| CEILING(value) | Rounds the given value an integer using the rounding mode CEILING |
| COALESCE(value, ...) | Returns the first non-null parameter, or NULL if all parameters are null |
| FACT(base) | Calculates the factorial of a base value |
| FLOOR(value) | Rounds the given value an integer using the rounding mode FLOOR |
| IF(condition, resultIfTrue, resultIfFalse) | Conditional evaluation function. If _condition_ is true, the _resultIfTrue_ is returned, else the _resultIfFalse_ value |
| LOG(value) | The natural logarithm (base e) of a value |
| LOG10(value) | The base 10 logarithm of a value |
| MAX(value, ...) | Returns the maximum value of all parameters. If a parameter is of type _ARRAY_, the maximum of all elements is calculated. |
| MIN(value, ...) | Returns the minimum value of all parameters. If a parameter is of type _ARRAY_, the minimum of all elements is calculated. |
| NOT(value) | Boolean negation, implemented as a function (for compatibility) |
| RANDOM() | Produces a random value between 0 and 1 |
| ROUND(value, scale) | Rounds the given value to the specified scale, using the current rounding mode |
| SQRT(value) | Square root function |
| SUM(value, ...) | Returns the sum of all parameters. If a parameter is of type _ARRAY_, the sum of all elements is calculated. |
| Name | Description |
|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| ABS(value) | Absolute (non-negative) value |
| AVERAGE(value, ...) | Returns the average (arithmetic mean) of all parameters. |
| CEILING(value) | Rounds the given value an integer using the rounding mode CEILING |
| COALESCE(value, ...) | Returns the first non-null parameter, or NULL if all parameters are null |
| FACT(base) | Calculates the factorial of a base value |
| FLOOR(value) | Rounds the given value an integer using the rounding mode FLOOR |
| IF(condition, resultIfTrue, resultIfFalse) | Conditional evaluation function. If _condition_ is true, the _resultIfTrue_ is returned, else the _resultIfFalse_ value |
| LOG(value) | The natural logarithm (base e) of a value |
| LOG10(value) | The base 10 logarithm of a value |
| MAX(value, ...) | Returns the maximum value of all parameters. If a parameter is of type _ARRAY_, the maximum of all elements is calculated. |
| MIN(value, ...) | Returns the minimum value of all parameters. If a parameter is of type _ARRAY_, the minimum of all elements is calculated. |
| NOT(value) | Boolean negation, implemented as a function (for compatibility) |
| RANDOM() | Produces a random value between 0 and 1 |
| ROUND(value, scale) | Rounds the given value to the specified scale, using the current rounding mode |
| SQRT(value) | Square root function |
| SUM(value, ...) | Returns the sum of all parameters. If a parameter is of type _ARRAY_, the sum of all elements is calculated. |
| SWITCH(expression, value1, result1, [value2-N, result2-N ...], [default]) | Returns the _result_ correponding to the first matching _value_ in the specified _expression_ or an optional _default_ value if no match found. |

### String Functions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ public class ExpressionConfiguration {
Map.entry("NOT", new NotFunction()),
Map.entry("RANDOM", new RandomFunction()),
Map.entry("ROUND", new RoundFunction()),
Map.entry("SUM", new SumFunction()),
Map.entry("SQRT", new SqrtFunction()),
Map.entry("SUM", new SumFunction()),
Map.entry("SWITCH", new SwitchFunction()),
// trigonometric
Map.entry("ACOS", new AcosFunction()),
Map.entry("ACOSH", new AcosHFunction()),
Expand Down
101 changes: 101 additions & 0 deletions src/main/java/com/ezylang/evalex/functions/basic/SwitchFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
Copyright 2012-2024 Udo Klimaschewski

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.ezylang.evalex.functions.basic;

import com.ezylang.evalex.EvaluationException;
import com.ezylang.evalex.Expression;
import com.ezylang.evalex.data.EvaluationValue;
import com.ezylang.evalex.functions.AbstractFunction;
import com.ezylang.evalex.functions.FunctionParameter;
import com.ezylang.evalex.parser.Token;

/**
* A function that evaluates one value (or expression) against a list of values, and returns the
* result corresponding to the first matching value. If there is no match, an optional default value
* may be returned.
*
* <p><strong>Syntax:</strong>
*
* <blockquote>
*
* {@code SWITCH(expression, value1, result1, [value, result, ...], [default])}
*
* </blockquote>
*
* <p><strong>Examples:</strong>
*
* <p>1. The following function will return either "Sunday", "Monday", or "Tuesday", depending on
* the result of the variable {@code weekday}. Since no default value was specified, the function
* will return a null value if there is no match:
*
* <blockquote>
*
* {@code SWITCH(weekday, 1, "Sunday", 2, "Monday", 3, "Tuesday")}
*
* </blockquote>
*
* <p>2. The following function will return either "Sunday", "Monday", "Tuesday", or "No match",
* depending on the result of the variable {@code weekday}:
*
* <blockquote>
*
* {@code SWITCH(weekday, 1, "Sunday", 2, "Monday", 3, "Tuesday", "No match")}
*
* </blockquote>
*
* @author oswaldo.bapvic.jr
*/
@FunctionParameter(name = "expression")
@FunctionParameter(name = "value1")
@FunctionParameter(name = "result1", isLazy = true)
@FunctionParameter(name = "additionalValues", isLazy = true, isVarArg = true)
public class SwitchFunction extends AbstractFunction {
@Override
public EvaluationValue evaluate(
Expression expression, Token functionToken, EvaluationValue... parameterValues)
throws EvaluationException {

EvaluationValue result = EvaluationValue.nullValue();

// First get the first parameter
EvaluationValue value = parameterValues[0];

// Iterate through the parameters to parse the pairs of value-result and the default result if
// present.
int index = 1;
while (index < parameterValues.length) {
int next = index + 1;
if (next < parameterValues.length) {
if (value.equals(evaluateParameter(expression, parameterValues[index]))) {
result = parameterValues[next];
break;
}
index += 2;
} else {
// The default result
result = parameterValues[index++];
}
}
return evaluateParameter(expression, result);
}

private EvaluationValue evaluateParameter(Expression expression, EvaluationValue parameter)
throws EvaluationException {
return parameter.isExpressionNode()
? expression.evaluateSubtree(parameter.getExpressionNode())
: parameter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ void testIf(String expression, String expectedResult) throws EvaluationException
assertExpressionHasExpectedResult(expression, expectedResult);
}

@ParameterizedTest
@CsvSource(
delimiter = ':',
value = {
"SWITCH(1, 1, \"one\", 2, \"two\") : one",
"SWITCH(1+1, 1, \"one\", 2, \"two\") : two",
"SWITCH(9 , 1, \"one\", 2, \"two\") : ",
"SWITCH(9-8, 1, \"one\", 2, \"two\", \"n/a\") : one",
"SWITCH(2, 1, \"one\", 2, \"two\", \"n/a\") : two",
"SWITCH(\"a\", 1, \"one\", 2, \"two\", \"n/a\") : n/a",
"SWITCH(true, true, \"Y\", \"N\") : Y",
"SWITCH(false, true, \"Y\", \"N\") : N",
"SWITCH(0, true, \"Y\", \"N\") : N",
"SWITCH(null, 5, 50, 90) : 90",
"SWITCH(null, null, 50, 90) : 50",
// The following divisions by zero are not supposed to occur due to lazy parameters
"SWITCH(\"BR\", \"BR\", \"result\"+123, \"DE\", 3/0, 2/0) : result123",
"SWITCH(\"DE\", \"BR\", 3/0, \"DE\", \"result\"+\"ABC\", 2/0) : resultABC",
"SWITCH(1000+900+10, 1909+1, \"OK\", 10/0, \"impossible\") : OK"
})
void testSwitch(String expression, String expectedResult)
throws EvaluationException, ParseException {
assertExpressionHasExpectedResult(expression, expectedResult);
}

@ParameterizedTest
@CsvSource(
delimiter = ':',
Expand Down
Loading