Skip to content

Implement UID-cursor pagination for search#18

Merged
odrobnik merged 4 commits intomainfrom
feature/issue-13-search-pagination
Mar 22, 2026
Merged

Implement UID-cursor pagination for search#18
odrobnik merged 4 commits intomainfrom
feature/issue-13-search-pagination

Conversation

@odrobnik
Copy link
Copy Markdown
Contributor

Summary

Implements #13: UID-based cursor pagination for large search results using ESEARCH PARTIAL (RFC 9394).

Changes

  • Added --limit and --after-uid flags to post search
  • Switched to extendedSearch() with server-side pagination
  • New structured JSON response:
    {
      "total": 998,
      "messages": [...],
      "page": {
        "returned": 50,
        "hasMore": true,
        "next": {
          "afterUid": 64241
        }
      }
    }
  • Created SearchResult, SearchResultPage, and SearchResultNext models
  • Isolated NIOIMAPCore types with SearchPaging.swift helper

Testing

Tested on drobnik / Archive (998 messages in 2025):

  • Page 1: ~6s, 50 results
  • Page 2: ~6s, 50 results
  • No timeouts with server-side paging

Verification

  • swift build -c release
  • swift test (8/8 passing)
  • ✅ Tested pagination with --after-uid

Closes #13

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2908ab6ae3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

var identifierSet: MessageIdentifierSet<UID>?
if let afterUid {
// Only search UIDs greater than the cursor
identifierSet = MessageIdentifierSet(UID(afterUid + 1)...)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate afterUid before incrementing cursor

searchMessages is exposed as an @MCPTool, but the new cursor logic does afterUid + 1 directly. If a caller sends afterUid = Int.max (or any value near the bound), Swift integer overflow traps at runtime, which can terminate the daemon for a single malformed request. Please bound-check afterUid (and ideally constrain it to IMAP UID range) before computing the next value.

Useful? React with 👍 / 👎.

// Show next page hint
if let next = result.page.next {
print()
print("To see more: post search --server \(serverId) --mailbox \(mailbox) --limit \(limit) --after-uid \(next.afterUid)")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include active filters in next-page hint

The plain-text pagination hint only includes --server, --mailbox, --limit, and --after-uid, so following the suggested command after a filtered search (for example --from, --subject, date bounds, or flag filters) fetches a different result set instead of the next page of the current query. This produces incorrect pagination guidance for users who rely on the printed command.

Useful? React with 👍 / 👎.

- P1: Validate afterUid bounds (0 to UInt32.max) to prevent overflow
- P2: Include all active filters in plain-text next-page hint
Resolved conflicts by keeping review fixes (P1 + P2) from the feature branch.
@odrobnik odrobnik merged commit 695ff8a into main Mar 22, 2026
2 checks passed
@odrobnik odrobnik deleted the feature/issue-13-search-pagination branch March 22, 2026 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ESEARCH PARTIAL paging support for large search results

1 participant