Skip to content

Fix Cosmos DB pagination for backwards compatibility (3.x)#1595

Open
MarcAstr0 wants to merge 4 commits intoboostercloud:release/3.xfrom
Optum:fix/cosmos-pagination_3.x
Open

Fix Cosmos DB pagination for backwards compatibility (3.x)#1595
MarcAstr0 wants to merge 4 commits intoboostercloud:release/3.xfrom
Optum:fix/cosmos-pagination_3.x

Conversation

@MarcAstr0
Copy link
Collaborator

@MarcAstr0 MarcAstr0 commented Mar 2, 2026

Description

Same fix as #1594, targeting the release/3.x branch (Node 20-compatible versions).

Checks

  • Project Builds
  • Project passes tests and checks
  • Updated documentation accordingly

@what-the-diff
Copy link

what-the-diff bot commented Mar 2, 2026

PR Summary

  • Introduces Trackable Fixes to Database Pagination Issues
    A new file for tracking adjustments related to improving pagination issues with a database named "Cosmos DB". This has been added in the "boostercloud framework-core" package.

  • Updates Multiple Dependencies
    Several dependencies in a core file have been updated, which could result in better performance and increased security of the applications. Consequently, a number of packages across various sections stand updated.

  • Refined Pagination Logic in Database Queries
    Within the 'query-helper.ts' file, there's now a constant value set for the default page size in the database queries. The refined logic ensures that the maximum item count for these queries is always set when using continuation tokens, or a limit is provided. This further results in a consistent pagination process as the calculations are now aligned with the effective limit. Also, both legacy cursor support and implementing cursor advancements based on the page size are now handled better.

@MarcAstr0
Copy link
Collaborator Author

/integration sha=7ba540a

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

⌛ Integration tests are running...

Check their status here 👈

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Backports the Cosmos DB pagination compatibility fix to the release/3.x line, aiming to restore a numeric cursor id for frontends while keeping continuation-token pagination for Azure Cosmos DB.

Changes:

  • Update Azure provider Cosmos query pagination logic (continuation token vs legacy OFFSET/LIMIT) and introduce a default page size.
  • Update Rush/pnpm lockfile with workspace specifier bumps and an updated resolved TypeScript nightly used by tooling.
  • Add a Rush changefile for a patch release.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

File Description
packages/framework-provider-azure/src/helpers/query-helper.ts Adjusts Cosmos DB paginated search behavior, including continuation-token feed options and cursor shaping.
common/config/rush/pnpm-lock.yaml Updates workspace dependency specifiers and refreshes some resolved toolchain dependencies in the lockfile.
common/changes/@boostercloud/framework-core/fix-cosmos-pagination_3.x_2026-02-27-21-16.json Declares a patch change entry for publishing/versioning.
Files not reviewed (1)
  • common/config/rush/pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


typescript@6.0.0-dev.20250822:
resolution: {integrity: sha512-omHezTVn6vg+B/eFHkIzUGFvlbbkJdsdmdBohcsw8NMLyKOhKRMinE9aLu8f0EALT4R2YS41xak2KinK74/6Xg==}
typescript@6.0.0-dev.20260302:
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This lockfile update bumps the resolved typescript@6.0.0-dev.* nightly used by downlevel-dts (from 20250822 to 20260302) without any corresponding direct dependency change. If this wasn’t intentional, consider reverting the Typescript nightly resolution to avoid unrelated toolchain drift in a pagination-focused backport PR.

Suggested change
typescript@6.0.0-dev.20260302:
typescript@6.0.0-dev.20250822:

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +7
{
"packageName": "@boostercloud/framework-core",
"comment": "Fix pagination issues with Cosmos DB",
"type": "patch"
}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This changeset is recorded under @boostercloud/framework-core, but the functional change in this PR is in @boostercloud/framework-provider-azure (Cosmos DB query helper). If the goal is to publish the Azure provider pagination fix, the changeset should target the provider package (so changelogs/version bumps line up with the shipped fix).

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +82
// Always set maxItemCount when limit is provided or when using continuation token
if (limit || afterCursor?.continuationToken) {
feedOptions.maxItemCount = limit ?? DEFAULT_PAGE_SIZE
}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

In the continuation-token path, maxItemCount is only set when limit is provided or when afterCursor.continuationToken is present. For the first page when limit is omitted (but continuation-token pagination is still used), this can yield an implementation-defined page size from the SDK/service, which makes cursor.id calculations non-deterministic and may break clients relying on stable offsets. Consider always setting feedOptions.maxItemCount when using the continuation-token pagination branch (e.g., to limit ?? DEFAULT_PAGE_SIZE), not only when a token is already present.

Suggested change
// Always set maxItemCount when limit is provided or when using continuation token
if (limit || afterCursor?.continuationToken) {
feedOptions.maxItemCount = limit ?? DEFAULT_PAGE_SIZE
}
// Always set maxItemCount when using continuation-token pagination
feedOptions.maxItemCount = limit ?? DEFAULT_PAGE_SIZE

Copilot uses AI. Check for mistakes.
count: processedResources.length,
cursor: {
id: (offset + processedResources.length).toString(),
id: (offset + effectiveLimit).toString(),
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The legacy OFFSET/LIMIT branch advances cursor.id by effectiveLimit rather than by the number of items actually returned (processedResources.length). If Cosmos returns fewer than effectiveLimit for any reason, an old client that paginates using only cursor.id will skip items on the next request. Advancing by the actual returned count keeps the numeric cursor aligned with the true offset.

Suggested change
id: (offset + effectiveLimit).toString(),
id: (offset + processedResources.length).toString(),

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +118
// cursor.id advances by the page size (limit) to maintain consistent page-based offsets
// that frontends rely on (e.g., limit=5 produces cursors 5, 10 ,15, ...)
const previousOffset = afterCursor?.id ? parseInt(afterCursor.id) : 0
const effectiveLimit = limit ?? DEFAULT_PAGE_SIZE

let cursor: Record<string, string> | undefined
if (continuationToken) {
cursor = { continuationToken }
cursor = { continuationToken, id: (previousOffset + effectiveLimit).toString() }
} else if (finalResources.length > 0) {
const currentOffset = afterCursor?.id && !isNaN(parseInt(afterCursor.id)) ? parseInt(afterCursor.id) : 0
cursor = { id: (currentOffset + finalResources.length).toString() } // Use the length of the results to calculate the next id
cursor = { id: (previousOffset + effectiveLimit).toString() }
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

previousOffset is computed via parseInt(afterCursor.id) without validating that afterCursor.id is numeric. If a client sends a non-numeric id alongside a continuationToken (or any other non-legacy cursor shape), this becomes NaN and the response cursor will include id: 'NaN'. Also, advancing cursor.id by effectiveLimit (instead of finalResources.length) can desynchronize offsets when fetchNext() returns fewer than maxItemCount, causing legacy clients (that ignore continuationToken) to skip results if they later fall back to OFFSET pagination. Consider (1) defaulting previousOffset to 0 unless afterCursor.id matches a numeric string, and (2) advancing by the actual number of returned items.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

❌ Oh no! Integration tests have failed

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

⌛ Integration tests are running...

Check their status here 👈

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

❌ Oh no! Integration tests have failed

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

⌛ Integration tests are running...

Check their status here 👈

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

❌ Oh no! Integration tests have failed

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

⌛ Integration tests are running...

Check their status here 👈

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

❌ Oh no! Integration tests have failed

@MarcAstr0
Copy link
Collaborator Author

/integration sha=832ebbe

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

⌛ Integration tests are running...

Check their status here 👈

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

❌ Oh no! Integration tests have failed

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

⌛ Integration tests are running...

Check their status here 👈

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

✅ Integration tests have finished successfully!

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.

2 participants