Skip to content

feat(query): order_by nulls placement e2e + golden vector - #367

Merged
0x054 merged 1 commit into
feat/order-by-nullsfrom
feat/363-order-by-nulls-e2e
Aug 29, 2026
Merged

0x054 merged 1 commit into
feat/order-by-nullsfrom
feat/363-order-by-nulls-e2e

Conversation

@0x054

@0x054 0x054 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Hand-authored query_card_nulls_v7 golden vector (first order_by term with nulls, next without; ir_version 7) asserted from the Python emitter and Rust decoder; existing vectors unchanged.
  • Backend-matrix e2e (tests/test_order_by_nulls.py) pins identical row order on SQLite and Postgres for DESC+nulls="last", nulls="first", chained terms, left-joined related NOT NULL columns, and projected SUM aggregates with NULL empty groups.
  • Contract validator accepts optional nulls and restricts present values to "first"/"last".

Closes #363

Test plan

  • uv run pytest tests/test_order_by_nulls.py tests/test_query_wire_vectors.py tests/test_ir_vectors_contract.py -q
  • cargo test -p ferro-schema-ir
  • CI backend matrix (sqlite + postgres)

Exit steps

  • Issue status: Closes #363 in PR body; assignee claimed

Made with Cursor

Pin mixed nulls=/omitted order_by terms on a dedicated Card fixture and
assert cross-backend result order for root, left-join, and aggregate sorts.

Co-authored-by: Cursor <cursoragent@cursor.com>
@0x054

0x054 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Gate pass (coordinator). Golden query_card_nulls_v7 has nulls on the first term and omits it on the second; both emitters pin it. E2e covers DESC last/first, chained terms, left-join related NOT NULL, and SUM-of-NULLs groups — result order only, both backends. CI green including the backend matrix. Landing on feat/order-by-nulls.

@0x054
0x054 merged commit 5854791 into feat/order-by-nulls Aug 29, 2026
7 checks passed
0x054 added a commit that referenced this pull request Aug 29, 2026
## Summary

Pin `NULL` sort-key placement on every `order_by()` with `nulls="first"
| "last"` (keyword-only). Native `NULLS FIRST` / `NULLS LAST` on
Postgres and SQLite. Omit the kwarg → backend default, no warning.

```python
cards = (
    await Card.select()
    .order_by(lambda card: card.pinned_at, "desc", nulls="last")
    .order_by(lambda card: card.updated_at, "desc")
    .all()
)
# ORDER BY pinned_at DESC NULLS LAST, updated_at DESC
```

- IR v7: optional `nulls` on an order_by term; key omitted when unset
- Python API on `Query` and `ProjectedQuery` (lambda, string, traversal,
aggregate, output alias)
- Golden vector + backend-matrix e2e
- Queries guide leads with pinned-first + rendered SQL; dialect split
stated once

Stacked: #365 (IR/SQL) → #366 (API) → #367 (e2e) → #368 (docs)

Closes #358
Closes #361
Closes #362
Closes #363
Closes #364

## Test plan

- [x] Slice CI green on each of #365#368 (lint, rust, python, backend
matrix)
- [ ] Integration CI against `main`
- [ ] Confirm issues #358, #361#364 close on merge to `main`


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant