Skip to content

Pagination fix #1308

Description

@SimonCropp

Release Notes — 25e5a26

Despite the "refs and cleanup" commit message, this contains two behavioral bug fixes plus a refactor.

🐛 Bug Fixes

Connection pagination: after is now an exclusive cursor for in-memory lists

The IList/in-memory overload of ConnectionConverter treated the after argument as inclusive (skip = after ?? 0), so paging with after: 1 would re-return the item at index 1. It now starts strictly after the cursor (skip = after + 1 ?? 0), matching the IQueryable path and the Relay connection spec.

⚠️ Behavioral change: queries that page over in-memory lists using after will shift by one position. For example, first: 2, after: 1 now returns ["c", "d"] instead of ["b", "c"]. Several connection snapshot tests were updated to reflect the corrected cursors.

HasPreviousPage no longer incorrectly reports false

The condition was skip > 0 && take < count. The take < count guard hid the existence of a previous page whenever the page size covered all remaining items. It's now simply skip > 0 — if you've skipped past the start, a previous page exists. For example, first: 10, after: 0 over a 10-item list now correctly reports HasPreviousPage: true.

Property lookup across inherited interfaces is fixed

PropertyCache.GetPropertyOrField failed to resolve members declared on a base interface when a type implemented multiple inherited interfaces. The old loop break'd after the very first interface regardless of whether the member was found, and recursed into a method that throws on a miss — so lookups depended on the unspecified ordering of Type.GetInterfaces() and would throw for members on later interfaces. The interface walk now probes each base interface individually and stops only when a match is found.

♻️ Refactoring

  • PropertyCache member resolution split into a non-throwing TryGetPropertyOrField (returns null on miss) and a throwing GetPropertyOrField wrapper, making the recursive interface walk correct and clearer.

✅ Tests

  • List_after_is_an_exclusive_cursor — verifies after exclusivity on in-memory lists.
  • List_HasPreviousPage_true_when_page_size_covers_remaining_items — guards the HasPreviousPage fix.
  • PropertyOnInheritedInterface — covers member resolution across multiple inherited interfaces (asserts both members so it's independent of GetInterfaces() ordering).
  • Updated 5 connection pagination snapshot files for the corrected cursor / page-info values.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions