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,82 @@ 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 .getKeyList () ).containsExactly (
186+ List .of ( margaret .name , margaret .id ),
187+ List .of ( rebeccaActress .name , rebeccaActress .id )
188+ );
189+ assertThat ( firstResults .isFirstPage () ).isTrue ();
190+ assertThat ( firstResults .isLastPage () ).isFalse ();
191+ assertThat ( firstResults .getPreviousPage () ).isNull ();
192+ return query .getReactiveKeyedResultList ( firstResults .getNextPage () )
193+ .thenAccept ( secondResults -> {
194+ assertThat ( secondResults .getResultList () ).containsExactly ( rebeccaSinger );
195+ assertThat ( secondResults .getKeyList () ).hasSize ( 1 );
196+ assertThat ( secondResults .getKeyList () ).containsExactly (
197+ List .of ( rebeccaSinger .name , rebeccaSinger .id )
198+ );
199+ assertThat ( secondResults .isFirstPage () ).isFalse ();
200+ assertThat ( secondResults .isLastPage () ).isTrue ();
201+ assertThat ( secondResults .getPreviousPage () ).isNotNull ();
202+ } );
203+ } );
204+ } )
205+ );
206+ }
207+
208+ @ Test
209+ public void testReactiveKeyedPaginationWithNoResults (VertxTestContext context ) {
210+ test ( context , openSession ()
211+ .thenCompose ( session -> session .createSelectionQuery (
212+ "from FamousPerson p where p.name = :name order by p.name, p.id" ,
213+ FamousPerson .class
214+ )
215+ .setParameter ( "name" , "Nobody" )
216+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( List .of (
217+ Order .asc ( FamousPerson .class , "name" ),
218+ Order .asc ( FamousPerson .class , "id" )
219+ ) ) ) )
220+ .thenAccept ( results -> {
221+ assertThat ( results .getResultList () ).isEmpty ();
222+ assertThat ( results .getKeyList () ).isEmpty ();
223+ assertThat ( results .isFirstPage () ).isTrue ();
224+ assertThat ( results .isLastPage () ).isTrue ();
225+ assertThat ( results .getNextPage () ).isNull ();
226+ assertThat ( results .getPreviousPage () ).isNull ();
227+ } )
228+ );
229+ }
230+
231+ @ Test
232+ public void testReactiveKeyedPaginationWithNativeQueryThrows (VertxTestContext context ) {
233+ test ( context , assertThrown ( UnsupportedOperationException .class , openSession ()
234+ .thenCompose ( session -> session .createNativeQuery (
235+ "select * from FamousPerson order by id" ,
236+ FamousPerson .class
237+ )
238+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( Order .asc ( FamousPerson .class , "id" ) ) ) ) )
239+ .thenAccept ( error -> assertThat ( error )
240+ .hasMessage ( "native queries do not support key-based pagination" ) )
241+ );
242+ }
243+
166244 @ Test
167245 public void testMaxResultsWithStageAndPage (VertxTestContext context ) {
168246 test ( context , enableFilter ( openSession (), FamousPerson .IS_ALIVE_FILTER )
@@ -183,6 +261,82 @@ public void testMaxResultsWithMutiny(VertxTestContext context) {
183261 );
184262 }
185263
264+ @ Test
265+ public void testReactiveKeyedPaginationWithMutiny (VertxTestContext context ) {
266+ test ( context , openMutinySession ()
267+ .chain ( session -> {
268+ var query = session .createSelectionQuery (
269+ "from FamousPerson p where p.status = :status order by p.name, p.id" ,
270+ FamousPerson .class
271+ );
272+ final var firstPage = first ( 2 ).keyedBy ( List .of (
273+ Order .asc ( FamousPerson .class , "name" ),
274+ Order .asc ( FamousPerson .class , "id" )
275+ ) );
276+ return query .setParameter ( "status" , Status .LIVING )
277+ .getReactiveKeyedResultList ( firstPage )
278+ .chain ( firstResults -> {
279+ assertThat ( firstResults .getResultList () ).containsExactly ( margaret , rebeccaActress );
280+ assertThat ( firstResults .getKeyList () ).hasSize ( 2 );
281+ assertThat ( firstResults .getKeyList () ).containsExactly (
282+ List .of ( margaret .name , margaret .id ),
283+ List .of ( rebeccaActress .name , rebeccaActress .id )
284+ );
285+ assertThat ( firstResults .isFirstPage () ).isTrue ();
286+ assertThat ( firstResults .isLastPage () ).isFalse ();
287+ assertThat ( firstResults .getPreviousPage () ).isNull ();
288+ return query .getReactiveKeyedResultList ( firstResults .getNextPage () )
289+ .invoke ( secondResults -> {
290+ assertThat ( secondResults .getResultList () ).containsExactly ( rebeccaSinger );
291+ assertThat ( secondResults .getKeyList () ).hasSize ( 1 );
292+ assertThat ( secondResults .getKeyList () ).containsExactly (
293+ List .of ( rebeccaSinger .name , rebeccaSinger .id )
294+ );
295+ assertThat ( secondResults .isFirstPage () ).isFalse ();
296+ assertThat ( secondResults .isLastPage () ).isTrue ();
297+ assertThat ( secondResults .getPreviousPage () ).isNotNull ();
298+ } );
299+ } );
300+ } )
301+ );
302+ }
303+
304+ @ Test
305+ public void testReactiveKeyedPaginationWithNoResultsMutiny (VertxTestContext context ) {
306+ test ( context , openMutinySession ().chain ( session -> session .createSelectionQuery (
307+ "from FamousPerson p where p.name = :name order by p.name, p.id" ,
308+ FamousPerson .class
309+ )
310+ .setParameter ( "name" , "Nobody" )
311+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy (
312+ List .of (
313+ Order .asc ( FamousPerson .class , "name" ),
314+ Order .asc ( FamousPerson .class , "id" )
315+ ) ) ) )
316+ .invoke ( results -> {
317+ assertThat ( results .getResultList () ).isEmpty ();
318+ assertThat ( results .getKeyList () ).isEmpty ();
319+ assertThat ( results .isFirstPage () ).isTrue ();
320+ assertThat ( results .isLastPage () ).isTrue ();
321+ assertThat ( results .getNextPage () ).isNull ();
322+ assertThat ( results .getPreviousPage () ).isNull ();
323+ } )
324+ );
325+ }
326+
327+ @ Test
328+ public void testReactiveKeyedPaginationWithNativeQueryThrowsMutiny (VertxTestContext context ) {
329+ test ( context , assertThrown ( UnsupportedOperationException .class , openMutinySession ()
330+ .chain ( session -> session .createNativeQuery (
331+ "select * from FamousPerson order by id" ,
332+ FamousPerson .class
333+ )
334+ .getReactiveKeyedResultList ( first ( 2 ).keyedBy ( Order .asc ( FamousPerson .class , "id" ) ) ) )
335+ ).invoke ( error -> assertThat ( error )
336+ .hasMessage ( "native queries do not support key-based pagination" ) )
337+ );
338+ }
339+
186340 @ Test
187341 public void testMaxResultsWithMutinyAndPage (VertxTestContext context ) {
188342 test ( context , enableFilter ( openMutinySession (), FamousPerson .IS_ALIVE_FILTER )
0 commit comments