From 0a39867a3adf5ba92ddcfff4324325cd09568a53 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Fri, 5 Mar 2021 12:10:52 +0100 Subject: [PATCH] GH-157 - Provide a method to turn a Java map into an expression. This closes #157. --- .../examples/core/PropertiesTest.java | 13 +++++++++++++ .../java/org/neo4j/cypherdsl/core/Cypher.java | 12 ++++++++++++ .../cypherdsl/core/ExposesProperties.java | 13 +++++++++++++ .../neo4j/cypherdsl/core/MapExpression.java | 13 +++++++++++++ .../org/neo4j/cypherdsl/core/CypherIT.java | 19 +++++++++++++++++++ 5 files changed, 70 insertions(+) diff --git a/neo4j-cypher-dsl-examples/src/test/java/org/neo4j/cypherdsl/examples/core/PropertiesTest.java b/neo4j-cypher-dsl-examples/src/test/java/org/neo4j/cypherdsl/examples/core/PropertiesTest.java index fa8ec8cf3e..1ecdfe058b 100644 --- a/neo4j-cypher-dsl-examples/src/test/java/org/neo4j/cypherdsl/examples/core/PropertiesTest.java +++ b/neo4j-cypher-dsl-examples/src/test/java/org/neo4j/cypherdsl/examples/core/PropertiesTest.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.Map; import java.util.regex.Pattern; import org.assertj.core.api.Assertions; @@ -102,4 +103,16 @@ void nestedProperties() { .isEqualTo("MATCH (p:`Person`) WHERE p.`home.location`.y > 50 RETURN p.`home.location`.y"); // end::nested-properties[] } + + @Test + void usingExistingJavaMaps() { + + var node = Cypher + .node("ANode") + .named("n") + .withProperties(Map.of("aProperty", 23)); + + assertThat(Cypher.match(node).returning(node).build().getCypher()) + .isEqualTo("MATCH (n:`ANode` {aProperty: 23}) RETURN n"); + } } diff --git a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/Cypher.java b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/Cypher.java index 7426a83da0..124f594165 100644 --- a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/Cypher.java +++ b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/Cypher.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.apiguardian.api.API; import org.neo4j.cypherdsl.core.ListComprehension.OngoingDefinitionWithVariable; @@ -393,6 +394,17 @@ public static MapExpression mapOf(Object... keysAndValues) { return MapExpression.create(keysAndValues); } + /** + * Creates a map of expression from a Java Map. + * + * @param map A map to be turned into a MapExpression + * @return A new map expression. + */ + public static MapExpression asExpression(Map map) { + + return MapExpression.create(map); + } + /** * Creates a {@link ListExpression list-expression} from several expressions. * diff --git a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/ExposesProperties.java b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/ExposesProperties.java index 3c0cf59097..4203a355d3 100644 --- a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/ExposesProperties.java +++ b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/ExposesProperties.java @@ -18,6 +18,8 @@ */ package org.neo4j.cypherdsl.core; +import java.util.Map; + /** * A container that exposes methods to add properties with values to nodes or relationships. * @@ -45,4 +47,15 @@ public interface ExposesProperties & PropertyCont * @return The new property container. */ T withProperties(Object... keysAndValues); + + /** + * Creates a a copy of this property container with additional properties. + * + * @param newProperties A map with the new properties + * @return The new property container. + */ + default T withProperties(Map newProperties) { + + return withProperties(MapExpression.create(newProperties)); + } } diff --git a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/MapExpression.java b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/MapExpression.java index 9e2277a714..4cf40645d0 100644 --- a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/MapExpression.java +++ b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/MapExpression.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apiguardian.api.API; @@ -43,6 +44,18 @@ @API(status = INTERNAL, since = "1.0") public final class MapExpression extends TypedSubtree implements Expression { + static MapExpression create(Map map) { + + Object[] args = new Object[map.size() * 2]; + int i = 0; + for (Map.Entry entry : map.entrySet()) { + Object value = entry.getValue(); + args[i++] = entry.getKey(); + args[i++] = value instanceof Expression ? value : Cypher.literalOf(value); + } + return create(args); + } + static MapExpression create(Object... input) { Assertions.isTrue(input.length % 2 == 0, "Need an even number of input parameters"); diff --git a/neo4j-cypher-dsl/src/test/java/org/neo4j/cypherdsl/core/CypherIT.java b/neo4j-cypher-dsl/src/test/java/org/neo4j/cypherdsl/core/CypherIT.java index f9e647969f..8227acd5f9 100644 --- a/neo4j-cypher-dsl/src/test/java/org/neo4j/cypherdsl/core/CypherIT.java +++ b/neo4j-cypher-dsl/src/test/java/org/neo4j/cypherdsl/core/CypherIT.java @@ -21,6 +21,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; @@ -2701,6 +2703,23 @@ void shouldRenderPointFunction() { @Nested class PropertyRendering { + @Test // GH-157 + void usingExistingJavaMaps() { + + Map newProperties = new LinkedHashMap<>(); + newProperties.put("prop1", 23); + newProperties.put("theTruth", 42); + newProperties.put("somethingElse", "foobar"); + newProperties.put("aParam", Cypher.parameter("x").withValue("y")); + Node node = Cypher + .node("ANode") + .named("n") + .withProperties(newProperties); + + assertThat(Cypher.match(node).returning(node).build().getCypher()) + .isEqualTo("MATCH (n:`ANode` {prop1: 23, theTruth: 42, somethingElse: 'foobar', aParam: $x}) RETURN n"); + } + @Test // GH-114 void manuallyNested() { Node node = Cypher.node("Person").named("p");