Fluent Commerce Logo
Docs
Sign In

Dynamic Pagination

Essential knowledge

Author:

Kirill Gaiduk

Changed on:

24 June 2025

Overview

`DynamicConnectionQuery` automatically derives the Connection fields (arrays) for the primary Entity based on the `RulesetContext` and can dynamically load all connection items, with pagination handled internally.

Key points

  • Automatic Pagination`DynamicUtils.queryList` completely automates fetching paginated data from a GraphQL connection. You get a simple `Iterable`, and the library handles fetching subsequent pages in the background as you iterate.
  • Lazy Loading: The utility is highly efficient because it uses a "lazy loading" approach. It only fetches the next page of data when you have iterated through the current one.
  • POJO-Driven: You define the data you need by creating a simple POJO class. The utility dynamically builds the GraphQL query to fetch only the fields defined in your POJO.
  • Server-Side Filtering: You can pass a `Map` of parameters to `queryList` to filter the connection on the server. This is much more efficient than fetching all the data and filtering it in your rule.

Here is a collection of common scenarios for the Dynamic Pagination usage:

Query from Context usage

The simplest approach is to let the system automatically select the appropriate GraphQL query based on the entity type from the `RulesetContext`.

1@lombok.Data
2public class Fulfilment {
3    String id;
4    String ref;
5    String type;
6}
7
8// Load all Order Fulfilments with status COMPLETE
9final List<Fulfilment> fulfilments = new ArrayList<>();
10final Iterable<Fulfilment> iterable = DynamicUtils.queryList(context,
11    "fulfilments", Fulfilment.class,
12    Collections.singletonMap("fulfilments", Collections.singletonMap("status", "COMPLETE")));
13orderItemIterable.forEach(fulfilments::add);

Explanation through an Example

The rule loads the attributes associated with an order and checks if attribute with specified name exists. If the condition is met, the rule sends an event.

1package com.example.rule; 
2  
3import com.fluentcommerce.util.core.EventUtils;
4import com.fluentcommerce.util.dynamic.DynamicUtils;
5import com.fluentretail.rubix.rule.meta.*;
6import com.fluentretail.rubix.v2.context.Context;
7import com.fluentretail.rubix.v2.rule.Rule;
8import java.util.List;
9import java.util.stream.Stream;
10import java.util.stream.StreamSupport;
11
12@RuleInfo(
13        name = "IfAllFulfilmentsInState",
14        description = "If all fulfilments are in status {status}, do {eventName}",
15        accepts = { @EventInfo(entityType = "ORDER") },
16        produces = { @EventInfo(eventName = "{eventName}", entityType = "ORDER", entitySubtype = EventInfoVariables.EVENT_SUBTYPE, status = EventInfoVariables.EVENT_STATUS) }
17)
18@ParamString(name = "status", array = true, description = "List of statuses to check")
19@ParamString(name = "eventName", description = "Name of the event to send")
20public class IfAllFulfilmentsInState implements Rule {
21    @Override
22    public void run(Context context) {
23        List<String> states = context.getPropList("status", String.class);
24
25        Iterable<Fulfilment> fulfilmentIterable = DynamicUtils.queryList(context, "fulfilments",
26                Fulfilment.class, null);
27        Stream<Fulfilment> fulfilmentStream = StreamSupport.stream(fulfilmentIterable.spliterator(), false);
28
29        if(fulfilmentStream.allMatch(f -> states.contains(f.status))) {
30            EventUtils.forwardInboundEventWithNewName(context, context.getProp("eventName"));
31        }
32    }
33
34    @lombok.Data
35    public static class Fulfilment {
36        String status;
37    }
38}
1{
2  "name": "example.orders.IfAllFulfilmentsInState",
3  "props": {
4    "status": [ "COMPLETE", "CANCELLED" ],
5    "eventName": "CompleteOrder"
6  }
7}

Query from Parameter usage 

Alternatively, you can explicitly specify the GraphQL query within the method, giving you more control over the query selection. This approach allows for greater flexibility when you need to handle different types of queries within the same rule.

1@lombok.Data
2public class OrderItem {
3    String id;
4    String ref;
5    Double price;
6}
7
8//Get Order Items By Order Id
9final List<OrderItem> orderItems = new ArrayList<>();
10Iterable<OrderItem> orderItemIterable = DynamicUtils.queryList(context, 
11    "order", "items", OrderItem.class,
12    Collections.singletonMap("id", orderId));
13orderItemIterable.forEach(orderItems::add);