Parent
#310 (feat PRD: Uniform predicate negation — prefix ~ as a NOT wire node)
What to build
The tracer bullet for uniform negation: prefix ~ on any leaf predicate, working end-to-end — Python spelling through the wire IR to rendered SQL on both database backends.
~ on a predicate node wraps it in a new recursive not wire node kind (beside the existing leaf and compound kinds; QueryIR version bumps). The Rust condition builder gains one recursion case rendering SQL NOT (...) over the rebuilt child. No per-operator negative forms are added anywhere — ~t.col.in_(ids) and ~t.col.like(p) are the spellings that close the pre-existing NOT IN / NOT LIKE gap (ADR-0008).
A hand-authored golden vector pins the not-over-leaf wire shape, asserted from both the Python emitter and the Rust decoder — the contract-review moment for the wire change.
Demo: Txn.where(lambda t: ~t.category_id.in_(ids)) returns exactly the complement rows (modulo SQL NULL semantics) on SQLite and Postgres.
Acceptance criteria
Blocked by
None - can start immediately
Parent
#310 (
featPRD: Uniform predicate negation — prefix~as a NOT wire node)What to build
The tracer bullet for uniform negation: prefix
~on any leaf predicate, working end-to-end — Python spelling through the wire IR to rendered SQL on both database backends.~on a predicate node wraps it in a new recursivenotwire node kind (beside the existing leaf and compound kinds; QueryIR version bumps). The Rust condition builder gains one recursion case rendering SQLNOT (...)over the rebuilt child. No per-operator negative forms are added anywhere —~t.col.in_(ids)and~t.col.like(p)are the spellings that close the pre-existing NOT IN / NOT LIKE gap (ADR-0008).A hand-authored golden vector pins the
not-over-leaf wire shape, asserted from both the Python emitter and the Rust decoder — the contract-review moment for the wire change.Demo:
Txn.where(lambda t: ~t.category_id.in_(ids))returns exactly the complement rows (modulo SQL NULL semantics) on SQLite and Postgres.Acceptance criteria
~works on every leaf operator kind: equality, ordering comparisons,in_,likeNOT (...)over the child predicate; no operator rewritingnot-over-leaf asserted by Python emitter and Rust decoder!=behavior)&/|,order_by,limit(composition tests at the e2e seam)not_in/not_likemethods introducedBlocked by
None - can start immediately