Repository: calcite
Updated Branches:
  refs/heads/master 980625481 -> 914b5cfbf


[CALCITE-1976] linq4j: support List and Map literals

Lists are printed as Collections.EMPTY_LIST or Arrays.asList();
maps are printed as common.collect.ImmutableMap of(..) or
builder().add(..).build().

Close apache/calcite#534


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/41687f3b
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/41687f3b
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/41687f3b

Branch: refs/heads/master
Commit: 41687f3bd7316acd931e81c7d2b061681fefc30b
Parents: 9806254
Author: Vladimir Sitnikov <[email protected]>
Authored: Fri Sep 8 14:57:18 2017 +0300
Committer: Julian Hyde <[email protected]>
Committed: Mon Oct 2 11:13:40 2017 -0700

----------------------------------------------------------------------
 .../calcite/linq4j/tree/ConstantExpression.java | 40 ++++++++++++
 .../calcite/linq4j/test/ExpressionTest.java     | 65 ++++++++++++++++++++
 2 files changed, 105 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/41687f3b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
----------------------------------------------------------------------
diff --git 
a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java 
b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
index 3fc112b..3437a42 100644
--- 
a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
+++ 
b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
@@ -26,6 +26,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -175,6 +176,17 @@ public class ConstantExpression extends Expression {
       list(writer, Primitive.asList(value), "[] {\n", ",\n", "}");
       return writer;
     }
+    if (value instanceof List) {
+      if (((List) value).isEmpty()) {
+        writer.append("java.util.Collections.EMPTY_LIST");
+        return writer;
+      }
+      list(writer, (List) value, "java.util.Arrays.asList(", ",\n", ")");
+      return writer;
+    }
+    if (value instanceof Map) {
+      return writeMap(writer, (Map) value);
+    }
     Constructor constructor = matchingConstructor(value);
     if (constructor != null) {
       writer.append("new ").append(value.getClass());
@@ -208,6 +220,34 @@ public class ConstantExpression extends Expression {
     writer.end(end);
   }
 
+  private static ExpressionWriter writeMap(ExpressionWriter writer, Map map) {
+    writer.append("com.google.common.collect.ImmutableMap.");
+    if (map.isEmpty()) {
+      return writer.append("of()");
+    }
+    if (map.size() < 5) {
+      return map(writer, map, "of(", ",\n", ")");
+    }
+    return map(writer, map, "builder().put(", ")\n.put(", ").build()");
+  }
+
+  private static ExpressionWriter map(ExpressionWriter writer, Map map,
+      String begin, String entrySep, String end) {
+    writer.append(begin);
+    boolean comma = false;
+    for (Object o : map.entrySet()) {
+      Map.Entry entry = (Map.Entry) o;
+      if (comma) {
+        writer.append(entrySep).indent();
+      }
+      write(writer, entry.getKey(), null);
+      writer.append(", ");
+      write(writer, entry.getValue(), null);
+      comma = true;
+    }
+    return writer.append(end);
+  }
+
   private static Constructor matchingConstructor(Object value) {
     final Field[] fields = value.getClass().getFields();
     for (Constructor<?> constructor : value.getClass().getConstructors()) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/41687f3b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
----------------------------------------------------------------------
diff --git 
a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java 
b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
index a8c1053..9d094b3 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
@@ -34,6 +34,8 @@ import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Shuttle;
 import org.apache.calcite.linq4j.tree.Types;
 
+import com.google.common.collect.ImmutableMap;
+
 import org.junit.Test;
 
 import java.lang.reflect.Modifier;
@@ -44,7 +46,10 @@ import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.TreeSet;
 
 import static org.hamcrest.core.Is.is;
@@ -1199,6 +1204,66 @@ public class ExpressionTest {
         Expressions.toString(builder.toBlock()));
   }
 
+  @Test public void testEmptyListLiteral() throws Exception {
+    assertEquals("java.util.Collections.EMPTY_LIST",
+        Expressions.toString(Expressions.constant(Arrays.asList())));
+  }
+
+  @Test public void testEneElementListLiteral() throws Exception {
+    assertEquals("java.util.Arrays.asList(1)",
+        Expressions.toString(Expressions.constant(Arrays.asList(1))));
+  }
+
+  @Test public void testTwoElementListLiteral() throws Exception {
+    assertEquals("java.util.Arrays.asList(1,\n"
+            + "  2)",
+        Expressions.toString(Expressions.constant(Arrays.asList(1, 2))));
+  }
+
+  @Test public void testNestedListsLiteral() throws Exception {
+    assertEquals("java.util.Arrays.asList(java.util.Arrays.asList(1,\n"
+            + "    2),\n"
+            + "  java.util.Arrays.asList(3,\n"
+            + "    4))",
+        Expressions.toString(
+            Expressions.constant(
+                Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4)))));
+  }
+
+  @Test public void testEmptyMapLiteral() throws Exception {
+    assertEquals("com.google.common.collect.ImmutableMap.of()",
+        Expressions.toString(Expressions.constant(new HashMap())));
+  }
+
+  @Test public void testOneElementMapLiteral() throws Exception {
+    assertEquals("com.google.common.collect.ImmutableMap.of(\"abc\", 42)",
+        
Expressions.toString(Expressions.constant(Collections.singletonMap("abc", 
42))));
+  }
+
+  @Test public void testTwoElementMapLiteral() throws Exception {
+    assertEquals("com.google.common.collect.ImmutableMap.of(\"abc\", 42,\n"
+            + "\"def\", 43)",
+        Expressions.toString(Expressions.constant(ImmutableMap.of("abc", 42, 
"def", 43))));
+  }
+
+  @Test public void testTenElementMapLiteral() throws Exception {
+    Map<String, String> map = new LinkedHashMap<>(); // for consistent output
+    for (int i = 0; i < 10; i++) {
+      map.put("key_" + i, "value_" + i);
+    }
+    
assertEquals("com.google.common.collect.ImmutableMap.builder().put(\"key_0\", 
\"value_0\")\n"
+            + ".put(\"key_1\", \"value_1\")\n"
+            + ".put(\"key_2\", \"value_2\")\n"
+            + ".put(\"key_3\", \"value_3\")\n"
+            + ".put(\"key_4\", \"value_4\")\n"
+            + ".put(\"key_5\", \"value_5\")\n"
+            + ".put(\"key_6\", \"value_6\")\n"
+            + ".put(\"key_7\", \"value_7\")\n"
+            + ".put(\"key_8\", \"value_8\")\n"
+            + ".put(\"key_9\", \"value_9\").build()",
+        Expressions.toString(Expressions.constant(map)));
+  }
+
   /** An enum. */
   enum MyEnum {
     X,

Reply via email to