8000 feat: cursor API — Minigraf::query and PreparedQuery::query (#432) by adityamukho · Pull Request #461 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

feat: cursor API — Minigraf::query and PreparedQuery::query (#432) - #461

Merged
adityamukho merged 1 commit into
v3from
feat/432-cursor-api
Oct 7, 2026
Merged

adityamukho merged 1 commit into
v3from
feat/432-cursor-api

Conversation

@adityamukho
Copy link
Copy Markdown
Collaborator

Part of #432 (option 2: the API in 3.0.0, with the current evaluator behind it; streaming operators land in 3.x without further API changes).

What changes

  • Minigraf::query(&str) -> Result<Cursor, MinigrafError> and PreparedQuery::query(binds) -> Result<Cursor, MinigrafError>.
  • Cursor: vars(), next_batch(max_rows) -> Result<Option<Batch>, _>, close(), Iterator<Item = Result<Vec<Value>, _>>. Owned and Send: it borrows nothing from the handle, so a streaming cursor later can hold Arcs and a tx_count bound instead of a lock or a borrow. This is the one choice that would otherwise break callers later.
  • Batch: len, is_empty, rows, into_rows, IntoIterator. Row-major with private fields; internal operator batches can become columnar behind it.
  • The answer is fixed when the cursor opens (tested against a later transact, a WriteTransaction commit, a retract and a checkpoint).
  • New API-012: query() given transact/retract/rule. Bind slots give API-010, a WriteTransaction thread gives INT-001, as in execute().
  • execute() is unchanged.

Design: docs/superpowers/specs/2026-10-07-cursor-api-design.md.

Notes for review

  • The issue says a cursor will have "no result cap". max_results and max_derived_facts only bound recursive rule evaluation today; they never cap a plain query's rows. So nothing changes there now, and query() applies the same limits as execute().
  • Existing quirk, unchanged here: PreparedQuery::execute (and now PreparedQuery::query) uses the default limits, not the OpenOptions ones.
  • Not in this PR: binding cursor objects (separate repos), WriteTransaction::query (additive), operator rewrite, and the memory-bound design, which is still open per the 2026-10-03 comment on enhancement (v3.0.0): rework the query and transaction engine as a streaming, pull-based operator pipeline with bounded memory #432.

Tests

tests/cursor_test.rs (17 tests) plus a doctest. Full suite: 1,276 passing, 9 ignored. cargo clippy -- -D warnings and --all-features are clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn

Both return an owned, Send `Cursor` that delivers a query's rows in
batches (`vars`, `next_batch`, `close`, row iterator). The answer is
fixed when the cursor opens. The current evaluator still computes the
answer at open, under execute()'s limits; the API is shaped so streaming
operators can replace it in 3.x without breaking callers (option 2 of
#432). Non-queries are rejected with the new API-012.

Design: docs/superpowers/specs/2026-10-07-cursor-api-design.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
@codecov
codecov Bot commented Oct 6, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.95918% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/cursor.rs 96.42% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

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

0