Skip to content

fix(webhooks): correct keyset cursor lookup for table-qualified columns - #978

Open
rexx010 wants to merge 1 commit into
FinChippay:mainfrom
rexx010:fix/webhook-events-keyset
Open

fix(webhooks): correct keyset cursor lookup for table-qualified columns#978
rexx010 wants to merge 1 commit into
FinChippay:mainfrom
rexx010:fix/webhook-events-keyset

Conversation

@rexx010

@rexx010 rexx010 commented Aug 30, 2026

Copy link
Copy Markdown

applyKnexKeyset() looked up cursor values by the raw column name (e.g. "e.created_at") but cursors are encoded with plain field names ("created_at"), so keyset comparisons bound to undefined and page 2+ silently came back empty.

Summary

Fixes applyKnexKeyset so table-qualified sort columns (e.g. "e.created_at") correctly resolve against cursor objects, which are always keyed by plain field names — restoring working pagination past page 1 for the webhook events endpoint.

Type of change

  • Bug fix
  • New feature
  • Documentation update
  • Refactor / chore
  • Smart contract change

Related issue

Closes #888

Changes

  • backend/src/utils/paginate.js: applyKnexKeyset now strips a table-alias prefix before reading the cursor object, and skips the seek predicate entirely if the cursor is missing a required field instead of comparing a column to undefined.
  • backend/__tests__/webhookService.test.js: fixed the knex mock's join() to actually evaluate where/andWhere/orWhere callbacks and sort rows via orderBy (it previously no-op'd them, so it couldn't exercise real keyset behavior).
  • Added a test verifying two pages of equal-created_at events return every row exactly once (no overlap, no gap).

Testing

  • Added/updated unit tests
  • npx jest __tests__/webhookService.test.js → 23/23 pass
  • npx eslint src/utils/paginate.js → clean

Screenshots (if UI change)

N/A — backend-only fix, no UI change.

Checklist

  • My code follows the project style
  • I've updated docs if needed
  • No console errors or warnings
  • I've rebased on latest main

…lookup

applyKnexKeyset() looked up cursor values by the raw column name
(e.g. "e.created_at") but cursors are encoded with plain field
names ("created_at"), so keyset comparisons bound to undefined
and page 2+ silently came back empty.
@github-actions

Copy link
Copy Markdown

🤖 Greptile AI Code Review

Greptile will automatically review this PR (2 file(s) changed).

Review gates:

  • ✅ CodeQL Security Scan
  • ✅ Custom rules (.greptile/config.json)
  • ✅ Architecture guidelines (.greptile/rules.md)

To manually trigger a re-review, comment @greptileai on this PR.
To skip review, add the skip-review label.

@github-actions github-actions Bot added the needs-review PR ready for Greptile AI code review label Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review PR ready for Greptile AI code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

#107 — Webhook Cursor Is a UUID String Comparison: Pagination Can Skip or Repeat Rows

1 participant