4545import org .springframework .data .util .TypeInformation ;
4646import org .springframework .graphql .data .GraphQlArgumentBinder ;
4747import org .springframework .graphql .data .GraphQlRepository ;
48+ import org .springframework .graphql .data .pagination .CursorEncoder ;
4849import org .springframework .graphql .data .pagination .CursorStrategy ;
4950import org .springframework .graphql .data .query .AutoRegistrationRuntimeWiringConfigurer .DataFetcherFactory ;
5051import org .springframework .graphql .execution .RuntimeWiringConfigurer ;
@@ -165,6 +166,7 @@ protected Collection<String> buildPropertyPaths(DataFetchingFieldSelectionSet se
165166 }
166167
167168 protected ScrollSubrange buildScrollSubrange (DataFetchingEnvironment environment ) {
169+ Assert .state (this .cursorStrategy != null , "Expected CursorStrategy" );
168170 return RepositoryUtils .buildScrollSubrange (environment , this .cursorStrategy );
169171 }
170172
@@ -234,7 +236,10 @@ public static RuntimeWiringConfigurer autoRegistrationConfigurer(
234236 for (QueryByExampleExecutor <?> executor : executors ) {
235237 String typeName = RepositoryUtils .getGraphQlTypeName (executor );
236238 if (typeName != null ) {
237- Builder <?, ?> builder = customize (executor , builder (executor ));
239+ Builder <?, ?> builder = customize (executor , builder (executor )
240+ .cursorStrategy (cursorStrategy )
241+ .defaultScrollSubrange (defaultScrollSubrange ));
242+
238243 factories .put (typeName , new DataFetcherFactory () {
239244 @ Override
240245 public DataFetcher <?> single () {
@@ -248,7 +253,7 @@ public DataFetcher<?> many() {
248253
249254 @ Override
250255 public DataFetcher <?> scrollable () {
251- return builder .scrollable (cursorStrategy , defaultScrollSubrange );
256+ return builder .scrollable ();
252257 }
253258 });
254259 }
@@ -257,7 +262,10 @@ public DataFetcher<?> scrollable() {
257262 for (ReactiveQueryByExampleExecutor <?> executor : reactiveExecutors ) {
258263 String typeName = RepositoryUtils .getGraphQlTypeName (executor );
259264 if (typeName != null ) {
260- ReactiveBuilder <?, ?> builder = customize (executor , builder (executor ));
265+ ReactiveBuilder <?, ?> builder = customize (executor , builder (executor )
266+ .cursorStrategy (cursorStrategy )
267+ .defaultScrollSubrange (defaultScrollSubrange ));
268+
261269 factories .put (typeName , new DataFetcherFactory () {
262270 @ Override
263271 public DataFetcher <?> single () {
@@ -271,7 +279,7 @@ public DataFetcher<?> many() {
271279
272280 @ Override
273281 public DataFetcher <?> scrollable () {
274- return builder .scrollable (cursorStrategy , defaultScrollSubrange );
282+ return builder .scrollable ();
275283 }
276284 });
277285 }
@@ -356,17 +364,28 @@ public static class Builder<T, R> {
356364
357365 private final Class <R > resultType ;
358366
367+ @ Nullable
368+ private final CursorStrategy <ScrollPosition > cursorStrategy ;
369+
370+ @ Nullable
371+ private final ScrollSubrange defaultSubrange ;
372+
359373 private final Sort sort ;
360374
361375 @ SuppressWarnings ("unchecked" )
362376 Builder (QueryByExampleExecutor <T > executor , Class <R > domainType ) {
363- this (executor , TypeInformation .of ((Class <T >) domainType ), domainType , Sort .unsorted ());
377+ this (executor , TypeInformation .of ((Class <T >) domainType ), domainType , null , null , Sort .unsorted ());
364378 }
365379
366- Builder (QueryByExampleExecutor <T > executor , TypeInformation <T > domainType , Class <R > resultType , Sort sort ) {
380+ Builder (QueryByExampleExecutor <T > executor , TypeInformation <T > domainType , Class <R > resultType ,
381+ @ Nullable CursorStrategy <ScrollPosition > cursorStrategy , @ Nullable ScrollSubrange defaultSubrange ,
382+ Sort sort ) {
383+
367384 this .executor = executor ;
368385 this .domainType = domainType ;
369386 this .resultType = resultType ;
387+ this .cursorStrategy = cursorStrategy ;
388+ this .defaultSubrange = defaultSubrange ;
370389 this .sort = sort ;
371390 }
372391
@@ -381,7 +400,36 @@ public static class Builder<T, R> {
381400 */
382401 public <P > Builder <T , P > projectAs (Class <P > projectionType ) {
383402 Assert .notNull (projectionType , "Projection type must not be null" );
384- return new Builder <>(this .executor , this .domainType , projectionType , this .sort );
403+ return new Builder <>(this .executor , this .domainType ,
404+ projectionType , this .cursorStrategy , this .defaultSubrange , this .sort );
405+ }
406+
407+ /**
408+ * Configure strategy for decoding a cursor from a paginated request.
409+ * <p>By default, this is {@link ScrollPositionCursorStrategy} with
410+ * {@link CursorEncoder#base64()} encoding.
411+ * @param cursorStrategy the strategy to use
412+ * @return a new {@link Builder} instance with all previously configured
413+ * options and {@code Sort} applied
414+ * @since 1.2
415+ */
416+ public Builder <T , R > cursorStrategy (@ Nullable CursorStrategy <ScrollPosition > cursorStrategy ) {
417+ return new Builder <>(this .executor , this .domainType ,
418+ this .resultType , cursorStrategy , this .defaultSubrange , this .sort );
419+ }
420+
421+ /**
422+ * Configure a {@link ScrollSubrange} to use when a paginated request does
423+ * not specify a cursor and/or a count of items.
424+ * <p>By default, this is {@link OffsetScrollPosition#initial()} with a
425+ * count of 20.
426+ * @return a new {@link Builder} instance with all previously configured
427+ * options and {@code Sort} applied
428+ * @since 1.2
429+ */
430+ public Builder <T , R > defaultScrollSubrange (@ Nullable ScrollSubrange defaultSubrange ) {
431+ return new Builder <>(this .executor , this .domainType ,
432+ this .resultType , this .cursorStrategy , defaultSubrange , this .sort );
385433 }
386434
387435 /**
@@ -392,7 +440,8 @@ public <P> Builder<T, P> projectAs(Class<P> projectionType) {
392440 */
393441 public Builder <T , R > sortBy (Sort sort ) {
394442 Assert .notNull (sort , "Sort must not be null" );
395- return new Builder <>(this .executor , this .domainType , this .resultType , sort );
443+ return new Builder <>(this .executor , this .domainType ,
444+ this .resultType , this .cursorStrategy , this .defaultSubrange , sort );
396445 }
397446
398447 /**
@@ -414,11 +463,12 @@ public DataFetcher<Iterable<R>> many() {
414463 * {@link org.springframework.data.domain.Window}.
415464 * @since 1.2
416465 */
417- public DataFetcher <Iterable <R >> scrollable (
418- CursorStrategy <ScrollPosition > cursorStrategy , ScrollSubrange defaultScrollSubrange ) {
419-
466+ public DataFetcher <Iterable <R >> scrollable () {
420467 return new ScrollableEntityFetcher <>(
421- this .executor , this .domainType , this .resultType , cursorStrategy , defaultScrollSubrange , this .sort );
468+ this .executor , this .domainType , this .resultType ,
469+ (this .cursorStrategy != null ? this .cursorStrategy : RepositoryUtils .defaultCursorStrategy ()),
470+ (this .defaultSubrange != null ? this .defaultSubrange : RepositoryUtils .defaultScrollSubrange ()),
471+ this .sort );
422472 }
423473
424474 }
@@ -460,20 +510,29 @@ public static class ReactiveBuilder<T, R> {
460510
461511 private final Class <R > resultType ;
462512
513+ @ Nullable
514+ private final CursorStrategy <ScrollPosition > cursorStrategy ;
515+
516+ @ Nullable
517+ private final ScrollSubrange defaultSubrange ;
518+
463519 private final Sort sort ;
464520
465521 @ SuppressWarnings ("unchecked" )
466522 ReactiveBuilder (ReactiveQueryByExampleExecutor <T > executor , Class <R > domainType ) {
467- this (executor , TypeInformation .of ((Class <T >) domainType ), domainType , Sort .unsorted ());
523+ this (executor , TypeInformation .of ((Class <T >) domainType ), domainType , null , null , Sort .unsorted ());
468524 }
469525
470526 ReactiveBuilder (
471- ReactiveQueryByExampleExecutor <T > executor , TypeInformation <T > domainType ,
472- Class <R > resultType , Sort sort ) {
527+ ReactiveQueryByExampleExecutor <T > executor , TypeInformation <T > domainType , Class <R > resultType ,
528+ @ Nullable CursorStrategy <ScrollPosition > cursorStrategy , @ Nullable ScrollSubrange defaultSubrange ,
529+ Sort sort ) {
473530
474531 this .executor = executor ;
475532 this .domainType = domainType ;
476533 this .resultType = resultType ;
534+ this .cursorStrategy = cursorStrategy ;
535+ this .defaultSubrange = defaultSubrange ;
477536 this .sort = sort ;
478537 }
479538
@@ -488,7 +547,36 @@ public static class ReactiveBuilder<T, R> {
488547 */
489548 public <P > ReactiveBuilder <T , P > projectAs (Class <P > projectionType ) {
490549 Assert .notNull (projectionType , "Projection type must not be null" );
491- return new ReactiveBuilder <>(this .executor , this .domainType , projectionType , this .sort );
550+ return new ReactiveBuilder <>(this .executor , this .domainType ,
551+ projectionType , this .cursorStrategy , this .defaultSubrange , this .sort );
552+ }
553+
554+ /**
555+ * Configure strategy for decoding a cursor from a paginated request.
556+ * <p>By default, this is {@link ScrollPositionCursorStrategy} with
557+ * {@link CursorEncoder#base64()} encoding.
558+ * @param cursorStrategy the strategy to use
559+ * @return a new {@link Builder} instance with all previously configured
560+ * options and {@code Sort} applied
561+ * @since 1.2
562+ */
563+ public ReactiveBuilder <T , R > cursorStrategy (@ Nullable CursorStrategy <ScrollPosition > cursorStrategy ) {
564+ return new ReactiveBuilder <>(this .executor , this .domainType ,
565+ this .resultType , cursorStrategy , this .defaultSubrange , this .sort );
566+ }
567+
568+ /**
569+ * Configure a {@link ScrollSubrange} to use when a paginated request does
570+ * not specify a cursor and/or a count of items.
571+ * <p>By default, this is {@link OffsetScrollPosition#initial()} with a
572+ * count of 20.
573+ * @return a new {@link Builder} instance with all previously configured
574+ * options and {@code Sort} applied
575+ * @since 1.2
576+ */
577+ public ReactiveBuilder <T , R > defaultScrollSubrange (@ Nullable ScrollSubrange defaultSubrange ) {
578+ return new ReactiveBuilder <>(this .executor , this .domainType ,
579+ this .resultType , this .cursorStrategy , defaultSubrange , this .sort );
492580 }
493581
494582 /**
@@ -499,7 +587,8 @@ public <P> ReactiveBuilder<T, P> projectAs(Class<P> projectionType) {
499587 */
500588 public ReactiveBuilder <T , R > sortBy (Sort sort ) {
501589 Assert .notNull (sort , "Sort must not be null" );
502- return new ReactiveBuilder <>(this .executor , this .domainType , this .resultType , sort );
590+ return new ReactiveBuilder <>(this .executor , this .domainType ,
591+ this .resultType , this .cursorStrategy , this .defaultSubrange , sort );
503592 }
504593
505594 /**
@@ -521,11 +610,12 @@ public DataFetcher<Flux<R>> many() {
521610 * {@link org.springframework.data.domain.Window}.
522611 * @since 1.2
523612 */
524- public DataFetcher <Mono <Iterable <R >>> scrollable (
525- CursorStrategy <ScrollPosition > cursorStrategy , ScrollSubrange defaultScrollSubrange ) {
526-
613+ public DataFetcher <Mono <Iterable <R >>> scrollable () {
527614 return new ReactiveScrollableEntityFetcher <>(
528- this .executor , this .domainType , this .resultType , cursorStrategy , defaultScrollSubrange , this .sort );
615+ this .executor , this .domainType , this .resultType ,
616+ (this .cursorStrategy != null ? this .cursorStrategy : RepositoryUtils .defaultCursorStrategy ()),
617+ (this .defaultSubrange != null ? this .defaultSubrange : RepositoryUtils .defaultScrollSubrange ()),
618+ this .sort );
529619 }
530620
531621 }
0 commit comments