diff --git a/core/src/main/java/apoc/merge/Merge.java b/core/src/main/java/apoc/merge/Merge.java index 1ad913494a..561e7d8864 100644 --- a/core/src/main/java/apoc/merge/Merge.java +++ b/core/src/main/java/apoc/merge/Merge.java @@ -47,18 +47,18 @@ public class Merge { @Description("apoc.merge.node.eager(['Label'], identProps:{key:value, ...}, onCreateProps:{key:value,...}, onMatchProps:{key:value,...}}) - merge nodes eagerly, with dynamic labels, with support for setting properties ON CREATE or ON MATCH") public Stream nodesEager(@Name("label") List labelNames, @Name("identProps") Map identProps, - @Name(value = "props",defaultValue = "{}") Map props, + @Name(value = "onCreateProps",defaultValue = "{}") Map onCreateProps, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { - return nodes(labelNames, identProps,props,onMatchProps); + return nodes(labelNames, identProps, onCreateProps, onMatchProps); } @Procedure(value="apoc.merge.node", mode = Mode.WRITE) @Description("\"apoc.merge.node(['Label'], identProps:{key:value, ...}, onCreateProps:{key:value,...}, onMatchProps:{key:value,...}}) - merge nodes with dynamic labels, with support for setting properties ON CREATE or ON MATCH") public Stream nodes(@Name("label") List labelNames, @Name("identProps") Map identProps, - @Name(value = "props",defaultValue = "{}") Map props, + @Name(value = "onCreateProps",defaultValue = "{}") Map onCreateProps, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { - final Result nodeResult = getNodeResult(labelNames, identProps, props, onMatchProps); + final Result nodeResult = getNodeResult(labelNames, identProps, onCreateProps, onMatchProps); return nodeResult.columnAs("n").stream().map(node -> new NodeResult((Node) node)); } @@ -66,33 +66,42 @@ public Stream nodes(@Name("label") List labelNames, @Description("apoc.merge.nodeWithStats.eager - same as apoc.merge.node.eager providing queryStatistics into result") public Stream nodeWithStatsEager(@Name("label") List labelNames, @Name("identProps") Map identProps, - @Name(value = "props",defaultValue = "{}") Map props, + @Name(value = "onCreateProps",defaultValue = "{}") Map onCreateProps, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { - return nodeWithStats(labelNames, identProps,props,onMatchProps); + return nodeWithStats(labelNames, identProps, onCreateProps, onMatchProps); } @Procedure(value="apoc.merge.nodeWithStats", mode = Mode.WRITE) @Description("apoc.merge.nodeWithStats - same as apoc.merge.node providing queryStatistics into result") public Stream nodeWithStats(@Name("label") List labelNames, @Name("identProps") Map identProps, - @Name(value = "props",defaultValue = "{}") Map props, + @Name(value = "onCreateProps",defaultValue = "{}") Map onCreateProps, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { - final Result nodeResult = getNodeResult(labelNames, identProps, props, onMatchProps); + final Result nodeResult = getNodeResult(labelNames, identProps, onCreateProps, onMatchProps); return nodeResult.columnAs("n").stream() .map(node -> new NodeResultWithStats((Node) node, Cypher.toMap(nodeResult.getQueryStatistics()))); } - private Result getNodeResult(List labelNames, Map identProps, Map props, Map onMatchProps) { - if (identProps ==null || identProps.isEmpty()) { + private Result getNodeResult(List labelNames, Map identProps, Map onCreateProps, Map onMatchProps) { + if (identProps == null || identProps.isEmpty()) { throw new IllegalArgumentException("you need to supply at least one identifying property for a merge"); } - String labels = labelString(labelNames); + if (labelNames != null && (labelNames.contains(null) || labelNames.contains(""))) { + throw new IllegalArgumentException("The list of label names may not contain any `NULL` or empty `STRING` values. If you wish to merge a `NODE` without a label, pass an empty list instead."); + } + + String labels; + if (labelNames == null || labelNames.isEmpty()) { + labels = ""; + } else { + labels = ":" + labelNames.stream().map(Util::quote).collect(Collectors.joining(":")); + } - Map params = Util.map("identProps", identProps, "onCreateProps", props, "onMatchProps", onMatchProps); + Map params = Util.map("identProps", identProps, "onCreateProps", onCreateProps, "onMatchProps", onMatchProps); String identPropsString = buildIdentPropsString(identProps); - final String cypher = "MERGE (n:" + labels + "{" + identPropsString + "}) ON CREATE SET n += $onCreateProps ON MATCH SET n += $onMatchProps RETURN n"; + final String cypher = "MERGE (n" + labels + "{" + identPropsString + "}) ON CREATE SET n += $onCreateProps ON MATCH SET n += $onMatchProps RETURN n"; return tx.execute(cypher, params); } @@ -100,7 +109,7 @@ private Result getNodeResult(List labelNames, Map identP @Description("apoc.merge.relationship(startNode, relType, identProps:{key:value, ...}, onCreateProps:{key:value, ...}, endNode, onMatchProps:{key:value, ...}) - merge relationship with dynamic type, with support for setting properties ON CREATE or ON MATCH") public Stream relationship(@Name("startNode") Node startNode, @Name("relationshipType") String relType, @Name("identProps") Map identProps, - @Name("props") Map onCreateProps, + @Name("onCreateProps") Map onCreateProps, @Name("endNode") Node endNode, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { final Result execute = getRelResult(startNode, relType, identProps, onCreateProps, endNode, onMatchProps); @@ -111,7 +120,7 @@ public Stream relationship(@Name("startNode") Node startNode @Description("apoc.merge.relationshipWithStats - same as apoc.merge.relationship providing queryStatistics into result") public Stream relationshipWithStats(@Name("startNode") Node startNode, @Name("relationshipType") String relType, @Name("identProps") Map identProps, - @Name("props") Map onCreateProps, + @Name("onCreateProps") Map onCreateProps, @Name("endNode") Node endNode, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { final Result relResult = getRelResult(startNode, relType, identProps, onCreateProps, endNode, onMatchProps); @@ -122,6 +131,11 @@ public Stream relationshipWithStats(@Name("startNod private Result getRelResult(Node startNode, String relType, Map identProps, Map onCreateProps, Node endNode, Map onMatchProps) { String identPropsString = buildIdentPropsString(identProps); + if (relType == null || relType.isEmpty()) { + throw new IllegalArgumentException("It is not possible to merge a `RELATIONSHIP` without a `RELATIONSHIP` type."); + } + + Map params = Util.map("identProps", identProps, "onCreateProps", onCreateProps == null ? emptyMap() : onCreateProps, Map params = Util.map("identProps", identProps, "onCreateProps", onCreateProps ==null ? emptyMap() : onCreateProps, "onMatchProps", onMatchProps == null ? emptyMap() : onMatchProps, "startNode", startNode, "endNode", endNode); @@ -138,7 +152,7 @@ private Result getRelResult(Node startNode, String relType, Map @Description("apoc.merge.relationship(startNode, relType, identProps:{key:value, ...}, onCreateProps:{key:value, ...}, endNode, onMatchProps:{key:value, ...}) - merge relationship with dynamic type, with support for setting properties ON CREATE or ON MATCH") public Stream relationshipEager(@Name("startNode") Node startNode, @Name("relationshipType") String relType, @Name("identProps") Map identProps, - @Name("props") Map onCreateProps, + @Name("onCreateProps") Map onCreateProps, @Name("endNode") Node endNode, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { return relationship(startNode, relType, identProps, onCreateProps, endNode, onMatchProps ); @@ -148,7 +162,7 @@ public Stream relationshipEager(@Name("startNode") Node star @Description("apoc.merge.relationshipWithStats.eager - same as apoc.merge.relationship.eager providing queryStatistics into result") public Stream relationshipWithStatsEager(@Name("startNode") Node startNode, @Name("relationshipType") String relType, @Name("identProps") Map identProps, - @Name("props") Map onCreateProps, + @Name("onCreateProps") Map onCreateProps, @Name("endNode") Node endNode, @Name(value = "onMatchProps",defaultValue = "{}") Map onMatchProps) { return relationshipWithStats(startNode, relType, identProps, onCreateProps, endNode, onMatchProps ); diff --git a/core/src/main/java/apoc/util/Util.java b/core/src/main/java/apoc/util/Util.java index beb0d46616..ad9542f731 100644 --- a/core/src/main/java/apoc/util/Util.java +++ b/core/src/main/java/apoc/util/Util.java @@ -143,10 +143,6 @@ public class Util { public static String INVALID_QUERY_MODE_ERROR = "This procedure allows for READ-only, non-schema based queries. " + "It is therefore not possible to perform writes or query the database with commands such as SHOW CONSTRAINTS/INDEXES."; - public static String labelString(List labelNames) { - return labelNames.stream().map(Util::quote).collect(Collectors.joining(":")); - } - public static String labelString(Node n) { return joinLabels(n.getLabels(), ":"); } diff --git a/core/src/test/java/apoc/merge/MergeTest.java b/core/src/test/java/apoc/merge/MergeTest.java index 559cf17fc9..46ad97ea5b 100644 --- a/core/src/test/java/apoc/merge/MergeTest.java +++ b/core/src/test/java/apoc/merge/MergeTest.java @@ -67,8 +67,8 @@ private void testMergeNodeCommon(boolean isWithStats) { testCall(db, String.format("CALL apoc.merge.%s(['Person','Bastard'],{ssid:'123'}, {name:'John'})", procName), (row) -> { Node node = (Node) row.get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals(true, node.hasLabel(Label.label("Bastard"))); + assertTrue(node.hasLabel(Label.label("Person"))); + assertTrue(node.hasLabel(Label.label("Bastard"))); assertEquals("John", node.getProperty("name")); assertEquals("123", node.getProperty("ssid")); @@ -87,7 +87,7 @@ public void testMergeNodeWithPreExisting() throws Exception { testCall(db, "CALL apoc.merge.node(['Person'],{ssid:'123'}, {name:'John'}) YIELD node RETURN node", (row) -> { Node node = (Node) row.get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); + assertTrue(node.hasLabel(Label.label("Person")));; assertEquals("Jim", node.getProperty("name")); assertEquals("123", node.getProperty("ssid")); }); @@ -96,6 +96,94 @@ public void testMergeNodeWithPreExisting() throws Exception { assertEquals(1, (long)(Iterators.single(result.columnAs("c")))) ); } + @Test + public void testMergeWithNoLabel() { + testCall(db, "CALL apoc.merge.node(null, {name:'John'}) YIELD node RETURN node", + (row) -> { + Node node = (Node) row.get("node"); + assertFalse(node.getLabels().iterator().hasNext()); + assertEquals("John", node.getProperty("name")); + }); + testResult(db, "match (p) return count(*) as c", result -> + assertEquals(1, (long)(Iterators.single(result.columnAs("c")))) + ); + } + + @Test + public void testMergeNodeWithEmptyLabelList() { + testCall(db, "CALL apoc.merge.node([], {name:'John'}) YIELD node RETURN node", + (row) -> { + Node node = (Node) row.get("node"); + assertFalse(node.getLabels().iterator().hasNext()); + assertEquals("John", node.getProperty("name")); + }); + + testResult(db, "match (p) return count(*) as c", result -> + assertEquals(1, (long)(Iterators.single(result.columnAs("c")))) + ); + } + + @Test + public void testMergeWithEmptyIdentityPropertiesShouldFail() { + for (String idProps: new String[]{"null", "{}"}) { + try { + testCall(db, "CALL apoc.merge.node(['Person']," + idProps +", {name:'John'}) YIELD node RETURN node", + row -> assertTrue(row.get("node") instanceof Node)); + fail(); + } catch (QueryExecutionException e) { + assertTrue(e.getMessage().contains("you need to supply at least one identifying property for a merge")); + } + } + } + + @Test + public void testMergeNodeWithNullLabelsShouldFail() { + try { + testCall(db, "CALL apoc.merge.node([null], {name:'John'}) YIELD node RETURN node", + row -> assertTrue(row.get("node") instanceof Node)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), "Failed to invoke procedure `apoc.merge.node`: Caused by: java.lang.IllegalArgumentException: " + + "The list of label names may not contain any `NULL` or empty `STRING` values. If you wish to merge a `NODE` without a label, pass an empty list instead."); + } + } + + @Test + public void testMergeNodeWithMixedLabelsContainingNullShouldFail() { + try { + testCall(db, "CALL apoc.merge.node(['Person', null], {name:'John'}) YIELD node RETURN node", + row -> assertTrue(row.get("node") instanceof Node)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), "Failed to invoke procedure `apoc.merge.node`: Caused by: java.lang.IllegalArgumentException: " + + "The list of label names may not contain any `NULL` or empty `STRING` values. If you wish to merge a `NODE` without a label, pass an empty list instead."); + } + } + + @Test + public void testMergeNodeWithSingleEmptyLabelShouldFail() { + try { + testCall(db, "CALL apoc.merge.node([''], {name:'John'}) YIELD node RETURN node", + Lojjs marked this conversation as resolved. + row -> assertTrue(row.get("node") instanceof Node)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), "Failed to invoke procedure `apoc.merge.node`: Caused by: java.lang.IllegalArgumentException: " + + "The list of label names may not contain any `NULL` or empty `STRING` values. If you wish to merge a `NODE` without a label, pass an empty list instead."); + } + } + + @Test + public void testMergeNodeContainingMixedLabelsContainingEmptyStringShouldFail() { + try { + testCall(db, "CALL apoc.merge.node(['Person', ''], {name:'John'}) YIELD node RETURN node", + row -> assertTrue(row.get("node") instanceof Node)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), "Failed to invoke procedure `apoc.merge.node`: Caused by: java.lang.IllegalArgumentException: " + + "The list of label names may not contain any `NULL` or empty `STRING` values. If you wish to merge a `NODE` without a label, pass an empty list instead."); + } + } @Test public void testMergeRelationships() throws Exception { @@ -105,7 +193,7 @@ public void testMergeRelationships() throws Exception { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Thu", rel.getProperty("since")); }); @@ -113,7 +201,7 @@ public void testMergeRelationships() throws Exception { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Thu", rel.getProperty("since")); }); testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, 'OTHER', null, null, e) YIELD rel RETURN rel", @@ -123,19 +211,6 @@ public void testMergeRelationships() throws Exception { assertTrue(rel.getAllProperties().isEmpty()); }); } - - @Test - public void testMergeWithEmptyIdentityPropertiesShouldFail() { - for (String idProps: new String[]{"null", "{}"}) { - try { - testCall(db, "CALL apoc.merge.node(['Person']," + idProps +", {name:'John'}) YIELD node RETURN node", - row -> assertTrue(row.get("node") instanceof Node)); - fail(); - } catch (QueryExecutionException e) { - assertTrue(e.getMessage().contains("you need to supply at least one identifying property for a merge")); - } - } - } @Test public void testEscapeIdentityPropertiesWithSpecialCharactersShouldWork() { @@ -146,7 +221,7 @@ public void testEscapeIdentityPropertiesWithSpecialCharactersShouldWork() { testCall(db, "CALL apoc.merge.node(['Person'], $identProps) YIELD node RETURN node", params, (row) -> { Node node = (Node) row.get("node"); - assertTrue(node instanceof Node); + assertNotNull(node); assertTrue(node.hasProperty(key)); assertEquals("value", node.getProperty(key)); }); @@ -162,6 +237,35 @@ public void testLabelsWithSpecialCharactersShouldWork() { } } + // MERGE RELATIONSHIPS + @Test + public void testMergeRelationships() { + db.executeTransactionally("create (:Person{name:'Foo'}), (:Person{name:'Bar'})"); + + testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, 'KNOWS', {rid:123}, {since:'Thu'}, e) YIELD rel RETURN rel", + (row) -> { + Relationship rel = (Relationship) row.get("rel"); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(123L, rel.getProperty("rid")); + assertEquals("Thu", rel.getProperty("since")); + }); + + testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, 'KNOWS', {rid:123}, {since:'Fri'}, e) YIELD rel RETURN rel", + (row) -> { + Relationship rel = (Relationship) row.get("rel"); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(123L, rel.getProperty("rid")); + assertEquals("Thu", rel.getProperty("since")); + }); + testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, 'OTHER', null, null, e) YIELD rel RETURN rel", + (row) -> { + Relationship rel = (Relationship) row.get("rel"); + assertEquals("OTHER", rel.getType().name()); + assertTrue(rel.getAllProperties().isEmpty()); + }); + } + + @Test public void testRelationshipTypesWithSpecialCharactersShouldWork() { for (String relType: new String[]{"Reltype with space", ":ReltypeWithCOlon", "rel-type-with-dash"}) { @@ -171,10 +275,31 @@ public void testRelationshipTypesWithSpecialCharactersShouldWork() { } } + @Test + public void testMergeRelWithNullRelTypeShouldFail() { + try { + testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, null, null, null, e) YIELD rel RETURN rel", + row -> assertTrue(row.get("rel") instanceof Relationship)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), ("Failed to invoke procedure `apoc.merge.relationship`: Caused by: java.lang.IllegalArgumentException: " + + "It is not possible to merge a `RELATIONSHIP` without a `RELATIONSHIP` type.")); + } + } - // MERGE EAGER TESTS - + @Test + public void testMergeWithEmptyRelTypeShouldFail() { + try { + testCall(db, "MERGE (s:Person{name:'Foo'}) MERGE (e:Person{name:'Bar'}) WITH s,e CALL apoc.merge.relationship(s, '', null, null, e) YIELD rel RETURN rel", + row -> assertTrue(row.get("rel") instanceof Relationship)); + fail(); + } catch (QueryExecutionException e) { + assertEquals(e.getMessage(), ("Failed to invoke procedure `apoc.merge.relationship`: Caused by: java.lang.IllegalArgumentException: " + + "It is not possible to merge a `RELATIONSHIP` without a `RELATIONSHIP` type.")); + } + } + // MERGE EAGER TESTS @Test public void testMergeEagerNode() throws Exception { testMergeEagerCommon(false); @@ -190,8 +315,8 @@ private void testMergeEagerCommon(boolean isWithStats) { testCall(db, String.format("CALL apoc.merge.%s.eager(['Person','Bastard'],{ssid:'123'}, {name:'John'})", procName), (row) -> { Node node = (Node) row.get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals(true, node.hasLabel(Label.label("Bastard"))); + assertTrue(node.hasLabel(Label.label("Person")));; + assertTrue(node.hasLabel(Label.label("Bastard"))); assertEquals("John", node.getProperty("name")); assertEquals("123", node.getProperty("ssid")); @@ -209,8 +334,8 @@ public void testMergeEagerNodeWithOnCreate() throws Exception { testCall(db, "CALL apoc.merge.node.eager(['Person','Bastard'],{ssid:'123'}, {name:'John'},{occupation:'juggler'}) YIELD node RETURN node", (row) -> { Node node = (Node) row.get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals(true, node.hasLabel(Label.label("Bastard"))); + assertTrue(node.hasLabel(Label.label("Person")));; + assertTrue(node.hasLabel(Label.label("Bastard"))); assertEquals("John", node.getProperty("name")); assertEquals("123", node.getProperty("ssid")); assertFalse(node.hasProperty("occupation")); @@ -223,8 +348,8 @@ public void testMergeEagerNodeWithOnMatch() throws Exception { testCall(db, "CALL apoc.merge.node.eager(['Person','Bastard'],{ssid:'123'}, {name:'John'}, {occupation:'juggler'}) YIELD node RETURN node", (row) -> { Node node = (Node) row.get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals(true, node.hasLabel(Label.label("Bastard"))); + assertTrue(node.hasLabel(Label.label("Person")));; + assertTrue(node.hasLabel(Label.label("Bastard"))); assertEquals("juggler", node.getProperty("occupation")); assertEquals("123", node.getProperty("ssid")); assertFalse(node.hasProperty("name")); @@ -240,8 +365,8 @@ public void testMergeEagerNodesWithOnMatchCanMergeOnMultipleMatches() throws Exc for (long index = 1; index <= 5; index++) { Node node = (Node) result.next().get("node"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals(true, node.hasLabel(Label.label("Bastard Man"))); + assertTrue(node.hasLabel(Label.label("Person")));; + assertTrue(node.hasLabel(Label.label("Bastard Man"))); assertEquals("123", node.getProperty("ssid")); assertEquals(index, node.getProperty("index")); assertEquals("juggler", node.getProperty("occupation")); @@ -272,7 +397,7 @@ private void testMergeRelsCommon(boolean isWithStats) { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Thu", rel.getProperty("since")); if (isWithStats) { @@ -287,7 +412,7 @@ private void testMergeRelsCommon(boolean isWithStats) { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Thu", rel.getProperty("since")); if (isWithStats) { @@ -320,7 +445,7 @@ public void testMergeEagerRelationshipsWithOnMatch() throws Exception { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Thu", rel.getProperty("since")); assertFalse(rel.hasProperty("until")); }); @@ -329,7 +454,7 @@ public void testMergeEagerRelationshipsWithOnMatch() throws Exception { (row) -> { Relationship rel = (Relationship) row.get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Fri", rel.getProperty("since")); }); } @@ -344,7 +469,7 @@ public void testMergeEagerRelationshipsWithOnMatchCanMergeOnMultipleMatches() th for (long index = 1; index <= 3; index++) { Relationship rel = (Relationship) result.next().get("rel"); assertEquals("KNOWS", rel.getType().name()); - assertEquals(123l, rel.getProperty("rid")); + assertEquals(123L, rel.getProperty("rid")); assertEquals("Fri", rel.getProperty("since")); } } catch (Exception e) {