This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a commit to branch unomi-1.6.x
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/unomi-1.6.x by this push:
     new 45fe9aa  UNOMI-523 : add date expression support to isDay / isNotDay 
property comparison (#359)
45fe9aa is described below

commit 45fe9aad4e8537d61dc67ec77f60eef4b09464fc
Author: David Griffon <[email protected]>
AuthorDate: Mon Nov 8 13:48:06 2021 +0100

    UNOMI-523 : add date expression support to isDay / isNotDay property 
comparison (#359)
    
    * UNOMI-523 : add date expression to isDay / isNotDay property comparison 
operator. (bonus, fix double property type support)
    
    * DMF-5016 : add support of date expression for multiple values
---
 .../org/apache/unomi/itests/ConditionBuilder.java  | 24 ++++++++++++
 .../apache/unomi/itests/ConditionEvaluatorIT.java  |  7 ++++
 .../PropertyConditionESQueryBuilder.java           | 26 ++++++++++++-
 .../conditions/PropertyConditionEvaluator.java     | 43 ++++++++++++++++++++--
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java 
b/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java
index 2d01f97..69a210f 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java
@@ -141,6 +141,10 @@ public class ConditionBuilder {
             return op("in").stringValues(values);
         }
 
+        public ComparisonCondition inDateExpr(String... values) {
+            return op("in").dateExprValues(values);
+        }
+
         public ComparisonCondition in(Date... values) {
             return op("in").dateValues(values);
         }
@@ -149,10 +153,18 @@ public class ConditionBuilder {
             return op("isDay").dateValue(value);
         }
 
+        public ComparisonCondition isDay(String expression) {
+            return op("isDay").dateValueExpr(expression);
+        }
+
         public ComparisonCondition isNotDay(Date value) {
             return op("isNotDay").dateValue(value);
         }
 
+        public ComparisonCondition isNotDay(String expression) {
+            return op("isNotDay").dateValueExpr(expression);
+        }
+
         public ComparisonCondition in(Integer... values) {
             return op("in").integerValues(values);
         }
@@ -221,6 +233,10 @@ public class ConditionBuilder {
             return op("notIn").dateValues(values);
         }
 
+        public ComparisonCondition notInDateExpr(String... values) {
+            return op("notIn").dateExprValues(values);
+        }
+
         public ComparisonCondition notIn(Integer... values) {
             return op("notIn").integerValues(values);
         }
@@ -262,6 +278,10 @@ public class ConditionBuilder {
             return parameter("propertyValueDate", value);
         }
 
+        private ComparisonCondition dateValueExpr(String value) {
+            return parameter("propertyValueDateExpr", value);
+        }
+
         private ComparisonCondition stringValues(String... values) {
             return parameter("propertyValues", values != null ? 
Arrays.asList(values) : null);
         }
@@ -277,6 +297,10 @@ public class ConditionBuilder {
         private ComparisonCondition dateValues(Date... values) {
             return parameter("propertyValuesDate", values != null ? 
Arrays.asList(values) : null);
         }
+
+        private ComparisonCondition dateExprValues(String... values) {
+            return parameter("propertyValuesDateExpr", values != null ? 
Arrays.asList(values) : null);
+        }
     }
 
     public class CompoundCondition extends ConditionItem {
diff --git 
a/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
index a1f93a6..749fc71 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
@@ -17,6 +17,7 @@
 
 package org.apache.unomi.itests;
 
+import org.apache.commons.lang3.time.DateUtils;
 import org.apache.unomi.api.Item;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.conditions.Condition;
@@ -32,6 +33,7 @@ import org.ops4j.pax.exam.util.Filter;
 
 import javax.inject.Inject;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 import static org.junit.Assert.*;
 
@@ -116,6 +118,11 @@ public class ConditionEvaluatorIT extends BaseIT {
 
         
assertTrue(eval(builder.profileProperty("properties.lastVisit").isDay(lastVisit).build()));
         
assertTrue(eval(builder.profileProperty("properties.lastVisit").isNotDay(new 
Date(lastVisit.getTime() + (24*60*60*1000))).build()));
+        long daysFromToday = 
TimeUnit.MILLISECONDS.toDays(DateUtils.truncate(new Date(), 
Calendar.DAY_OF_MONTH).getTime() - DateUtils.truncate(lastVisit, 
Calendar.DAY_OF_MONTH).getTime());
+        
assertTrue(eval(builder.profileProperty("properties.lastVisit").isDay("now-" + 
daysFromToday + "d").build()));
+        
assertTrue(eval(builder.profileProperty("properties.lastVisit").isNotDay("now-" 
+ (daysFromToday + 1) + "d").build()));
+        
assertTrue(eval(builder.profileProperty("properties.lastVisit").inDateExpr("" + 
lastVisit.getTime()).build()));
+        
assertTrue(eval(builder.profileProperty("properties.lastVisit").notInDateExpr("now-"
 + (daysFromToday + 1) + "d").build()));
     }
 
     @Test
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java
index e9a5dfb..994924d 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionESQueryBuilder.java
@@ -34,6 +34,8 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
+import static 
org.apache.unomi.plugins.baseplugin.conditions.PropertyConditionEvaluator.getDate;
+
 public class PropertyConditionESQueryBuilder implements 
ConditionESQueryBuilder {
 
     DateTimeFormatter dateTimeFormatter;
@@ -144,9 +146,31 @@ public class PropertyConditionESQueryBuilder implements 
ConditionESQueryBuilder
                 return boolQueryBuilder;
             case "isDay":
                 checkRequiredValue(value, name, comparisonOperator, false);
-                return getIsSameDayRange(value, name);
+                return getIsSameDayRange(getDate(value), name);
             case "isNotDay":
                 checkRequiredValue(value, name, comparisonOperator, false);
+                return 
QueryBuilders.boolQuery().mustNot(getIsSameDayRange(getDate(value), name));
+            case "distance":
+                final String unitString = (String) 
condition.getParameter("unit");
+                final Object centerObj = condition.getParameter("center");
+                final Double distance = (Double) 
condition.getParameter("distance");
+
+                if (centerObj != null && distance != null) {
+                    String centerString;
+                    if (centerObj instanceof org.apache.unomi.api.GeoPoint) {
+                        centerString = ((org.apache.unomi.api.GeoPoint) 
centerObj).asString();
+                    } else if (centerObj instanceof String) {
+                        centerString = (String) centerObj;
+                    } else {
+                        centerString = centerObj.toString();
+                    }
+                    DistanceUnit unit = unitString != null ? 
DistanceUnit.fromString(unitString) : DistanceUnit.DEFAULT;
+
+                    return QueryBuilders.geoDistanceQuery(name)
+                            .ignoreUnmapped(true)
+                            .distance(distance, unit)
+                            .point(new GeoPoint(centerString));
+                }
                 return 
QueryBuilders.boolQuery().mustNot(getIsSameDayRange(value, name));
         }
         return null;
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
index 5dfee9f..2ecd3b7 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
@@ -41,6 +41,7 @@ import java.lang.reflect.Modifier;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * Evaluator for property comparison conditions
@@ -68,7 +69,7 @@ public class PropertyConditionEvaluator implements 
ConditionEvaluator {
     }
 
     private int compare(Object actualValue, String expectedValue, Object 
expectedValueDate, Object expectedValueInteger, Object expectedValueDateExpr, 
Object expectedValueDouble) {
-        if (expectedValue == null && expectedValueDate == null && 
expectedValueInteger == null && getDate(expectedValueDateExpr) == null) {
+        if (expectedValue == null && expectedValueDate == null && 
expectedValueInteger == null && getDate(expectedValueDateExpr) == null && 
expectedValueDouble == null) {
             return actualValue == null ? 0 : 1;
         } else if (actualValue == null) {
             return -1;
@@ -87,8 +88,13 @@ public class PropertyConditionEvaluator implements 
ConditionEvaluator {
         }
     }
 
-    private boolean compareMultivalue(Object actualValue, List<?> 
expectedValues, List<?> expectedValuesDate, List<?> expectedValuesNumber, 
List<?> expectedValuesDateExpr, String op) {
+    private boolean compareValues(Object actualValue, Collection<?> 
expectedValues, Collection<?> expectedValuesInteger,  Collection<?> 
expectedValuesDouble,  Collection<?> expectedValuesDate, Collection<?> 
expectedValuesDateExpr, String op) {
+        Collection<Object> expectedDateExpr = null;
+        if (expectedValuesDateExpr != null) {
+            expectedDateExpr = 
expectedValuesDateExpr.stream().map(PropertyConditionEvaluator::getDate).collect(Collectors.toList());
+        }
         @SuppressWarnings("unchecked")
+        Collection<?> expected = ObjectUtils.firstNonNull(expectedValues, 
expectedValuesDate, expectedValuesInteger, expectedValuesDouble, 
expectedDateExpr);
         List<?> expected = ObjectUtils.firstNonNull(expectedValues, 
expectedValuesDate, expectedValuesNumber);
         if (actualValue == null) {
             return expected == null;
@@ -196,10 +202,17 @@ public class PropertyConditionEvaluator implements 
ConditionEvaluator {
             actualValue = ConditionContextHelper.foldToASCII((String) 
actualValue);
         }
 
+        return isMatch(op, actualValue, expectedValue, expectedValueInteger, 
expectedValueDouble, expectedValueDate,
+                expectedValueDateExpr, condition);
+    }
+
+    protected boolean isMatch(String op, Object actualValue, String 
expectedValue, Object expectedValueInteger, Object expectedValueDouble,
+                              Object expectedValueDate, Object 
expectedValueDateExpr, Condition condition) {
         if (op == null) {
             return false;
         } else if (actualValue == null) {
             return op.equals("missing");
+            return op.equals("missing") || op.equals("notIn") || 
op.equals("notEquals") || op.equals("hasNoneOf");
         } else if (op.equals("exists")) {
             return true;
         } else if (op.equals("equals")) {
@@ -252,11 +265,35 @@ public class PropertyConditionEvaluator implements 
ConditionEvaluator {
         } else if (op.equals("matchesRegex")) {
             return expectedValue != null && 
Pattern.compile(expectedValue).matcher(actualValue.toString()).matches();
         } else if (op.equals("in") || op.equals("inContains") || 
op.equals("notIn") || op.equals("hasSomeOf") || op.equals("hasNoneOf") || 
op.equals("all")) {
+            Collection<?> expectedValues = 
ConditionContextHelper.foldToASCII((Collection<?>) 
condition.getParameter("propertyValues"));
+            Collection<?> expectedValuesInteger = (Collection<?>) 
condition.getParameter("propertyValuesInteger");
+            Collection<?> expectedValuesDate = (Collection<?>) 
condition.getParameter("propertyValuesDate");
+            Collection<?> expectedValuesDateExpr = (Collection<?>) 
condition.getParameter("propertyValuesDateExpr");
+            Collection<?> expectedValuesDouble = (Collection<?>) 
condition.getParameter("propertyValuesDouble");
             List<?> expectedValues = 
ConditionContextHelper.foldToASCII((List<?>) 
condition.getParameter("propertyValues"));
             List<?> expectedValuesInteger = (List<?>) 
condition.getParameter("propertyValuesInteger");
             List<?> expectedValuesDate = (List<?>) 
condition.getParameter("propertyValuesDate");
             List<?> expectedValuesDateExpr = (List<?>) 
condition.getParameter("propertyValuesDateExpr");
 
+            return compareValues(actualValue, expectedValues, 
expectedValuesInteger, expectedValuesDouble, expectedValuesDate, 
expectedValuesDateExpr, op);
+        } else if (op.equals("isDay") && (expectedValueDate != null || 
expectedValueDateExpr != null)) {
+            Object expectedDate = expectedValueDate == null ? 
expectedValueDateExpr : expectedValueDate;
+            return 
yearMonthDayDateFormat.format(getDate(actualValue)).equals(yearMonthDayDateFormat.format(getDate(expectedDate)));
+        } else if (op.equals("isNotDay") && (expectedValueDate != null || 
expectedValueDateExpr != null)) {
+            Object expectedDate = expectedValueDate == null ? 
expectedValueDateExpr : expectedValueDate;
+            return 
!yearMonthDayDateFormat.format(getDate(actualValue)).equals(yearMonthDayDateFormat.format(getDate(expectedDate)));
+        } else if (op.equals("distance")) {
+            GeoPoint actualCenter = null;
+            if (actualValue instanceof GeoPoint) {
+                actualCenter = (GeoPoint) actualValue;
+            } else if (actualValue instanceof Map) {
+                actualCenter = GeoPoint.fromMap((Map<String, Double>) 
actualValue);
+            } else if (actualValue instanceof String) {
+                actualCenter = GeoPoint.fromString((String) actualValue);
+            }
+            if (actualCenter == null) {
+                return false;
+            }
             return compareMultivalue(actualValue, expectedValues, 
expectedValuesDate, expectedValuesInteger, expectedValuesDateExpr, op);
         } else if (op.equals("isDay") && expectedValueDate != null) {
             return 
yearMonthDayDateFormat.format(getDate(actualValue)).equals(yearMonthDayDateFormat.format(getDate(expectedValueDate)));
@@ -399,7 +436,7 @@ public class PropertyConditionEvaluator implements 
ConditionEvaluator {
         return accessor;
     }
 
-    private Date getDate(Object value) {
+    protected static Date getDate(Object value) {
         if (value == null) {
             return null;
         }

Reply via email to