Skip to content

SODA: query-by-example (QBE) find (#201)#208

Merged
lemenkov merged 1 commit into
masterfrom
soda-3-qbe-201
Jun 25, 2026
Merged

SODA: query-by-example (QBE) find (#201)#208
lemenkov merged 1 commit into
masterfrom
soda-3-qbe-201

Conversation

@lemenkov

Copy link
Copy Markdown
Owner

Third step of the #163 SODA umbrella — SodaOperation becomes a full read builder over DBMS_SODA.

API (sync + async)

  • find().filter(qbe) (dict or JSON string) · .skip(n) · .limit(n)
  • .count() → number of matches
  • .getDocuments() → every matching SodaDocument, materialised through a SODA_CURSOR_T loop into host arrays (cursor.arrayvar, PL/SQL associative-array (collection) binds #122) in one round trip. Without .limit() it caps at a fixed count and raises on overflow rather than truncating (streaming getCursor is a follow-up).
  • .getOne() now returns the first match for a key or a filter.

Notable regression caught

SODA's op.get_one() returns a stale result when its filter is a bind variable and the same statement runs again — it caches the first call's filter. op.get_cursor() re-evaluates correctly. So getOne runs the cursor path with limit 1 (which also matches oracledb's "first matching document" semantics). Confirmed pyoracle's bind handling is fine (a 13-bind block re-binds correctly); the staleness is purely inside SODA's get_one(). count() / get_cursor() with bind filters were verified to re-evaluate across calls.

Tests: offline _norm_filter; live count/filter/getDocuments/skip/limit, the getOne filter-reevaluation regression, and the overflow guard — sync + async, 23ai/21c pass, 11g/9i skip. Offline suite 527. Per-document content keeps the 32767-byte inline read limit from #200.

Closes #201

🤖 Generated with Claude Code

Third step of the #163 SODA umbrella, extending SodaOperation into a full
read builder over DBMS_SODA:

- filter(qbe) (a dict or JSON string), skip(n), limit(n) chained on
  collection.find().
- count() -> number of matches.
- getDocuments() -> every matching SodaDocument, materialised through a
  SODA_CURSOR_T loop into host arrays (cursor.arrayvar, #122) in one round
  trip. Without limit() it caps at a fixed count and raises on overflow
  rather than truncating.
- getOne() now returns the first match for a key OR a filter.

RE / regression note: SODA's op.get_one() returns a stale result when its
filter is a bind variable and the same statement runs again (it caches the
first call's filter); op.get_cursor() re-evaluates correctly. So getOne
runs the cursor path with a limit of 1 — which also matches oracledb's
"first matching document" semantics. count() and get_cursor() with bind
filters were verified to re-evaluate across calls.

Sync + async; 23ai/21c pass, 11g/9i skip. Per-document content keeps the
32767-byte inline read limit from #200.

Closes #201

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
@lemenkov lemenkov added this to the 1.10.0 milestone Jun 25, 2026
@lemenkov lemenkov merged commit abb1fc2 into master Jun 25, 2026
10 checks passed
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.

SODA: query-by-example (QBE) find

1 participant