Result Set Management (RSM)
Result Set Management (RSM), defined in XEP-0059, provides a standardized way to paginate through large result sets. It's used by many XMPP extensions like MAM, Inbox, and PubSub to handle pagination efficiently.
Overview
RSM enables:
- Paginating through large result sets
- Requesting specific pages
- Getting result set counts
- Navigating forward and backward through results
Basic Pagination
Limit the number of results:
final rsm = RSM.limitNumberOfItems(25);
// Use with MAM
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Requesting the Last Page
Request the last page of results:
final rsm = RSM.requestLastPage(25);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Paginating Backwards
Page backwards through results:
final rsm = RSM.pageBackwards(25);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Paginating with Cursors
Use after to continue from a specific point:
final rsm = RSMSet(
max: 25,
after: 'last-item-id',
);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Use before to get items before a specific point:
final rsm = RSMSet(
max: 25,
before: 'first-item-id',
);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Getting Item Count
Get the total count of items without retrieving them:
final rsm = RSM.getItemCount();
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
// Check the count in the result
if (result.payload is MAMFin) {
final fin = result.payload as MAMFin;
print('Total items: ${fin.count}');
}
Retrieving Pages Out of Order
Retrieve a specific page by index:
final rsm = RSM.retrievePageOutOfOrder(5, max: 25);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
Complete Pagination Example
Here's a complete example of paginating through all results:
Future<void> getAllMessages() async {
String? lastItem;
int page = 0;
do {
final rsm = RSMSet(
max: 25,
after: lastItem,
);
final result = await MAM.queryArchive(
whixp.transport,
pagination: rsm,
);
final fin = result.payload is MAMFin
? result.payload as MAMFin
: null;
if (fin == null) break;
print('Page ${++page}: ${fin.complete ? "Complete" : "More available"}');
// Process results...
// Handle incoming MAM results in message handler
lastItem = fin.last?.lastItem;
} while (lastItem != null && !fin.complete);
}
Processing RSM Results
RSM results are typically included in the response:
// With MAM
if (result.payload is MAMFin) {
final fin = result.payload as MAMFin;
print('First item: ${fin.first}');
print('Last item: ${fin.last}');
print('Count: ${fin.count}');
print('Complete: ${fin.complete}');
// Use fin.last.lastItem for next page
final nextPage = fin.last?.lastItem;
}
// With Inbox
if (result.payload is InboxFin) {
final fin = result.payload as InboxFin;
print('Last item: ${fin.last?.lastItem}');
// Use for next page
}
RSMSet Parameters
The RSMSet class supports various parameters:
max: Maximum number of items to returnafter: Continue after this item IDbefore: Get items before this item IDindex: Retrieve a specific page by indexfirst: First item ID (used in responses)last: Last item ID (used in responses)count: Total count of items (used in responses)
Best Practices
- Use appropriate page sizes: Choose page sizes that balance performance and user experience (typically 25-50 items)
- Handle complete flag: Check the
completeflag to know when all results have been retrieved - Cache cursors: Store cursor positions (last item IDs) to enable efficient navigation
- Handle empty results: Always check if results are empty before processing
- Use count sparingly: Only request counts when necessary, as they can be expensive
RSM is essential for efficiently handling large result sets in XMPP applications, ensuring good performance and user experience.