From b6c65812ea5c989711488202f6da75fb33eb75d6 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Wed, 23 Feb 2011 00:30:02 +0100 Subject: [PATCH] added EAGER_IGNORE_RESULT iteration mode for callback-only PathMappers --- .../neo4j/template/IterationController.java | 2 +- .../data/graph/neo4j/template/PathMapper.java | 12 +++- .../neo4j/template/PathMappingIterator.java | 6 ++ .../template/PathMappingIteratorTest.java | 68 ++++++++++++++++--- 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/IterationController.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/IterationController.java index f77c6ff11..fb1e9817a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/IterationController.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/IterationController.java @@ -6,7 +6,7 @@ package org.springframework.data.graph.neo4j.template; */ public interface IterationController { public enum IterationMode { - LAZY, EAGER, EAGER_STOP_ON_NULL + LAZY, EAGER, EAGER_STOP_ON_NULL, EAGER_IGNORE_RESULTS } IterationMode getIterationMode(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMapper.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMapper.java index 95d703eea..1acc8bf5a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMapper.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMapper.java @@ -3,6 +3,13 @@ package org.springframework.data.graph.neo4j.template; import org.neo4j.graphdb.Path; /** + * A mapper for paths as the generic return type of querying graph operations. Simple results like just nodes + * or relationships are also wrapped in a @{see Path} for uniform access. + * + * Allows iteration control when implementing @{see IterationController}. Default iteration mode is @{see IterationMode#LAZY} + * + * Inner class @{see PathMapper.WithoutResult} allows callbacks instead and comes with an eager iteration mode. + * @see Path * @author mh * @since 19.02.11 */ @@ -10,6 +17,9 @@ public interface PathMapper { T mapPath(Path path); + /** + * callback instead of mapping + */ public abstract class WithoutResult implements PathMapper, IterationController{ public abstract void eachPath(Path path); @@ -21,7 +31,7 @@ public interface PathMapper { @Override public IterationMode getIterationMode() { - return IterationMode.EAGER; + return IterationMode.EAGER_IGNORE_RESULTS; } } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMappingIterator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMappingIterator.java index b1005dae4..ffb290570 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMappingIterator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/PathMappingIterator.java @@ -27,6 +27,12 @@ public class PathMappingIterator { result.add(mapped); } return result; + + case EAGER_IGNORE_RESULTS: + for (Path path : paths) { + pathMapper.mapPath(path); + } + return null; case LAZY: return new IterableWrapper(paths) { @Override diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/PathMappingIteratorTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/PathMappingIteratorTest.java index a918c309f..f6bc32c9d 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/PathMappingIteratorTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/PathMappingIteratorTest.java @@ -5,8 +5,10 @@ import org.neo4j.graphdb.Path; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; /** @@ -15,27 +17,73 @@ import static org.mockito.Mockito.mock; */ public class PathMappingIteratorTest { + private static final int PATHS_COUNT = 3; + @Test public void lazyIteratorShouldNotCallBackBeforeUse() { - runAndCheckMode(0, 3, IterationController.IterationMode.LAZY); + runAndCheckMode(0, PATHS_COUNT, IterationController.IterationMode.LAZY); } + @Test public void eagerIteratorShouldBeCalledImmediately() { - runAndCheckMode(3, 3, IterationController.IterationMode.EAGER); + runAndCheckMode(PATHS_COUNT, PATHS_COUNT, IterationController.IterationMode.EAGER); } + @Test public void eagerStopOnNullIteratorShouldBeCalledImmediatelyAndReturnReducedResult() { runAndCheckMode(2, 2, IterationController.IterationMode.EAGER_STOP_ON_NULL); } + @Test + public void eagerStopIgnoresResultIteratorShouldBeCalledImmediatelyAndReturnNoResult() { + Iterable result = runAndCheckMode(PATHS_COUNT, PATHS_COUNT, IterationController.IterationMode.EAGER_IGNORE_RESULTS); + assertNull("no result",result); + } - private void runAndCheckMode(int countAfterMap, int countAfterIteration, IterationController.IterationMode iterationMode) { - TestPathMapper lazyMapper = new TestPathMapper(iterationMode); + @Test + public void defaultPathMapperIsLazy() { + final AtomicInteger counter=new AtomicInteger(); + PathMapper pathMapper = new PathMapper() { + + @Override + public Integer mapPath(Path path) { + return counter.incrementAndGet(); + } + }; + Iterable result = new PathMappingIterator().mapPaths(paths(), pathMapper); + assertEquals(0, counter.get()); + for (Integer integer : result) ; + assertEquals(PATHS_COUNT, counter.get()); + } + @Test + public void defaultPathCallbackIsEagerAndIgnoresResult() { + final AtomicInteger counter=new AtomicInteger(); + PathMapper.WithoutResult pathMapper = new PathMapper.WithoutResult() { + + @Override + public void eachPath(Path path) { + counter.incrementAndGet(); + } + }; + Iterable result = new PathMappingIterator().mapPaths(paths(), pathMapper); + assertEquals(PATHS_COUNT, counter.get()); + assertNull("no result",result); + assertEquals(PATHS_COUNT, counter.get()); + } + + private List paths() { Path anyPath = mock(Path.class); - List paths = Arrays.asList(anyPath, anyPath, anyPath); - Iterable result = new PathMappingIterator().mapPaths(paths, lazyMapper); - assertEquals(countAfterMap, lazyMapper.counter); - for (Integer integer : result); - assertEquals(countAfterIteration, lazyMapper.counter); + Path[] paths=new Path[3]; + Arrays.fill(paths,anyPath); + return Arrays.asList(paths); + } + + private Iterable runAndCheckMode(int countAfterMap, int countAfterIteration, IterationController.IterationMode iterationMode) { + TestPathMapper pathMapper = new TestPathMapper(iterationMode); + Iterable result = new PathMappingIterator().mapPaths(paths(), pathMapper); + assertEquals(countAfterMap, pathMapper.counter); + if (result!=null) for (Integer integer : result) ; + assertEquals(countAfterIteration, pathMapper.counter); + return result; } private static class TestPathMapper implements PathMapper, IterationController { @@ -49,7 +97,7 @@ public class PathMappingIteratorTest { @Override public Integer mapPath(Path path) { counter++; - if (counter==2) return null; + if (counter == 2) return null; return counter; }