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,
