99import java .util .Objects ;
1010import java .util .concurrent .CompletionStage ;
1111
12+ import org .hibernate .query .Order ;
1213import org .hibernate .annotations .Filter ;
1314import org .hibernate .annotations .FilterDef ;
1415import org .hibernate .annotations .ParamDef ;
3435import static org .hibernate .query .Page .first ;
3536import static org .hibernate .query .Page .page ;
3637import static org .hibernate .reactive .containers .DatabaseConfiguration .DBType .DB2 ;
38+ import static org .hibernate .reactive .testing .ReactiveAssertions .assertThrown ;
3739
3840/**
3941 * Test the combination of filters, max results, first result, and {@link org.hibernate.query.Page}.
@@ -163,6 +165,75 @@ public void testMaxResultsWithStage(VertxTestContext context) {
163165 );
164166 }
165167
168+ @ Test
169+ public void testReactiveKeyedPagination (VertxTestContext context ) {
170+ test ( context , openSession ()
171+ .thenCompose ( session -> {
172+ var query = session .createSelectionQuery (
173+ "from FamousPerson p where p.status = :status order by p.name, p.id" ,
174+ FamousPerson .class
175+ );
176+ final var firstPage = first ( 2 ).keyedBy ( List .of (
177+ Order .asc ( FamousPerson .class , "name" ),
178+ Order .asc ( FamousPerson .class , "id" )
179+ ) );
180+ return query .setParameter ( "status" , Status .LIVING )
181+ .getReactiveKeyedResultList ( firstPage )
182+ .thenCompose ( firstResults -> {
183+ assertThat ( firstResults .getResultList () ).containsExactly ( margaret , rebeccaActress );
184+ assertThat ( firstResults .getKeyList () ).hasSize ( 2 );
185+ assertThat ( firstResults .isFirstPage () ).isTrue ();
186+ assertThat ( firstResults .isLastPage () ).isFalse ();
187+ assertThat ( firstResults .getPreviousPage () ).isNull ();
188+ return query .getReactiveKeyedResultList ( firstResults .getNextPage () )
189+ .thenAccept ( secondResults -> {
190+ assertThat ( secondResults .getResultList () ).containsExactly ( rebeccaSinger );
191+ assertThat ( secondResults .getKeyList () ).hasSize ( 1 );
192+ assertThat ( secondResults .isFirstPage () ).isFalse ();
193+ assertThat ( secondResults .isLastPage () ).isTrue ();
194+ assertThat ( secondResults .getPreviousPage () ).isNotNull ();
195+ } );
196+ } );
197+ } )
198+ );
199+ }
200+
201+ @ Test
202+ public void testReactiveKeyedPaginationWithNoResults (VertxTestContext context ) {
203+ test ( context , openSession ()
204+ .thenCompose ( session -> session .createSelectionQuery (
205+ "from FamousPerson p where p.name = :name order by p.name, p.id" ,
206+ FamousPerson .class
207+ )
208+ .setParameter ( "name" , "Nobody" )
209+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( List .of (
210+ Order .asc ( FamousPerson .class , "name" ),
211+ Order .asc ( FamousPerson .class , "id" )
212+ ) ) ) )
213+ .thenAccept ( results -> {
214+ assertThat ( results .getResultList () ).isEmpty ();
215+ assertThat ( results .getKeyList () ).isEmpty ();
216+ assertThat ( results .isFirstPage () ).isTrue ();
217+ assertThat ( results .isLastPage () ).isTrue ();
218+ assertThat ( results .getNextPage () ).isNull ();
219+ assertThat ( results .getPreviousPage () ).isNull ();
220+ } )
221+ );
222+ }
223+
224+ @ Test
225+ public void testReactiveKeyedPaginationWithNativeQueryThrows (VertxTestContext context ) {
226+ test ( context , assertThrown ( UnsupportedOperationException .class , openSession ()
227+ .thenCompose ( session -> session .createNativeQuery (
228+ "select * from FamousPerson order by id" ,
229+ FamousPerson .class
230+ )
231+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( Order .asc ( FamousPerson .class , "id" ) ) ) ) )
232+ .thenAccept ( error -> assertThat ( error )
233+ .hasMessage ( "native queries do not support key-based pagination" ) )
234+ );
235+ }
236+
166237 @ Test
167238 public void testMaxResultsWithStageAndPage (VertxTestContext context ) {
168239 test ( context , enableFilter ( openSession (), FamousPerson .IS_ALIVE_FILTER )
@@ -183,6 +254,77 @@ public void testMaxResultsWithMutiny(VertxTestContext context) {
183254 );
184255 }
185256
257+ @ Test
258+ public void testReactiveKeyedPaginationWithMutiny (VertxTestContext context ) {
259+ test ( context , openMutinySession ()
260+ .chain ( session -> {
261+ var query = session .createSelectionQuery (
262+ "from FamousPerson p where p.status = :status order by p.name, p.id" ,
263+ FamousPerson .class
264+ );
265+ final var firstPage = first ( 2 ).keyedBy ( List .of (
266+ Order .asc ( FamousPerson .class , "name" ),
267+ Order .asc ( FamousPerson .class , "id" )
268+ ) );
269+ return Uni .createFrom ().completionStage ( query .setParameter ( "status" , Status .LIVING )
270+ .getReactiveKeyedResultList ( firstPage ) )
271+ .chain ( firstResults -> {
272+ assertThat ( firstResults .getResultList () ).containsExactly ( margaret , rebeccaActress );
273+ assertThat ( firstResults .getKeyList () ).hasSize ( 2 );
274+ assertThat ( firstResults .isFirstPage () ).isTrue ();
275+ assertThat ( firstResults .isLastPage () ).isFalse ();
276+ assertThat ( firstResults .getPreviousPage () ).isNull ();
277+ return Uni .createFrom ().completionStage ( query .getReactiveKeyedResultList ( firstResults .getNextPage () ) )
278+ .invoke ( secondResults -> {
279+ assertThat ( secondResults .getResultList () ).containsExactly ( rebeccaSinger );
280+ assertThat ( secondResults .getKeyList () ).hasSize ( 1 );
281+ assertThat ( secondResults .isFirstPage () ).isFalse ();
282+ assertThat ( secondResults .isLastPage () ).isTrue ();
283+ assertThat ( secondResults .getPreviousPage () ).isNotNull ();
284+ } );
285+ } );
286+ } )
287+ );
288+ }
289+
290+ @ Test
291+ public void testReactiveKeyedPaginationWithNoResultsMutiny (VertxTestContext context ) {
292+ test ( context , openMutinySession ().chain ( session -> Uni .createFrom ()
293+ .completionStage (
294+ session .createSelectionQuery (
295+ "from FamousPerson p where p.name = :name order by p.name, p.id" ,
296+ FamousPerson .class
297+ )
298+ .setParameter ( "name" , "Nobody" )
299+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy (
300+ List .of (
301+ Order .asc ( FamousPerson .class , "name" ),
302+ Order .asc ( FamousPerson .class , "id" )
303+ ) ) ) ) )
304+ .invoke ( results -> {
305+ assertThat ( results .getResultList () ).isEmpty ();
306+ assertThat ( results .getKeyList () ).isEmpty ();
307+ assertThat ( results .isFirstPage () ).isTrue ();
308+ assertThat ( results .isLastPage () ).isTrue ();
309+ assertThat ( results .getNextPage () ).isNull ();
310+ assertThat ( results .getPreviousPage () ).isNull ();
311+ } )
312+ );
313+ }
314+
315+ @ Test
316+ public void testReactiveKeyedPaginationWithNativeQueryThrowsMutiny (VertxTestContext context ) {
317+ test ( context , assertThrown ( UnsupportedOperationException .class , openMutinySession ()
318+ .chain ( session -> Uni .createFrom ().completionStage ( session .createNativeQuery (
319+ "select * from FamousPerson order by id" ,
320+ FamousPerson .class
321+ )
322+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( Order .asc ( FamousPerson .class , "id" ) ) ) ) ) )
323+ .invoke ( error -> assertThat ( error )
324+ .hasMessage ( "native queries do not support key-based pagination" ) )
325+ );
326+ }
327+
186328 @ Test
187329 public void testMaxResultsWithMutinyAndPage (VertxTestContext context ) {
188330 test ( context , enableFilter ( openMutinySession (), FamousPerson .IS_ALIVE_FILTER )
0 commit comments