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

imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph.git


The following commit(s) were added to refs/heads/master by this push:
     new e108076ac fix(server): normalize bool range predicates in gremlin 
filters (#2991)
e108076ac is described below

commit e108076aca60c06735fc1b315a4dd6c15f7562c1
Author: contrueCT <[email protected]>
AuthorDate: Sat May 9 15:23:52 2026 +0800

    fix(server): normalize bool range predicates in gremlin filters (#2991)
---
 .../apache/hugegraph/backend/query/Condition.java  |  16 ++-
 .../backend/query/ConditionQueryFlatten.java       |  45 +++++-
 .../traversal/optimize/TraversalUtil.java          |  43 +++++-
 .../org/apache/hugegraph/core/EdgeCoreTest.java    | 159 +++++++++++++++++++++
 .../org/apache/hugegraph/core/VertexCoreTest.java  |  81 +++++++++++
 .../unit/core/ConditionQueryFlattenTest.java       | 122 ++++++++++++++++
 .../apache/hugegraph/unit/core/ConditionTest.java  |  32 +++++
 .../java/org/apache/hugegraph/query/Condition.java |  16 ++-
 .../org/apache/hugegraph/query/ConditionTest.java  |  56 ++++++++
 9 files changed, 555 insertions(+), 15 deletions(-)

diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
index 09e223e4c..8d9ecd433 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
@@ -195,7 +195,7 @@ public abstract class Condition {
          *
          * @param first  is actual value, might be Number/Date or String, It is
          *               probably that the `first` is serialized to String.
-         * @param second is value in query condition, must be Number/Date
+         * @param second is value in query condition, must be 
Number/Date/Boolean
          * @return the value 0 if first is numerically equal to second;
          * a value less than 0 if first is numerically less than
          * second; and a value greater than 0 if first is
@@ -208,6 +208,8 @@ public abstract class Condition {
                                                  (Number) second);
             } else if (second instanceof Date) {
                 return compareDate(first, (Date) second);
+            } else if (second instanceof Boolean) {
+                return compareBoolean(first, (Boolean) second);
             }
 
             throw new IllegalArgumentException(String.format(
@@ -230,6 +232,18 @@ public abstract class Condition {
                     second, second.getClass().getSimpleName()));
         }
 
+        private static int compareBoolean(Object first, Boolean second) {
+            if (first instanceof Boolean) {
+                return Boolean.compare((Boolean) first, second);
+            }
+
+            throw new IllegalArgumentException(String.format(
+                    "Can't compare between %s(%s) and %s(%s)",
+                    first, first == null ? null :
+                           first.getClass().getSimpleName(),
+                    second, second.getClass().getSimpleName()));
+        }
+
         private void checkBaseType(Object value, Class<?> clazz) {
             if (!clazz.isInstance(value)) {
                 String valueClass = value == null ? "null" :
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
index 83af41b00..649f88e7b 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
@@ -115,12 +115,23 @@ public final class ConditionQueryFlatten {
                 }
             case AND:
                 Condition.And and = (Condition.And) condition;
-                return new Condition.And(flattenIn(and.left(), supportIn),
-                                         flattenIn(and.right(), supportIn));
+                Condition andLeft = flattenIn(and.left(), supportIn);
+                Condition andRight = flattenIn(and.right(), supportIn);
+                if (andLeft == null || andRight == null) {
+                    return null;
+                }
+                return new Condition.And(andLeft, andRight);
             case OR:
                 Condition.Or or = (Condition.Or) condition;
-                return new Condition.Or(flattenIn(or.left(), supportIn),
-                                        flattenIn(or.right(), supportIn));
+                Condition orLeft = flattenIn(or.left(), supportIn);
+                Condition orRight = flattenIn(or.right(), supportIn);
+                if (orLeft == null) {
+                    return orRight;
+                }
+                if (orRight == null) {
+                    return orLeft;
+                }
+                return new Condition.Or(orLeft, orRight);
             default:
                 throw new AssertionError(String.format("Wrong condition type: 
'%s'",
                                                        condition.type()));
@@ -427,9 +438,26 @@ public final class ConditionQueryFlatten {
         if (low == null || high == null) {
             return true;
         }
-        return compare(low, high) < 0 || compare(low, high) == 0 &&
-                                         low.relation() == 
Condition.RelationType.GTE &&
-                                         high.relation() == 
Condition.RelationType.LTE;
+        int compared = compare(low, high);
+        if (compared > 0) {
+            return false;
+        }
+        if (compared == 0) {
+            return low.relation() == Condition.RelationType.GTE &&
+                   high.relation() == Condition.RelationType.LTE;
+        }
+        return !emptyBooleanRange(low, high);
+    }
+
+    private static boolean emptyBooleanRange(Relation low, Relation high) {
+        if (!(low.value() instanceof Boolean) ||
+            !(high.value() instanceof Boolean)) {
+            return false;
+        }
+        return Boolean.FALSE.equals(low.value()) &&
+               Boolean.TRUE.equals(high.value()) &&
+               low.relation() == Condition.RelationType.GT &&
+               high.relation() == Condition.RelationType.LT;
     }
 
     private static boolean validEq(Relation eq, Relation low, Relation high) {
@@ -507,6 +535,9 @@ public final class ConditionQueryFlatten {
             return NumericUtil.compareNumber(firstValue, (Number) secondValue);
         } else if (firstValue instanceof Date && secondValue instanceof Date) {
             return ((Date) firstValue).compareTo((Date) secondValue);
+        } else if (firstValue instanceof Boolean &&
+                   secondValue instanceof Boolean) {
+            return Boolean.compare((Boolean) firstValue, (Boolean) 
secondValue);
         } else {
             throw new IllegalArgumentException(String.format("Can't compare 
between %s and %s",
                                                              first, second));
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
index 11a5c0cee..142c95620 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
@@ -46,6 +46,7 @@ import org.apache.hugegraph.schema.SchemaLabel;
 import org.apache.hugegraph.structure.HugeElement;
 import org.apache.hugegraph.structure.HugeProperty;
 import org.apache.hugegraph.type.HugeType;
+import org.apache.hugegraph.type.define.DataType;
 import org.apache.hugegraph.type.define.Directions;
 import org.apache.hugegraph.type.define.HugeKeys;
 import org.apache.hugegraph.util.CollectionUtil;
@@ -419,9 +420,9 @@ public final class TraversalUtil {
         return cond;
     }
 
-    private static Condition.Relation convCompare2Relation(HugeGraph graph,
-                                                           HugeType type,
-                                                           HasContainer has) {
+    private static Condition convCompare2Relation(HugeGraph graph,
+                                                  HugeType type,
+                                                  HasContainer has) {
         assert type.isGraph();
         BiPredicate<?, ?> bp = has.getPredicate().getBiPredicate();
         assert bp instanceof Compare;
@@ -459,9 +460,9 @@ public final class TraversalUtil {
         }
     }
 
-    private static Condition.Relation convCompare2UserpropRelation(HugeGraph 
graph,
-                                                                   HugeType 
type,
-                                                                   
HasContainer has) {
+    private static Condition convCompare2UserpropRelation(HugeGraph graph,
+                                                          HugeType type,
+                                                          HasContainer has) {
         BiPredicate<?, ?> bp = has.getPredicate().getBiPredicate();
         assert bp instanceof Compare;
 
@@ -469,6 +470,11 @@ public final class TraversalUtil {
         PropertyKey pkey = graph.propertyKey(key);
         Id pkeyId = pkey.id();
         Object value = validPropertyValue(has.getValue(), pkey);
+        if (pkey.dataType() == DataType.BOOLEAN &&
+            value instanceof Boolean) {
+            return convCompare2BooleanUserpropRelation((Compare) bp, pkeyId,
+                                                       (Boolean) value);
+        }
 
         switch ((Compare) bp) {
             case eq:
@@ -488,6 +494,31 @@ public final class TraversalUtil {
         }
     }
 
+    private static Condition convCompare2BooleanUserpropRelation(Compare 
compare,
+                                                                 Id key,
+                                                                 Boolean 
value) {
+        switch (compare) {
+            case eq:
+                return Condition.eq(key, value);
+            case neq:
+                return Condition.eq(key, !value);
+            case gt:
+                return value ? Condition.in(key, ImmutableList.of()) :
+                       Condition.eq(key, true);
+            case gte:
+                return value ? Condition.eq(key, true) :
+                       Condition.in(key, ImmutableList.of(false, true));
+            case lt:
+                return value ? Condition.eq(key, false) :
+                       Condition.in(key, ImmutableList.of());
+            case lte:
+                return value ? Condition.in(key, ImmutableList.of(false, 
true)) :
+                       Condition.eq(key, false);
+            default:
+                throw new AssertionError(compare);
+        }
+    }
+
     private static Condition convRelationType2Relation(HugeGraph graph,
                                                        HugeType type,
                                                        HasContainer has) {
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 6bec6dc06..74aa483e4 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
@@ -7140,6 +7140,165 @@ public class EdgeCoreTest extends BaseCoreTest {
         Assert.assertEquals(1, (int) el.get(0).value("id"));
     }
 
+    @Test
+    public void testQueryEdgeByBooleanRangePredicate() {
+        HugeGraph graph = graph();
+        initStrikeIndex();
+        graph.schema().indexLabel("strikeByArrested").onE("strike").secondary()
+             .by("arrested").create();
+
+        Vertex louise = graph.addVertex(T.label, "person", "name", "Louise",
+                                        "city", "Beijing", "age", 21);
+        Vertex sean = graph.addVertex(T.label, "person", "name", "Sean",
+                                      "city", "Beijing", "age", 23);
+        long current = System.currentTimeMillis();
+        louise.addEdge("strike", sean, "id", 1,
+                       "timestamp", current, "place", "park",
+                       "tool", "shovel", "reason", "jeer",
+                       "arrested", false);
+        louise.addEdge("strike", sean, "id", 2,
+                       "timestamp", current + 1, "place", "street",
+                       "tool", "shovel", "reason", "jeer",
+                       "arrested", true);
+
+        List<Edge> hasLtEdges = graph.traversal().E()
+                                     .has("arrested", P.lt(true))
+                                     .toList();
+        Assert.assertEquals(1, hasLtEdges.size());
+        Assert.assertEquals(1, (int) hasLtEdges.get(0).value("id"));
+
+        List<Edge> whereEdges = graph.traversal().E()
+                                     .where(__.has("arrested", P.lt(true)))
+                                     .toList();
+        Assert.assertEquals(1, whereEdges.size());
+        Assert.assertEquals(1, (int) whereEdges.get(0).value("id"));
+
+        List<Edge> matchEdges = graph.traversal().E()
+                                     .match(__.as("start")
+                                              .where(__.has("arrested",
+                                                            P.lt(true)))
+                                              .as("matched"))
+                                     .<Edge>select("matched")
+                                     .toList();
+        Assert.assertEquals(1, matchEdges.size());
+        Assert.assertEquals(1, (int) matchEdges.get(0).value("id"));
+
+        List<Edge> hasNeqTrueEdges = graph.traversal().E()
+                                          .has("arrested", P.neq(true))
+                                          .toList();
+        Assert.assertEquals(1, hasNeqTrueEdges.size());
+        Assert.assertEquals(1, (int) hasNeqTrueEdges.get(0).value("id"));
+
+        List<Edge> hasNeqFalseEdges = graph.traversal().E()
+                                           .has("arrested", P.neq(false))
+                                           .toList();
+        Assert.assertEquals(1, hasNeqFalseEdges.size());
+        Assert.assertEquals(2, (int) hasNeqFalseEdges.get(0).value("id"));
+
+        List<Edge> hasLteFalseEdges = graph.traversal().E()
+                                           .has("arrested", P.lte(false))
+                                           .toList();
+        Assert.assertEquals(1, hasLteFalseEdges.size());
+        Assert.assertEquals(1, (int) hasLteFalseEdges.get(0).value("id"));
+
+        List<Edge> hasGtFalseEdges = graph.traversal().E()
+                                          .has("arrested", P.gt(false))
+                                          .toList();
+        Assert.assertEquals(1, hasGtFalseEdges.size());
+        Assert.assertEquals(2, (int) hasGtFalseEdges.get(0).value("id"));
+
+        List<Edge> hasGteTrueEdges = graph.traversal().E()
+                                           .has("arrested", P.gte(true))
+                                           .toList();
+        Assert.assertEquals(1, hasGteTrueEdges.size());
+        Assert.assertEquals(2, (int) hasGteTrueEdges.get(0).value("id"));
+
+        List<Edge> hasGteFalseEdges = graph.traversal().E()
+                                            .has("arrested", P.gte(false))
+                                            .toList();
+        Assert.assertEquals(2, hasGteFalseEdges.size());
+        Set<Integer> gteFalseIds = new HashSet<>();
+        for (Edge edge : hasGteFalseEdges) {
+            gteFalseIds.add(edge.value("id"));
+        }
+        Assert.assertEquals(ImmutableSet.of(1, 2), gteFalseIds);
+
+        List<Edge> hasLteTrueEdges = graph.traversal().E()
+                                           .has("arrested", P.lte(true))
+                                           .toList();
+        Assert.assertEquals(2, hasLteTrueEdges.size());
+        Set<Integer> lteTrueIds = new HashSet<>();
+        for (Edge edge : hasLteTrueEdges) {
+            lteTrueIds.add(edge.value("id"));
+        }
+        Assert.assertEquals(ImmutableSet.of(1, 2), lteTrueIds);
+
+        Assert.assertEquals(0, graph.traversal().E()
+                                    .has("arrested", P.lt(false))
+                                    .toList().size());
+        Assert.assertEquals(0, graph.traversal().E()
+                                    .has("arrested", P.gt(true))
+                                    .toList().size());
+    }
+
+    @Test
+    public void testQueryEdgeByBooleanRangePredicateWithoutNullableProperty() {
+        HugeGraph graph = graph();
+        initStrikeIndex();
+        graph.schema().indexLabel("strikeByHurt").onE("strike").secondary()
+             .by("hurt").create();
+
+        Vertex louise = graph.addVertex(T.label, "person", "name", "Louise",
+                                        "city", "Beijing", "age", 21);
+        Vertex sean = graph.addVertex(T.label, "person", "name", "Sean",
+                                      "city", "Beijing", "age", 23);
+        long current = System.currentTimeMillis();
+        louise.addEdge("strike", sean, "id", 1,
+                       "timestamp", current, "place", "park",
+                       "tool", "shovel", "reason", "jeer",
+                       "hurt", false, "arrested", false);
+        louise.addEdge("strike", sean, "id", 2,
+                       "timestamp", current + 1, "place", "street",
+                       "tool", "shovel", "reason", "jeer",
+                       "hurt", true, "arrested", true);
+        louise.addEdge("strike", sean, "id", 3,
+                       "timestamp", current + 2, "place", "mall",
+                       "tool", "shovel", "reason", "jeer",
+                       "arrested", false);
+
+        List<Edge> gteFalseEdges = graph.traversal().E()
+                                        .has("hurt", P.gte(false))
+                                        .toList();
+        Assert.assertEquals(2, gteFalseEdges.size());
+        Set<Integer> gteFalseIds = new HashSet<>();
+        for (Edge edge : gteFalseEdges) {
+            gteFalseIds.add(edge.value("id"));
+        }
+        Assert.assertEquals(ImmutableSet.of(1, 2), gteFalseIds);
+
+        List<Edge> lteTrueEdges = graph.traversal().E()
+                                        .has("hurt", P.lte(true))
+                                        .toList();
+        Assert.assertEquals(2, lteTrueEdges.size());
+        Set<Integer> lteTrueIds = new HashSet<>();
+        for (Edge edge : lteTrueEdges) {
+            lteTrueIds.add(edge.value("id"));
+        }
+        Assert.assertEquals(ImmutableSet.of(1, 2), lteTrueIds);
+
+        List<Edge> lteFalseEdges = graph.traversal().E()
+                                         .has("hurt", P.lte(false))
+                                         .toList();
+        Assert.assertEquals(1, lteFalseEdges.size());
+        Assert.assertEquals(1, (int) lteFalseEdges.get(0).value("id"));
+
+        List<Edge> neqTrueEdges = graph.traversal().E()
+                                       .has("hurt", P.neq(true))
+                                       .toList();
+        Assert.assertEquals(1, neqTrueEdges.size());
+        Assert.assertEquals(1, (int) neqTrueEdges.get(0).value("id"));
+    }
+
     @Test
     public void testQueryEdgeByPage() {
         Assume.assumeTrue("Not support paging",
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
index a329de3af..c56db9f2b 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
@@ -6470,6 +6470,87 @@ public class VertexCoreTest extends BaseCoreTest {
         Assert.assertEquals("", vertex.value("city"));
     }
 
+    @Test
+    public void testQueryVertexByBooleanPredicate() {
+        HugeGraph graph = graph();
+        Assume.assumeFalse("skip this test for hstore",
+                           Objects.equals("hstore", graph.backend()));
+
+        graph.schema().indexLabel("languageByDynamic").onV("language")
+             .secondary().by("dynamic").create();
+
+        graph.addVertex(T.label, "language", "name", "java",
+                        "dynamic", true);
+        graph.addVertex(T.label, "language", "name", "rust",
+                        "dynamic", false);
+        graph.addVertex(T.label, "language", "name", "c");
+        this.commitTx();
+
+        List<Vertex> neqTrueVertices = graph.traversal().V()
+                                             .hasLabel("language")
+                                             .has("dynamic", P.neq(true))
+                                             .toList();
+        Assert.assertEquals(1, neqTrueVertices.size());
+        Assert.assertEquals("rust", neqTrueVertices.get(0).value("name"));
+
+        List<Vertex> neqFalseVertices = graph.traversal().V()
+                                               .hasLabel("language")
+                                               .has("dynamic", P.neq(false))
+                                               .toList();
+        Assert.assertEquals(1, neqFalseVertices.size());
+        Assert.assertEquals("java", neqFalseVertices.get(0).value("name"));
+
+        List<Vertex> hasLtVertices = graph.traversal().V()
+                                           .hasLabel("language")
+                                           .has("dynamic", P.lt(true))
+                                           .toList();
+        Assert.assertEquals(1, hasLtVertices.size());
+        Assert.assertEquals("rust", hasLtVertices.get(0).value("name"));
+
+        List<Vertex> whereLtVertices = graph.traversal().V()
+                                             .hasLabel("language")
+                                             .where(__.has("dynamic",
+                                                           P.lt(true)))
+                                             .toList();
+        Assert.assertEquals(1, whereLtVertices.size());
+        Assert.assertEquals("rust", whereLtVertices.get(0).value("name"));
+
+        List<Vertex> matchLtVertices = graph.traversal().V()
+                                             .hasLabel("language")
+                                             .match(__.as("start")
+                                                      .where(__.has("dynamic",
+                                                                    
P.lt(true)))
+                                                      .as("matched"))
+                                             .<Vertex>select("matched")
+                                             .toList();
+        Assert.assertEquals(1, matchLtVertices.size());
+        Assert.assertEquals("rust", matchLtVertices.get(0).value("name"));
+
+        List<Vertex> compoundOrVertices = graph.traversal().V()
+                                                .hasLabel("language")
+                                                .has("dynamic",
+                                                     P.gt(true).or(P.eq(true)))
+                                                .toList();
+        Assert.assertEquals(1, compoundOrVertices.size());
+        Assert.assertEquals("java", compoundOrVertices.get(0).value("name"));
+
+        Assert.assertEquals(0, graph.traversal().V()
+                                    .hasLabel("language")
+                                    .has("dynamic", P.lt(false))
+                                    .toList().size());
+
+        List<Vertex> gteFalseVertices = graph.traversal().V()
+                                             .hasLabel("language")
+                                             .has("dynamic", P.gte(false))
+                                             .toList();
+        Assert.assertEquals(2, gteFalseVertices.size());
+        Set<String> gteFalseNames = new HashSet<>();
+        for (Vertex vertex : gteFalseVertices) {
+            gteFalseNames.add(vertex.value("name"));
+        }
+        Assert.assertEquals(ImmutableSet.of("java", "rust"), gteFalseNames);
+    }
+
     @Test
     public void testQueryVertexBeforeAfterUpdateMultiPropertyWithIndex() {
         HugeGraph graph = graph();
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionQueryFlattenTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionQueryFlattenTest.java
index 627dcb29a..64833a3f7 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionQueryFlattenTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionQueryFlattenTest.java
@@ -256,5 +256,127 @@ public class ConditionQueryFlattenTest extends 
BaseUnitTest {
         Collection<Condition> actual = queries.iterator().next().conditions();
         Assert.assertEquals(expect, actual);
     }
+
+    @Test
+    public void testFlattenWithBooleanRangeUpperBound() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(Condition.lt(key, true));
+        query.query(Condition.lt(key, false));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(Condition.lt(key, false)), 
actual);
+    }
+
+    @Test
+    public void testFlattenWithBooleanRangeWindow() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(Condition.gte(key, false));
+        query.query(Condition.lt(key, true));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(Condition.gte(key, false),
+                                             Condition.lt(key, true)), actual);
+    }
+
+    @Test
+    public void testFlattenWithConflictingBooleanRange() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(Condition.gt(key, false).and(Condition.lt(key, true)));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(0, queries.size());
+    }
+
+    @Test
+    public void testFlattenWithImpossibleInInsideAnd() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(Condition.in(key, ImmutableList.of())
+                             .and(Condition.eq(key, true)));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(0, queries.size());
+    }
+
+    @Test
+    public void testFlattenWithImpossibleInInsideOr() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        Condition eq = Condition.eq(key, true);
+        query.query(Condition.in(key, ImmutableList.of()).or(eq));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(eq), actual);
+    }
+
+    @Test
+    public void testFlattenWithImpossibleInInsideOrRight() {
+        Id key = IdGenerator.of("c1");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        Condition eq = Condition.eq(key, true);
+        query.query(eq.or(Condition.in(key, ImmutableList.of())));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(eq), actual);
+    }
+
+    @Test
+    public void testFlattenWithImpossibleInInsideNestedAndOverOr() {
+        Id leftKey = IdGenerator.of("c1");
+        Id rightKey = IdGenerator.of("c2");
+
+        Condition left = Condition.in(leftKey, ImmutableList.of())
+                                  .or(Condition.eq(leftKey, "a"));
+        Condition right = Condition.eq(rightKey, "b");
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(left.and(right));
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(Condition.eq(leftKey, "a"),
+                                             right), actual);
+    }
+
+    @Test
+    public void testFlattenWithConflictingNumericRangeKeepsQuery() {
+        Id key = IdGenerator.of("c1");
+
+        Condition gt = Condition.gt(key, 10);
+        Condition eq = Condition.eq(key, 9);
+
+        ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+        query.query(gt);
+        query.query(eq);
+
+        List<ConditionQuery> queries = ConditionQueryFlatten.flatten(query);
+        Assert.assertEquals(1, queries.size());
+
+        Collection<Condition> actual = queries.iterator().next().conditions();
+        Assert.assertEquals(ImmutableList.of(gt, eq), actual);
+    }
 }
 
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionTest.java
index e333c7a98..ba4b09dca 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ConditionTest.java
@@ -293,6 +293,38 @@ public class ConditionTest extends BaseUnitTest {
         });
     }
 
+    @Test
+    public void testConditionBooleanRange() {
+        Condition lt = Condition.lt(HugeKeys.ID, true);
+        Assert.assertTrue(lt.test(false));
+        Assert.assertFalse(lt.test(true));
+
+        Condition lte = Condition.lte(HugeKeys.ID, false);
+        Assert.assertTrue(lte.test(false));
+        Assert.assertFalse(lte.test(true));
+
+        Condition gt = Condition.gt(HugeKeys.ID, false);
+        Assert.assertTrue(gt.test(true));
+        Assert.assertFalse(gt.test(false));
+
+        Condition gte = Condition.gte(HugeKeys.ID, true);
+        Assert.assertTrue(gte.test(true));
+        Assert.assertFalse(gte.test(false));
+
+        Assert.assertThrows(IllegalArgumentException.class, () -> {
+            Condition.lt(HugeKeys.ID, true).test(1);
+        }, e -> {
+            String err = "Can't compare between 1(Integer) and true(Boolean)";
+            Assert.assertEquals(err, e.getMessage());
+        });
+        Assert.assertThrows(IllegalArgumentException.class, () -> {
+            Condition.lt(HugeKeys.ID, true).test((Object) null);
+        }, e -> {
+            String err = "Can't compare between null(null) and true(Boolean)";
+            Assert.assertEquals(err, e.getMessage());
+        });
+    }
+
     @Test
     public void testConditionNeq() {
         Condition c1 = Condition.neq(HugeKeys.ID, 123);
diff --git 
a/hugegraph-struct/src/main/java/org/apache/hugegraph/query/Condition.java 
b/hugegraph-struct/src/main/java/org/apache/hugegraph/query/Condition.java
index 5c7d3e221..0d1b7ad05 100644
--- a/hugegraph-struct/src/main/java/org/apache/hugegraph/query/Condition.java
+++ b/hugegraph-struct/src/main/java/org/apache/hugegraph/query/Condition.java
@@ -437,7 +437,7 @@ public abstract class Condition {
          *
          * @param first  is actual value, might be Number/Date or String, It is
          *               probably that the `first` is serialized to String.
-         * @param second is value in query condition, must be Number/Date
+         * @param second is value in query condition, must be 
Number/Date/Boolean
          * @return the value 0 if first is numerically equal to second;
          * a value less than 0 if first is numerically less than
          * second; and a value greater than 0 if first is
@@ -450,6 +450,8 @@ public abstract class Condition {
                         (Number) second);
             } else if (second instanceof Date) {
                 return compareDate(first, (Date) second);
+            } else if (second instanceof Boolean) {
+                return compareBoolean(first, (Boolean) second);
             }
 
             throw new IllegalArgumentException(String.format(
@@ -472,6 +474,18 @@ public abstract class Condition {
                     second, second.getClass().getSimpleName()));
         }
 
+        private static int compareBoolean(Object first, Boolean second) {
+            if (first instanceof Boolean) {
+                return Boolean.compare((Boolean) first, second);
+            }
+
+            throw new IllegalArgumentException(String.format(
+                    "Can't compare between %s(%s) and %s(%s)",
+                    first, first == null ? null :
+                           first.getClass().getSimpleName(),
+                    second, second.getClass().getSimpleName()));
+        }
+
         public static List<String> tokenize(String str) {
             final ArrayList<String> tokens = new ArrayList<>();
             int previous = 0;
diff --git 
a/hugegraph-struct/src/test/java/org/apache/hugegraph/query/ConditionTest.java 
b/hugegraph-struct/src/test/java/org/apache/hugegraph/query/ConditionTest.java
new file mode 100644
index 000000000..b34fa4e73
--- /dev/null
+++ 
b/hugegraph-struct/src/test/java/org/apache/hugegraph/query/ConditionTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hugegraph.query;
+
+import org.apache.hugegraph.type.define.HugeKeys;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ConditionTest {
+
+    @Test
+    public void testConditionBooleanRange() {
+        Condition lt = Condition.lt(HugeKeys.ID, true);
+        Assert.assertTrue(lt.test(false));
+        Assert.assertFalse(lt.test(true));
+
+        Condition lte = Condition.lte(HugeKeys.ID, false);
+        Assert.assertTrue(lte.test(false));
+        Assert.assertFalse(lte.test(true));
+
+        Condition gt = Condition.gt(HugeKeys.ID, false);
+        Assert.assertTrue(gt.test(true));
+        Assert.assertFalse(gt.test(false));
+
+        Condition gte = Condition.gte(HugeKeys.ID, true);
+        Assert.assertTrue(gte.test(true));
+        Assert.assertFalse(gte.test(false));
+
+        IllegalArgumentException exception = Assert.assertThrows(
+                IllegalArgumentException.class,
+                () -> Condition.lt(HugeKeys.ID, true).test(1));
+        Assert.assertEquals("Can't compare between 1(Integer) and 
true(Boolean)",
+                            exception.getMessage());
+
+        exception = Assert.assertThrows(IllegalArgumentException.class,
+                                        () -> Condition.lt(HugeKeys.ID, true)
+                                                       .test((Object) null));
+        Assert.assertEquals("Can't compare between null(null) and 
true(Boolean)",
+                            exception.getMessage());
+    }
+}


Reply via email to