Latest Results
fix: make cursor pagination lossless over nullable, tied, and boolean orderings (#55)
## Problem
Cursor pagination breaks whenever the user-supplied ordering does not
form a total order:
- A **nullable** trailing order key cannot mint a bookmark once a page
ends on a null row β `bookmark_from_item` raised `Cursor bookmark
requires a non-null unique tiebreak order key` (surfacing as a 500
downstream).
- A **non-unique** order key silently skips rows tied at the page
boundary (`name < 'dup'` excludes the remaining `'dup'` rows).
- A **boolean** order key (e.g. `pinned DESC`) could not even compile
its bookmark: SQLAlchemy refuses ordering comparators against raw Python
`bool` literals (`ArgumentError: Only '=', '!=', 'is_()', ...`).
## Fix
**Identity tiebreak** (`fef1f58`): `with_identity_tiebreak(entity,
order_bys)` appends the entity's `Identity`-marked keys (descending,
matching the newest-first default) to any ordering that lacks one,
applied at the three consumption points β `Session.list` ORDER BY
compile, `Cursor.from_expressions` minting, and `bookmark_from_item`.
Empty orderings, non-transmuter entities (plain ORM classes are narrowed
out via `isinstance(entity, TransmuterMetaclass)`), and orderings
already naming an identity pass through unchanged; identity-less
transmuters still hit the existing tiebreak error as a backstop.
**Boolean literals** (`3214bf0`): `SqlalchemyExpressionCompiler.apply`
wraps `bool` operands of `lt`/`le`/`gt`/`ge` in `sqlalchemy.literal()`,
compiling to legal SQL such as `pinned < false`. Equality operators are
untouched.
Existing serialized cursors keep decoding β bookmarks are stored
expressions, no migration needed.
## Null placement
The bookmark math assumes PostgreSQL null placement (ASC NULLS LAST /
DESC NULLS FIRST). `SqlalchemyExpressionCompiler.order` has emitted that
placement explicitly since `674d569`, so every backend β including
SQLite, whose own default is nulls-first β sorts the way the bookmarks
assume. An earlier revision of this description called this out as a
gap; that was wrong, and an end-to-end null-boundary walk test now pins
the guarantee.
## Verification
- `uv run pytest tests`: **1018 passed, 1 skipped** (baseline on main:
1009 passed, 1 skipped).
- `ruff check` and `ruff format --check`: clean.
- Verified end-to-end against real PostgreSQL from a downstream
consumer: limit-1 cursor walks over ascending-nullable, descending-tied,
and boolean orderings each visit every row exactly once. Latest Branches
0%
release-please--branches--main 0%
fix/association-proxy-peek 0%
fix/cursor-identity-tiebreak Β© 2026 CodSpeed Technology