fix(server): handle repeated range predicates correctly (#3122)
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
index 063d23a..097e98d 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
@@ -629,12 +629,18 @@
         /*
          * NOTE: seems need to keep call checkRangeIndex() for each condition,
          * so don't break early even if test() return false.
-         */
+        */
         boolean valid = true;
+        Map<Id, Boolean> rangeIndexMatches = null;
+        if (this.element2IndexValueMap != null) {
+            rangeIndexMatches = new HashMap<>();
+        }
         for (Condition cond : this.conditions) {
             valid &= cond.test(element);
-            valid &= this.element2IndexValueMap == null ||
-                     this.element2IndexValueMap.checkRangeIndex(element, cond);
+            if (this.element2IndexValueMap != null) {
+                valid &= this.element2IndexValueMap.checkRangeIndex(
+                         element, cond, rangeIndexMatches);
+            }
         }
         return valid;
     }
@@ -859,7 +865,8 @@
             this.leftIndexMap.remove(elementId);
         }
 
-        public boolean checkRangeIndex(HugeElement element, Condition cond) {
+        public boolean checkRangeIndex(HugeElement element, Condition cond,
+                                       Map<Id, Boolean> rangeIndexMatches) {
             // Not UserpropRelation
             if (!(cond instanceof Condition.UserpropRelation)) {
                 return true;
@@ -875,11 +882,16 @@
                 return true;
             }
 
+            if (rangeIndexMatches.containsKey(propId)) {
+                return rangeIndexMatches.get(propId);
+            }
+
             HugeProperty<Object> property = element.getProperty(propId);
             if (property == null) {
                 // Property value has been deleted, so it's not matched
                 this.addLeftIndex(element.id(), propId, fieldValues);
-                return false;
+                return this.cacheRangeIndexMatch(rangeIndexMatches, propId,
+                                                 false);
             }
 
             /*
@@ -900,10 +912,19 @@
              * the element is valid or not.
              */
             if (this.selectedIndexField != null) {
-                return !propId.equals(this.selectedIndexField) || hasRightValue;
+                hasRightValue = !propId.equals(this.selectedIndexField) ||
+                                hasRightValue;
             }
 
-            return hasRightValue;
+            return this.cacheRangeIndexMatch(rangeIndexMatches, propId,
+                                             hasRightValue);
+        }
+
+        private boolean cacheRangeIndexMatch(Map<Id, Boolean> rangeIndexMatches,
+                                             Id propertyId,
+                                             boolean matched) {
+            rangeIndexMatches.put(propertyId, matched);
+            return matched;
         }
 
         private static boolean removeFieldValue(Set<Object> values,
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
index f74c5c1..cbb2b7d 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
@@ -4792,6 +4792,38 @@
     }
 
     @Test
+    public void testQueryByRepeatedRangePredicates() {
+        HugeGraph graph = graph();
+        SchemaManager schema = graph.schema();
+
+        schema.indexLabel("transferByTimestamp").onE("transfer").range()
+              .by("timestamp").create();
+
+        Vertex source = graph.addVertex(T.label, "person", "name", "source",
+                                        "city", "Beijing", "age", 20);
+        Vertex target = graph.addVertex(T.label, "person", "name", "target",
+                                        "city", "Beijing", "age", 21);
+        source.addEdge("transfer", target, "id", 1, "amount", 1.0F,
+                       "timestamp", -4L, "message", "test");
+        graph.tx().commit();
+
+        List<Edge> edges = graph.traversal().E()
+                                .has("timestamp", -4L)
+                                .has("timestamp", P.lte(4L)).toList();
+        Assert.assertEquals(1, edges.size());
+
+        long count = graph.traversal().E()
+                          .has("timestamp", -4L)
+                          .has("timestamp", P.lte(4L)).count().next();
+        Assert.assertEquals(1L, count);
+
+        count = graph.traversal().E()
+                     .has("timestamp", P.lte(4L))
+                     .has("timestamp", -4L).count().next();
+        Assert.assertEquals(1L, count);
+    }
+
+    @Test
     public void testQueryByNegativeFloatProperty() {
         HugeGraph graph = graph();
         SchemaManager schema = graph.schema();