Skip to content

Commit

Permalink
Rebase 3.1.x main (#388)
Browse files Browse the repository at this point in the history
* adds DATE_TIME and DURATION data types (#381)
---------
Co-authored-by: vlejeune <vincent.lejeune@savoye.com>

* new development version 3.1.0-SNAPSHOT

* adds handling of null values (#367)
---------
Co-authored-by: Kayla White <kayla.white@ida-analytics.de>

* fixes integration errors, formatting, code smells and branch build (#384)
---------

Co-authored-by: Vincent Lejeune <vinchou11@gmail.com>
Co-authored-by: vlejeune <vincent.lejeune@savoye.com>
Co-authored-by: Rene Greuel <41747375+ida-greuelr@users.noreply.github.com>
  • Loading branch information
4 people authored Jun 8, 2023
1 parent 574efc2 commit 483df4a
Show file tree
Hide file tree
Showing 33 changed files with 1,221 additions and 107 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ name: Build

on:
push:
branches: [ "main" ]
branches: [ "main", "3.0.x", "3.1.x" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "3.0.x", "3.1.x" ]

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ target/

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/.sdkmanrc
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ strings.

## Key Features:

- Supports numerical, boolean, string, array and structure expressions, operations and variables.
- Supports numerical, boolean, string, date time, duration, array and structure expressions, operations and variables.
- Array and structure support: Arrays and structures can be mixed, building arbitrary data
structures.
- Uses BigDecimal for numerical calculations.
Expand Down
30 changes: 30 additions & 0 deletions docs/concepts/datatypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ EvalEx supports the following data types:
| NUMBER | java.math.BigDecimal |
| BOOLEAN | java.lang.Boolean |
| STRING | java.lang.String |
| DATE_TIME | java.time.Instant |
| DURATION | java.time.Duration |
| ARRAY | java.util.List |
| STRUCTURE | java.util.Map |
| EXPRESSION_NODE | com.ezylang.evalex.parser.ASTNode |
| NULL | null |

Data is stored in an _EvaluationValue_, which holds the value and the data type.

Expand Down Expand Up @@ -61,6 +64,16 @@ Any instance of _java.lang.CharSequence_ or _java.lang.Character_ will automatic
a _STRING_ datatype. Conversion will be done by invoking the _toString()_ method on the input
object.

### DATE_TIME

Any instance of _java.time.LocalDate_, _java.time.LocalDateTime_, _java.time.ZoneDateTime_ or _java.time.OffsetDateTime_ will automatically be converted to
a _DATE_TIME_ datatype. Conversion will be done by using the current time zone id on the input
object.

### DURATION

Duration are stored as a _java.time.Duration_. The duration values are useful for calculations with _DATE_TIME_ values.

### ARRAY

Arrays are stored internally as a _java.util.List&lt;EvaluationValue&gt;_. When passed as a
Expand Down Expand Up @@ -194,3 +207,20 @@ System.out.println(result); // prints 14
Note that the above expression is not evaluated as "2 * 4 + 3", which would result in 11.
Instead, the sub-expression "4 + 3" is calculated first, when it comes to finding the value of the
variable _b_. Resulting in calculation of "2 * 7", which is 14.

### NULL

A representation for _null_ objects.

This allows the handling of nulls inside the expression itself (for example using the _IF()_ function),
in case it can not be guaranteed that the passed variable values are not null before passing them.

```java
Expression expression = new Expression("if(name == null, "unknown", name)");

EvaluationValue result = expression
.with("name", null)
.evaluate();

System.out.println(result); // prints unknown
```
8 changes: 8 additions & 0 deletions docs/concepts/parsing_evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ Another option to have EvalEx use your data is to define a custom data accessor.

See chapter [Data Access](../customization/data_access.html) for details.

### Null value Handling

Operations and Functions that can not handle null will throw either a _NullPointerException_
or an _EvaluationException_ when encountering null.

When passing null as variable values is a possibility the expression should be written to handle null
itself, for example using the _IF()_ function.

### Exception Handling

In EvalEx, there are two general exceptions:
Expand Down
1 change: 1 addition & 0 deletions docs/references/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ Available through the _ExpressionConfiguration.StandardConstants_ constant:
| FALSE | Boolean.FALSE |
| PI | 3.14159265358979323846264338327950288419716939937510582097... |
| E | 2.71828182845904523536028747135266249775724709369995957496... |
| NULL | null |


13 changes: 13 additions & 0 deletions docs/references/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,16 @@ Available through the _ExpressionConfiguration.StandardFunctionsDictionary_ cons
| TANH(value) | Returns the hyperbolic tangent of a value |
| TANR(value) | Returns the tangent of an angle (in radians) |

### DateTime Functions

| Name | Description |
|---------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| DT_DATE_TIME(year, month, day [, hour, minute, second, nano]) | Returns the corresponding date time value |
| DT_PARSE(value [, format]) | Converts the given string value to a date time value by using the optional format. Without a format, the [ISO_LOCAL_DATE_TIME ](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME), [ISO_LOCAL_DATE](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME) or [ISO_INSTANT](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_INSTANT)(for more details on the format, see [JDK DateTimeFormatted documentation](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) |
| DT_ZONED_PARSE(value [, format]) | Converts the given string zoned date time value to a date time type by using the optional format. Without a format, the [ISO representation is used](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME) (for more details on the format, see [JDK DateTimeFormatted documentation](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) |
| DT_FORMAT(value, [, format]) | Converts the given date time value to a string value by using the optional format. Without a format, the [ISO representation is used](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME). (for more details on the format, see [JDK DateTimeFormatted documentation](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) |
| DT_EPOCH(value) | Converts the given value to epoch timestamp in millisecond |
| DT_DATE_TIME_EPOCH(value) | Converts the given epoch timestamp value to a date time value |
| DT_DURATION_MILLIS(value) | Converts the given value in millisecond to a duration value |
| DT_DURATION_DAYS(value) | Converts the given days quantity to a duration value |
| DT_DURATION_PARSE(value) | Converts the given duration representation to a duration value (see [JDK Duration#parse documentation](https://docs.oracle.com/javase/11/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-) |
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.ezylang</groupId>
<artifactId>EvalEx</artifactId>
<version>3.0.6-SNAPSHOT</version>
<version>3.1.0-SNAPSHOT</version>

<name>EvalEx</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,78 +19,19 @@
import com.ezylang.evalex.data.EvaluationValue;
import com.ezylang.evalex.data.MapBasedDataAccessor;
import com.ezylang.evalex.functions.FunctionIfc;
import com.ezylang.evalex.functions.basic.AbsFunction;
import com.ezylang.evalex.functions.basic.CeilingFunction;
import com.ezylang.evalex.functions.basic.FactFunction;
import com.ezylang.evalex.functions.basic.FloorFunction;
import com.ezylang.evalex.functions.basic.IfFunction;
import com.ezylang.evalex.functions.basic.Log10Function;
import com.ezylang.evalex.functions.basic.LogFunction;
import com.ezylang.evalex.functions.basic.MaxFunction;
import com.ezylang.evalex.functions.basic.MinFunction;
import com.ezylang.evalex.functions.basic.NotFunction;
import com.ezylang.evalex.functions.basic.RandomFunction;
import com.ezylang.evalex.functions.basic.RoundFunction;
import com.ezylang.evalex.functions.basic.SqrtFunction;
import com.ezylang.evalex.functions.basic.SumFunction;
import com.ezylang.evalex.functions.basic.*;
import com.ezylang.evalex.functions.datetime.*;
import com.ezylang.evalex.functions.string.StringContains;
import com.ezylang.evalex.functions.string.StringLowerFunction;
import com.ezylang.evalex.functions.string.StringUpperFunction;
import com.ezylang.evalex.functions.trigonometric.AcosFunction;
import com.ezylang.evalex.functions.trigonometric.AcosHFunction;
import com.ezylang.evalex.functions.trigonometric.AcosRFunction;
import com.ezylang.evalex.functions.trigonometric.AcotFunction;
import com.ezylang.evalex.functions.trigonometric.AcotHFunction;
import com.ezylang.evalex.functions.trigonometric.AcotRFunction;
import com.ezylang.evalex.functions.trigonometric.AsinFunction;
import com.ezylang.evalex.functions.trigonometric.AsinHFunction;
import com.ezylang.evalex.functions.trigonometric.AsinRFunction;
import com.ezylang.evalex.functions.trigonometric.Atan2Function;
import com.ezylang.evalex.functions.trigonometric.Atan2RFunction;
import com.ezylang.evalex.functions.trigonometric.AtanFunction;
import com.ezylang.evalex.functions.trigonometric.AtanHFunction;
import com.ezylang.evalex.functions.trigonometric.AtanRFunction;
import com.ezylang.evalex.functions.trigonometric.CosFunction;
import com.ezylang.evalex.functions.trigonometric.CosHFunction;
import com.ezylang.evalex.functions.trigonometric.CosRFunction;
import com.ezylang.evalex.functions.trigonometric.CotFunction;
import com.ezylang.evalex.functions.trigonometric.CotHFunction;
import com.ezylang.evalex.functions.trigonometric.CotRFunction;
import com.ezylang.evalex.functions.trigonometric.CscFunction;
import com.ezylang.evalex.functions.trigonometric.CscHFunction;
import com.ezylang.evalex.functions.trigonometric.CscRFunction;
import com.ezylang.evalex.functions.trigonometric.DegFunction;
import com.ezylang.evalex.functions.trigonometric.RadFunction;
import com.ezylang.evalex.functions.trigonometric.SecFunction;
import com.ezylang.evalex.functions.trigonometric.SecHFunction;
import com.ezylang.evalex.functions.trigonometric.SecRFunction;
import com.ezylang.evalex.functions.trigonometric.SinFunction;
import com.ezylang.evalex.functions.trigonometric.SinHFunction;
import com.ezylang.evalex.functions.trigonometric.SinRFunction;
import com.ezylang.evalex.functions.trigonometric.TanFunction;
import com.ezylang.evalex.functions.trigonometric.TanHFunction;
import com.ezylang.evalex.functions.trigonometric.TanRFunction;
import com.ezylang.evalex.functions.trigonometric.*;
import com.ezylang.evalex.operators.OperatorIfc;
import com.ezylang.evalex.operators.arithmetic.InfixDivisionOperator;
import com.ezylang.evalex.operators.arithmetic.InfixMinusOperator;
import com.ezylang.evalex.operators.arithmetic.InfixModuloOperator;
import com.ezylang.evalex.operators.arithmetic.InfixMultiplicationOperator;
import com.ezylang.evalex.operators.arithmetic.InfixPlusOperator;
import com.ezylang.evalex.operators.arithmetic.InfixPowerOfOperator;
import com.ezylang.evalex.operators.arithmetic.PrefixMinusOperator;
import com.ezylang.evalex.operators.arithmetic.PrefixPlusOperator;
import com.ezylang.evalex.operators.booleans.InfixAndOperator;
import com.ezylang.evalex.operators.booleans.InfixEqualsOperator;
import com.ezylang.evalex.operators.booleans.InfixGreaterEqualsOperator;
import com.ezylang.evalex.operators.booleans.InfixGreaterOperator;
import com.ezylang.evalex.operators.booleans.InfixLessEqualsOperator;
import com.ezylang.evalex.operators.booleans.InfixLessOperator;
import com.ezylang.evalex.operators.booleans.InfixNotEqualsOperator;
import com.ezylang.evalex.operators.booleans.InfixOrOperator;
import com.ezylang.evalex.operators.booleans.PrefixNotOperator;
import com.ezylang.evalex.operators.arithmetic.*;
import com.ezylang.evalex.operators.booleans.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
Expand Down Expand Up @@ -120,7 +61,7 @@
* Map.entry("update", new UpdateFunction()));
* </pre>
*/
@Builder
@Builder(toBuilder = true)
public class ExpressionConfiguration {

/** The standard set constants for EvalEx. */
Expand Down Expand Up @@ -221,7 +162,17 @@ public class ExpressionConfiguration {
// string functions
Map.entry("STR_CONTAINS", new StringContains()),
Map.entry("STR_LOWER", new StringLowerFunction()),
Map.entry("STR_UPPER", new StringUpperFunction()));
Map.entry("STR_UPPER", new StringUpperFunction()),
// date time functions
Map.entry("DT_DATE_TIME", new DateTimeFunction()),
Map.entry("DT_PARSE", new DateTimeParseFunction()),
Map.entry("DT_ZONED_PARSE", new ZonedDateTimeParseFunction()),
Map.entry("DT_FORMAT", new DateTimeFormatFunction()),
Map.entry("DT_EPOCH", new DateTimeToEpochFunction()),
Map.entry("DT_DATE_TIME_EPOCH", new DateTimeFromEpochFunction()),
Map.entry("DT_DURATION_MILLIS", new DurationFromMillisFunction()),
Map.entry("DT_DURATION_DAYS", new DurationFromDaysFunction()),
Map.entry("DT_DURATION_PARSE", new DurationParseFunction()));

/** The math context to use. */
@Builder.Default @Getter private final MathContext mathContext = DEFAULT_MATH_CONTEXT;
Expand Down Expand Up @@ -276,6 +227,8 @@ public class ExpressionConfiguration {
*/
@Builder.Default @Getter private final boolean allowOverwriteConstants = true;

/** Set the default zone id. By default, the system default zone id is used. */
@Builder.Default @Getter private final ZoneId defaultZoneId = ZoneId.systemDefault();
/**
* Convenience method to create a default configuration.
*
Expand Down Expand Up @@ -347,6 +300,7 @@ private static Map<String, EvaluationValue> getStandardConstants() {
new EvaluationValue(
new BigDecimal(
"2.71828182845904523536028747135266249775724709369995957496696762772407663")));
constants.put("NULL", new EvaluationValue(null));

return constants;
}
Expand Down
Loading

0 comments on commit 483df4a

Please sign in to comment.