2323
2424import org .assertj .core .data .Index ;
2525import org .junit .jupiter .api .BeforeAll ;
26+ import org .junit .jupiter .api .DisplayName ;
27+ import org .junit .jupiter .api .Nested ;
2628import org .junit .jupiter .api .Tag ;
2729import org .junit .jupiter .api .Test ;
2830import org .neo4j .driver .Driver ;
4648import org .springframework .data .neo4j .test .Neo4jImperativeTestConfiguration ;
4749import org .springframework .data .neo4j .test .Neo4jIntegrationTest ;
4850import org .springframework .data .support .WindowIterator ;
51+ import org .springframework .test .context .junit .jupiter .SpringJUnitConfig ;
4952import org .springframework .transaction .PlatformTransactionManager ;
5053import org .springframework .transaction .annotation .EnableTransactionManagement ;
5154
@@ -57,174 +60,197 @@ class ScrollingIT {
5760
5861 @ SuppressWarnings ("unused" )
5962 private static Neo4jExtension .Neo4jConnectionSupport neo4jConnectionSupport ;
60-
61- @ BeforeAll
62- static void setupTestData (@ Autowired Driver driver , @ Autowired BookmarkCapture bookmarkCapture ) {
63- try (
64- var session = driver .session (bookmarkCapture .createSessionConfig ());
65- var transaction = session .beginTransaction ()
66- ) {
67- ScrollingEntity .createTestData (transaction );
68- transaction .commit ();
69- bookmarkCapture .seedWith (session .lastBookmarks ());
63+ @ Nested
64+ @ SpringJUnitConfig (Config .class )
65+ @ DisplayName ("Scroll with derived finder method" )
66+ class ScrollWithDerivedFinderMethod {
67+
68+ @ BeforeAll
69+ static void setupTestData (@ Autowired Driver driver , @ Autowired BookmarkCapture bookmarkCapture ) {
70+ try (
71+ var session = driver .session (bookmarkCapture .createSessionConfig ());
72+ var transaction = session .beginTransaction ()
73+ ) {
74+ ScrollingEntity .createTestData (transaction );
75+ transaction .commit ();
76+ bookmarkCapture .seedWith (session .lastBookmarks ());
77+ }
7078 }
71- }
7279
73- @ Test
74- void oneColumnSortNoScroll (@ Autowired ScrollingRepository repository ) {
80+ @ Test
81+ void oneColumnSortNoScroll (@ Autowired ScrollingRepository repository ) {
7582
76- var topN = repository .findTop4ByOrderByB ();
77- assertThat (topN )
78- .hasSize (4 )
79- .extracting (ScrollingEntity ::getA )
80- .containsExactly ("A0" , "B0" , "C0" , "D0" );
81- }
83+ var topN = repository .findTop4ByOrderByB ();
84+ assertThat (topN )
85+ .hasSize (4 )
86+ .extracting (ScrollingEntity ::getA )
87+ .containsExactly ("A0" , "B0" , "C0" , "D0" );
88+ }
8289
83- @ Test
84- void forwardWithDuplicatesManualIteration (@ Autowired ScrollingRepository repository ) {
85-
86- var duplicates = repository .findAllByAOrderById ("D0" );
87- assertThat (duplicates ).hasSize (2 );
88-
89- var window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , ScrollPosition .keyset ());
90- assertThat (window .hasNext ()).isTrue ();
91- assertThat (window )
92- .hasSize (4 )
93- .extracting (Function .identity ())
94- .satisfies (e -> assertThat (e .getId ()).isEqualTo (duplicates .get (0 ).getId ()), Index .atIndex (3 ))
95- .extracting (ScrollingEntity ::getA )
96- .containsExactly ("A0" , "B0" , "C0" , "D0" );
97-
98- window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , window .positionAt (window .size () - 1 ));
99- assertThat (window .hasNext ()).isTrue ();
100- assertThat (window )
101- .hasSize (4 )
102- .extracting (Function .identity ())
103- .satisfies (e -> assertThat (e .getId ()).isEqualTo (duplicates .get (1 ).getId ()), Index .atIndex (0 ))
104- .extracting (ScrollingEntity ::getA )
105- .containsExactly ("D0" , "E0" , "F0" , "G0" );
106-
107- window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , window .positionAt (window .size () - 1 ));
108- assertThat (window .isLast ()).isTrue ();
109- assertThat (window ).extracting (ScrollingEntity ::getA )
110- .containsExactly ("H0" , "I0" );
111- }
90+ @ Test
91+ void forwardWithDuplicatesManualIteration (@ Autowired ScrollingRepository repository ) {
92+
93+ var duplicates = repository .findAllByAOrderById ("D0" );
94+ assertThat (duplicates ).hasSize (2 );
95+
96+ var window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , ScrollPosition .keyset ());
97+ assertThat (window .hasNext ()).isTrue ();
98+ assertThat (window )
99+ .hasSize (4 )
100+ .extracting (Function .identity ())
101+ .satisfies (e -> assertThat (e .getId ()).isEqualTo (duplicates .get (0 ).getId ()), Index .atIndex (3 ))
102+ .extracting (ScrollingEntity ::getA )
103+ .containsExactly ("A0" , "B0" , "C0" , "D0" );
104+
105+ window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , window .positionAt (window .size () - 1 ));
106+ assertThat (window .hasNext ()).isTrue ();
107+ assertThat (window )
108+ .hasSize (4 )
109+ .extracting (Function .identity ())
110+ .satisfies (e -> assertThat (e .getId ()).isEqualTo (duplicates .get (1 ).getId ()), Index .atIndex (0 ))
111+ .extracting (ScrollingEntity ::getA )
112+ .containsExactly ("D0" , "E0" , "F0" , "G0" );
113+
114+ window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , window .positionAt (window .size () - 1 ));
115+ assertThat (window .isLast ()).isTrue ();
116+ assertThat (window ).extracting (ScrollingEntity ::getA )
117+ .containsExactly ("H0" , "I0" );
118+ }
112119
113- @ Test
114- @ Tag ("GH-2726" )
115- void forwardWithFluentQueryByExample (@ Autowired ScrollingRepository scrollingRepository ) {
116- ScrollingEntity scrollingEntity = new ScrollingEntity ();
117- Example <ScrollingEntity > example = Example .of (scrollingEntity , ExampleMatcher .matchingAll ().withIgnoreNullValues ());
118-
119- var window = scrollingRepository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (ScrollPosition .keyset ()));
120- assertThat (window .hasNext ()).isTrue ();
121- assertThat (window )
122- .hasSize (4 )
123- .extracting (ScrollingEntity ::getA )
124- .containsExactly ("A0" , "B0" , "C0" , "D0" );
125-
126- ScrollPosition newPosition = ScrollPosition .forward (((KeysetScrollPosition ) window .positionAt (window .size () - 1 )).getKeys ());
127- window = scrollingRepository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (newPosition ));
128- assertThat (window )
129- .hasSize (4 )
130- .extracting (ScrollingEntity ::getA )
131- .containsExactly ("D0" , "E0" , "F0" , "G0" );
132-
133- window = scrollingRepository .findTop4By (ScrollingEntity .SORT_BY_C , window .positionAt (window .size () - 1 ));
134- assertThat (window .isLast ()).isTrue ();
135- assertThat (window ).extracting (ScrollingEntity ::getA )
136- .containsExactly ("H0" , "I0" );
137- }
120+ @ Test
121+ void forwardWithDuplicatesIteratorIteration (@ Autowired ScrollingRepository repository ) {
138122
139- @ Test
140- void forwardWithDuplicatesIteratorIteration (@ Autowired ScrollingRepository repository ) {
123+ var it = WindowIterator .of (pos -> repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos ))
124+ .startingAt (ScrollPosition .keyset ());
125+ var content = new ArrayList <ScrollingEntity >();
126+ while (it .hasNext ()) {
127+ var next = it .next ();
128+ content .add (next );
129+ }
141130
142- var it = WindowIterator .of (pos -> repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos ))
143- .startingAt (ScrollPosition .keyset ());
144- var content = new ArrayList <ScrollingEntity >();
145- while (it .hasNext ()) {
146- var next = it .next ();
147- content .add (next );
131+ assertThat (content ).hasSize (10 );
132+ assertThat (content .stream ().map (ScrollingEntity ::getId )
133+ .distinct ().toList ()).hasSize (10 );
148134 }
149135
150- assertThat (content ).hasSize (10 );
151- assertThat (content .stream ().map (ScrollingEntity ::getId )
152- .distinct ().toList ()).hasSize (10 );
136+ @ Test
137+ void backwardWithDuplicatesManualIteration (@ Autowired ScrollingRepository repository ) {
138+
139+ // Recreate the last position
140+ var last = repository .findFirstByA ("I0" );
141+ var keys = Map .of (
142+ "foobar" , Values .value (last .getA ()),
143+ "b" , Values .value (last .getB ()),
144+ Constants .NAME_OF_ADDITIONAL_SORT , Values .value (last .getId ().toString ())
145+ );
146+
147+ var duplicates = repository .findAllByAOrderById ("D0" );
148+ assertThat (duplicates ).hasSize (2 );
149+
150+ var window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , ScrollPosition .backward (keys ));
151+ assertThat (window .hasNext ()).isTrue ();
152+ assertThat (window )
153+ .hasSize (4 )
154+ .extracting (ScrollingEntity ::getA )
155+ .containsExactly ("F0" , "G0" , "H0" , "I0" );
156+
157+ var pos = ((KeysetScrollPosition ) window .positionAt (0 ));
158+ pos = ScrollPosition .backward (pos .getKeys ());
159+ window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos );
160+ assertThat (window .hasNext ()).isTrue ();
161+ assertThat (window )
162+ .hasSize (4 )
163+ .extracting (Function .identity ())
164+ .extracting (ScrollingEntity ::getA )
165+ .containsExactly ("C0" , "D0" , "D0" , "E0" );
166+
167+ pos = ((KeysetScrollPosition ) window .positionAt (0 ));
168+ pos = ScrollPosition .backward (pos .getKeys ());
169+ window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos );
170+ assertThat (window .isLast ()).isTrue ();
171+ assertThat (window ).extracting (ScrollingEntity ::getA )
172+ .containsExactly ("A0" , "B0" );
173+ }
153174 }
154175
155- @ Test
156- void backwardWithDuplicatesManualIteration (@ Autowired ScrollingRepository repository ) {
157-
158- // Recreate the last position
159- var last = repository .findFirstByA ("I0" );
160- var keys = Map .of (
161- "foobar" , Values .value (last .getA ()),
162- "b" , Values .value (last .getB ()),
163- Constants .NAME_OF_ADDITIONAL_SORT , Values .value (last .getId ().toString ())
164- );
165-
166- var duplicates = repository .findAllByAOrderById ("D0" );
167- assertThat (duplicates ).hasSize (2 );
168-
169- var window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , ScrollPosition .backward (keys ));
170- assertThat (window .hasNext ()).isTrue ();
171- assertThat (window )
172- .hasSize (4 )
173- .extracting (ScrollingEntity ::getA )
174- .containsExactly ("F0" , "G0" , "H0" , "I0" );
175-
176- var pos = ((KeysetScrollPosition ) window .positionAt (0 ));
177- pos = ScrollPosition .backward (pos .getKeys ());
178- window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos );
179- assertThat (window .hasNext ()).isTrue ();
180- assertThat (window )
181- .hasSize (4 )
182- .extracting (Function .identity ())
183- .extracting (ScrollingEntity ::getA )
184- .containsExactly ("C0" , "D0" , "D0" , "E0" );
185-
186- pos = ((KeysetScrollPosition ) window .positionAt (0 ));
187- pos = ScrollPosition .backward (pos .getKeys ());
188- window = repository .findTop4By (ScrollingEntity .SORT_BY_B_AND_A , pos );
189- assertThat (window .isLast ()).isTrue ();
190- assertThat (window ).extracting (ScrollingEntity ::getA )
191- .containsExactly ("A0" , "B0" );
192- }
176+ @ Nested
177+ @ SpringJUnitConfig (Config .class )
178+ @ DisplayName ("ScrollWithExampleApi" )
179+ class ScrollWithExampleApi {
180+
181+ @ BeforeAll
182+ static void setupTestData (@ Autowired Driver driver , @ Autowired BookmarkCapture bookmarkCapture ) {
183+ try (
184+ var session = driver .session (bookmarkCapture .createSessionConfig ());
185+ var transaction = session .beginTransaction ()
186+ ) {
187+ ScrollingEntity .createTestDataWithoutDuplicates (transaction );
188+ transaction .commit ();
189+ bookmarkCapture .seedWith (session .lastBookmarks ());
190+ }
191+ }
193192
194- @ Test
195- void backwardWithFluentQueryByExample (@ Autowired ScrollingRepository repository ) {
196-
197- ScrollingEntity scrollingEntity = new ScrollingEntity ();
198- Example <ScrollingEntity > example = Example .of (scrollingEntity , ExampleMatcher .matchingAll ().withIgnoreNullValues ());
199-
200- var last = repository .findFirstByA ("I0" );
201- var keys = Map .of (
202- "c" , last .getC (),
203- Constants .NAME_OF_ADDITIONAL_SORT , Values .value (last .getId ().toString ())
204- );
205-
206- var window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (ScrollPosition .backward (keys )));
207- assertThat (window .hasNext ()).isTrue ();
208- assertThat (window )
209- .hasSize (4 )
210- .extracting (ScrollingEntity ::getA )
211- .containsExactly ("F0" , "G0" , "H0" , "I0" );
212-
213- var pos = ((KeysetScrollPosition ) window .positionAt (0 ));
214- var nextPos = ScrollPosition .backward (pos .getKeys ());
215- window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (nextPos ));
216- assertThat (window .hasNext ()).isTrue ();
217- assertThat (window )
218- .hasSize (4 )
219- .extracting (Function .identity ())
220- .extracting (ScrollingEntity ::getA )
221- .containsExactly ("C0" , "D0" , "D0" , "E0" );
222-
223- var nextNextPos = ScrollPosition .backward (((KeysetScrollPosition ) window .positionAt (0 )).getKeys ());
224- window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (nextNextPos ));
225- assertThat (window .isLast ()).isTrue ();
226- assertThat (window ).extracting (ScrollingEntity ::getA )
227- .containsExactly ("A0" , "B0" );
193+ @ Test
194+ @ Tag ("GH-2726" )
195+ void forwardWithFluentQueryByExample (@ Autowired ScrollingRepository scrollingRepository ) {
196+ ScrollingEntity scrollingEntity = new ScrollingEntity ();
197+ Example <ScrollingEntity > example = Example .of (scrollingEntity , ExampleMatcher .matchingAll ().withIgnoreNullValues ());
198+
199+ var window = scrollingRepository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (ScrollPosition .keyset ()));
200+ assertThat (window .hasNext ()).isTrue ();
201+ assertThat (window )
202+ .hasSize (4 )
203+ .extracting (ScrollingEntity ::getA )
204+ .containsExactly ("A0" , "B0" , "C0" , "D0" );
205+
206+ ScrollPosition newPosition = ScrollPosition .forward (((KeysetScrollPosition ) window .positionAt (window .size () - 1 )).getKeys ());
207+ window = scrollingRepository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (newPosition ));
208+ assertThat (window )
209+ .hasSize (4 )
210+ .extracting (ScrollingEntity ::getA )
211+ .containsExactly ("E0" , "F0" , "G0" , "H0" );
212+
213+ window = scrollingRepository .findTop4By (ScrollingEntity .SORT_BY_C , window .positionAt (window .size () - 1 ));
214+ assertThat (window .isLast ()).isTrue ();
215+ assertThat (window ).extracting (ScrollingEntity ::getA )
216+ .containsExactly ("I0" );
217+ }
218+
219+ @ Test
220+ void backwardWithFluentQueryByExample (@ Autowired ScrollingRepository repository ) {
221+
222+ ScrollingEntity scrollingEntity = new ScrollingEntity ();
223+ Example <ScrollingEntity > example = Example .of (scrollingEntity , ExampleMatcher .matchingAll ().withIgnoreNullValues ());
224+
225+ var last = repository .findFirstByA ("I0" );
226+ var keys = Map .of (
227+ "c" , last .getC (),
228+ Constants .NAME_OF_ADDITIONAL_SORT , Values .value (last .getId ().toString ())
229+ );
230+
231+ var window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (ScrollPosition .backward (keys )));
232+ assertThat (window .hasNext ()).isTrue ();
233+ assertThat (window )
234+ .hasSize (4 )
235+ .extracting (ScrollingEntity ::getA )
236+ .containsExactly ("F0" , "G0" , "H0" , "I0" );
237+
238+ var pos = ((KeysetScrollPosition ) window .positionAt (0 ));
239+ var nextPos = ScrollPosition .backward (pos .getKeys ());
240+ window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (nextPos ));
241+ assertThat (window .hasNext ()).isTrue ();
242+ assertThat (window )
243+ .hasSize (4 )
244+ .extracting (Function .identity ())
245+ .extracting (ScrollingEntity ::getA )
246+ .containsExactly ("B0" , "C0" , "D0" , "E0" );
247+
248+ var nextNextPos = ScrollPosition .backward (((KeysetScrollPosition ) window .positionAt (0 )).getKeys ());
249+ window = repository .findBy (example , q -> q .sortBy (ScrollingEntity .SORT_BY_C ).limit (4 ).scroll (nextNextPos ));
250+ assertThat (window .isLast ()).isTrue ();
251+ assertThat (window ).extracting (ScrollingEntity ::getA )
252+ .containsExactly ("A0" );
253+ }
228254 }
229255
230256 @ Configuration
0 commit comments