diff --git a/integrationtests/src/test/java/org/neo4j/procedure/EagerProcedureIT.java b/integrationtests/src/test/java/org/neo4j/procedure/EagerProcedureIT.java index 5c94daec0b606..8c3fe6736b86f 100644 --- a/integrationtests/src/test/java/org/neo4j/procedure/EagerProcedureIT.java +++ b/integrationtests/src/test/java/org/neo4j/procedure/EagerProcedureIT.java @@ -34,9 +34,11 @@ import java.io.IOException; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.neo4j.procedure.Mode.READ; import static org.neo4j.procedure.Mode.WRITE; public class EagerProcedureIT @@ -79,6 +81,22 @@ public void shouldGetPropertyAccessFailureWhenStreamingToANonEagerDestructivePro res.resultAsString(); // pull all results. The second row will cause the exception } + @Test + public void shouldNotGetErrorBecauseOfNormalEagerizationWhenStreamingFromANormalReadProcedureToDestructiveCypher() + { + // When we have a simple graph (a) + int count = 10; + setUpTestData( count ); + + // Then we can run an normal read procedure and it will be eagerized by normal Cypher eagerization + Result res = db.execute( "MATCH (n) WHERE n.key = 'value' " + + "CALL org.neo4j.procedure.findNeighboursNotEagerized(n) " + + "YIELD relationship AS r, node as m " + + "DELETE r, m RETURN true" ); + assertThat( "Should get one fewer rows than original nodes", res.resultAsString(), containsString( (count - 1) + " rows" ) ); + assertThat( "The plan description should contain the 'Eager' operation", res.getExecutionPlanDescription().toString(), containsString( "+Eager" ) ); + } + @Test public void shouldGetEagerPlanForAnEagerProcedure() { @@ -101,10 +119,15 @@ public void shouldNotGetEagerPlanForANonEagerProcedure() } private void setUpTestData() + { + setUpTestData( 2 ); + } + + private void setUpTestData( int nodes ) { try ( Transaction tx = db.beginTx() ) { - createChainOfNodesWithLabelAndProperty( 2, "FOLLOWS", "User", "key", "value" ); + createChainOfNodesWithLabelAndProperty( nodes, "FOLLOWS", "User", "key", "value" ); tx.success(); } } @@ -159,12 +182,36 @@ public Output( long value ) } } + public static class NeighbourOutput + { + public final Relationship relationship; + public final Node node; + + public NeighbourOutput( Relationship relationship, Node node ) + { + this.relationship = relationship; + this.node = node; + } + } + @SuppressWarnings( "unused" ) public static class ClassWithProcedures { @Context public GraphDatabaseService db; + @Procedure( mode = READ ) + public Stream findNeighboursNotEagerized( @Name( "node" ) Node node ) + { + return findNeighbours( node ); + } + + private Stream findNeighbours( Node node ) + { + return StreamSupport.stream( node.getRelationships(Direction.OUTGOING).spliterator(), false ).map( + (relationship -> new NeighbourOutput( relationship, relationship.getOtherNode( node ) )) ); + } + @Procedure( mode = WRITE, eager = true ) public Stream deleteNeighboursEagerized( @Name( "node" ) Node node, @Name( "relation" ) String relation ) {