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());
+ }
+}