Skip to content

fix(python): key query rows in projection order - #1180

Merged
thekevinscott merged 5 commits into
mainfrom
claude/1173-py-projection-order
Sep 24, 2026
Merged

thekevinscott merged 5 commits into
mainfrom
claude/1173-py-projection-order

Conversation

@thekevinbot

@thekevinbot thekevinbot commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1173

db.query() returned dicts built by iterating the core's row HashMap, so key order was hash order and changed from run to run. The binding now calls the core's query_ordered and builds each dict by walking columns, so list(row) is the order the SELECT list names (SELECT * follows the declared column order).

API shape: no new surface. Python dicts keep insertion order, so the guarantee lives on the rows query() already returns. A separate query_ordered accessor was the alternative; it was not added because the only thing it would add is a column list for a zero-row result.

Red/green

The test commit (f4e1847) went up alone. CI (dirsql Python CI / Binding tests, run 35994439070) failed on the new test for the asserted reason on 3.10, 3.12 and 3.13:

FAILED tests/integration/binding/column_order_test.py::describe_query_column_order::it_keys_rows_in_the_select_list_order
AssertionError: assert ['e', 'g', 'c'...'a', 'h', ...] == ['f', 'c', 'h'...'e', 'b', ...]

Manual run

SELECT path, ctime, size FROM './' ORDER BY path -> [{'path': 'a.md', 'ctime': 1790250329, 'size': 6}, ...]
SELECT size, basename, path FROM './' ORDER BY path -> [{'size': 6, 'basename': 'a.md', 'path': 'a.md'}, ...]
SELECT 1 AS z, 2 AS a, 3 AS m -> [{'z': 1, 'a': 2, 'm': 3}]

E2E Verification

  • Ran e2e suites locally for every affected SDK
  • Python SDK e2e: pass
  • TypeScript SDK e2e: N/A
  • Rust core e2e (if applicable): N/A (no packages/rust change)
  • packages/python/e2e-attestations/<branch>.json receipt written if packages/python changed (just e2e-attest-python)
  • packages/ts/e2e-attestations/<branch>.json receipt written if packages/ts changed (just e2e-attest-ts) — N/A
  • Command(s) run: just e2e-attest-python, uv run python -m pytest tests/integration/binding/, just preflight
  • Result summary: python e2e 38 passed; binding 108 passed; preflight 0 failing pairs.

Changelog / Migrations

  • Changelog fragment added under <root>/<pkg>/changelog.d/ for each changed package (packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md)
  • Migration fragment added under <root>/<pkg>/migrations.d/ (packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md -- key order changes from per-process hash order to projection order; no code change required)

Parity

Closes the last projection-order drift: Python rows are keyed in projection order; Rust and TypeScript expose query_ordered / queryOrdered. PARITY.md updated; docs/reference/sdk.md notes the Python guarantee and points Rust and TypeScript callers at queryOrdered.

@thekevinbot
thekevinbot force-pushed the claude/1173-py-projection-order branch from 15d8fe0 to 9087a1a Compare September 24, 2026 21:03
@thekevinscott
thekevinscott merged commit d583452 into main Sep 24, 2026
60 checks passed
@thekevinscott
thekevinscott deleted the claude/1173-py-projection-order branch September 24, 2026 21:10
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.

Python SDK: no way to get a query's projection order

2 participants