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

cancai pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new e3184180ba [CALCITE-2109] MongoAdapter: Support in condition with and 
condition
e3184180ba is described below

commit e3184180ba170827e0e91682a693cd02b46b8657
Author: tuichenchuxin <[email protected]>
AuthorDate: Thu Mar 27 11:39:04 2025 +0800

    [CALCITE-2109] MongoAdapter: Support in condition with and condition
---
 .../calcite/adapter/mongodb/MongoFilter.java       | 67 ++++++++++++++--------
 .../calcite/adapter/mongodb/MongoAdapterTest.java  | 60 +++++++++++++++++++
 2 files changed, 103 insertions(+), 24 deletions(-)

diff --git 
a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoFilter.java 
b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoFilter.java
index bb8299b202..455877aa94 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoFilter.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoFilter.java
@@ -81,10 +81,6 @@ public MongoFilter(
   /** Translates {@link RexNode} expressions into MongoDB expression strings. 
*/
   static class Translator {
     final JsonBuilder builder = new JsonBuilder();
-    final Multimap<String, Pair<String, RexLiteral>> multimap =
-        HashMultimap.create();
-    final Map<String, RexLiteral> eqMap =
-        new LinkedHashMap<>();
     private final RexBuilder rexBuilder;
     private final List<String> fieldNames;
 
@@ -99,11 +95,11 @@ private String translateMatch(RexNode condition) {
       return builder.toJsonString(map);
     }
 
-    private Object translateOr(RexNode condition) {
+    private Map<String, Object> translateOr(RexNode condition) {
       final RexNode condition2 =
           RexUtil.expandSearch(rexBuilder, null, condition);
 
-      List<Object> list = new ArrayList<>();
+      List<Map<String, Object>> list = new ArrayList<>();
       for (RexNode node : RelOptUtil.disjunctions(condition2)) {
         list.add(translateAnd(node));
       }
@@ -120,10 +116,13 @@ private Object translateOr(RexNode condition) {
     /** Translates a condition that may be an AND of other conditions. Gathers
      * together conditions that apply to the same field. */
     private Map<String, Object> translateAnd(RexNode node0) {
-      eqMap.clear();
-      multimap.clear();
+      final Multimap<String, Pair<String, RexLiteral>> multimap =
+          HashMultimap.create();
+      final Map<String, RexLiteral> eqMap =
+          new LinkedHashMap<>();
+      final List<Map<String, Object>> orMapList = new ArrayList<>();
       for (RexNode node : RelOptUtil.conjunctions(node0)) {
-        translateMatch2(node);
+        translateMatch2(node, orMapList, multimap, eqMap);
       }
       Map<String, Object> map = builder.map();
       for (Map.Entry<String, RexLiteral> entry : eqMap.entrySet()) {
@@ -138,6 +137,14 @@ private Map<String, Object> translateAnd(RexNode node0) {
         }
         map.put(entry.getKey(), map2);
       }
+      if (!orMapList.isEmpty()) {
+        Map<String, Object> andMap = builder.map();
+        if (!map.isEmpty()) {
+          orMapList.add(map);
+        }
+        andMap.put("$and", orMapList);
+        return andMap;
+      }
       return map;
     }
 
@@ -173,35 +180,45 @@ private static Object literalValue(RexLiteral literal) {
       return literal.getValue2();
     }
 
-    private Void translateMatch2(RexNode node) {
+    private Void translateMatch2(RexNode node, List<Map<String, Object>> 
orMapList,
+        Multimap<String, Pair<String, RexLiteral>> multimap, Map<String, 
RexLiteral> eqMap) {
       switch (node.getKind()) {
       case EQUALS:
-        return translateBinary(null, null, (RexCall) node);
+        return translateBinary(null, null, (RexCall) node, multimap, eqMap);
       case LESS_THAN:
-        return translateBinary("$lt", "$gt", (RexCall) node);
+        return translateBinary("$lt", "$gt", (RexCall) node, multimap, eqMap);
       case LESS_THAN_OR_EQUAL:
-        return translateBinary("$lte", "$gte", (RexCall) node);
+        return translateBinary("$lte", "$gte", (RexCall) node, multimap, 
eqMap);
       case NOT_EQUALS:
-        return translateBinary("$ne", "$ne", (RexCall) node);
+        return translateBinary("$ne", "$ne", (RexCall) node, multimap, eqMap);
       case GREATER_THAN:
-        return translateBinary("$gt", "$lt", (RexCall) node);
+        return translateBinary("$gt", "$lt", (RexCall) node, multimap, eqMap);
       case GREATER_THAN_OR_EQUAL:
-        return translateBinary("$gte", "$lte", (RexCall) node);
+        return translateBinary("$gte", "$lte", (RexCall) node, multimap, 
eqMap);
+      case OR:
+        return translateOrAddToList(node, orMapList);
       default:
         throw new AssertionError("cannot translate " + node);
       }
     }
 
+    private Void translateOrAddToList(RexNode node, List<Map<String, Object>> 
orMapList) {
+      Map<String, Object> or = translateOr(node);
+      orMapList.add(or);
+      return null;
+    }
+
     /** Translates a call to a binary operator, reversing arguments if
      * necessary. */
-    private Void translateBinary(String op, String rop, RexCall call) {
+    private Void translateBinary(String op, String rop, RexCall call,
+        Multimap<String, Pair<String, RexLiteral>> multimap, Map<String, 
RexLiteral> eqMap) {
       final RexNode left = call.operands.get(0);
       final RexNode right = call.operands.get(1);
-      boolean b = translateBinary2(op, left, right);
+      boolean b = translateBinary2(op, left, right, multimap, eqMap);
       if (b) {
         return null;
       }
-      b = translateBinary2(rop, right, left);
+      b = translateBinary2(rop, right, left, multimap, eqMap);
       if (b) {
         return null;
       }
@@ -209,7 +226,8 @@ private Void translateBinary(String op, String rop, RexCall 
call) {
     }
 
     /** Translates a call to a binary operator. Returns whether successful. */
-    private boolean translateBinary2(String op, RexNode left, RexNode right) {
+    private boolean translateBinary2(String op, RexNode left, RexNode right,
+        Multimap<String, Pair<String, RexLiteral>> multimap, Map<String, 
RexLiteral> eqMap) {
       switch (right.getKind()) {
       case LITERAL:
         break;
@@ -221,14 +239,14 @@ private boolean translateBinary2(String op, RexNode left, 
RexNode right) {
       case INPUT_REF:
         final RexInputRef left1 = (RexInputRef) left;
         String name = fieldNames.get(left1.getIndex());
-        translateOp2(op, name, rightLiteral);
+        translateOp2(op, name, rightLiteral, multimap, eqMap);
         return true;
       case CAST:
-        return translateBinary2(op, ((RexCall) left).operands.get(0), right);
+        return translateBinary2(op, ((RexCall) left).operands.get(0), right, 
multimap, eqMap);
       case ITEM:
         String itemName = MongoRules.isItem((RexCall) left);
         if (itemName != null) {
-          translateOp2(op, itemName, rightLiteral);
+          translateOp2(op, itemName, rightLiteral, multimap, eqMap);
           return true;
         }
         // fall through
@@ -237,7 +255,8 @@ private boolean translateBinary2(String op, RexNode left, 
RexNode right) {
       }
     }
 
-    private void translateOp2(String op, String name, RexLiteral right) {
+    private void translateOp2(String op, String name, RexLiteral right,
+        Multimap<String, Pair<String, RexLiteral>> multimap, Map<String, 
RexLiteral> eqMap) {
       if (op == null) {
         // E.g.: {deptno: 100}
         eqMap.put(name, right);
diff --git 
a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
 
b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
index 0aeb6ef87c..1876862d2e 100644
--- 
a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
+++ 
b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
@@ -859,4 +859,64 @@ private static Consumer<List> mongoChecker(final String... 
expected) {
         .limit(2)
         .returns("STATE=VT; AVG(pop)=26408\nSTATE=AK; AVG(pop)=26856\n");
   }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2109";>[CALCITE-2109]
+   * Mongo adapter: unable to translate (A AND B) conditional case</a>. */
+  @Test void testTranslateAndInCondition() {
+    assertModel(MODEL)
+        .query("select state, city from zips "
+            + "where city='LEWISTON' and state in ('ME', 'VT') "
+            + "order by state")
+        .queryContains(
+            mongoChecker(
+            "{$match: {$and: [{$or: [{state: \"ME\"}, {state: \"VT\"}]}, 
{city: \"LEWISTON\"}]}}",
+            "{$project: {STATE: '$state', CITY: '$city'}}",
+            "{$sort: {STATE: 1}}"))
+        .returns("STATE=ME; CITY=LEWISTON\n");
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2109";>[CALCITE-2109]
+   * Mongo adapter: unable to translate (A AND B) conditional case</a>. */
+  @Test void testTranslateOrAndCondition() {
+    assertModel(MODEL)
+        .query("select state, city from zips "
+            + "where (state = 'MI' or state = 'VT') and city='TAYLOR' "
+            + "order by state")
+        .queryContains(
+            mongoChecker(
+                "{$match: {$and: [{$or: [{state: \"MI\"}, {state: \"VT\"}]}, 
{city: \"TAYLOR\"}]}}",
+                "{$project: {STATE: '$state', CITY: '$city'}}",
+                "{$sort: {STATE: 1}}"))
+        .returns("STATE=MI; CITY=TAYLOR\n");
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2109";>[CALCITE-2109]
+   * Mongo adapter: unable to translate (A AND B) conditional case</a>. */
+  @Test void testAndAlwaysFalseCondition() {
+    assertModel(MODEL)
+        .query("select state, city from zips "
+            + "where city='LEWISTON' and 1=0 "
+            + "order by state")
+        .explainContains("PLAN=EnumerableValues(tuples=[[]])")
+        .returns("");
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2109";>[CALCITE-2109]
+   * Mongo adapter: unable to translate (A AND B) conditional case</a>. */
+  @Test void testCNFCondition() {
+    assertModel(MODEL)
+        .query("select state, city from zips "
+            + "where (state='ME' OR state='VT') AND (city='LEWISTON' OR 
city='BRATTLEBORO') "
+            + "order by state")
+        .queryContains(
+            mongoChecker(
+                "{$match: {$and: [{$or: [{state: \"ME\"}, {state: \"VT\"}]}, 
{$or: [{city: \"BRATTLEBORO\"}, {city: \"LEWISTON\"}]}]}}",
+                "{$project: {STATE: '$state', CITY: '$city'}}",
+                "{$sort: {STATE: 1}}"))
+        .returns("STATE=ME; CITY=LEWISTON\nSTATE=VT; CITY=BRATTLEBORO\n");
+  }
 }

Reply via email to