Skip to content

feat(checks): full check-predicate dialect (#346) - #352

Merged
0x054 merged 1 commit into
feat/table-checksfrom
feat/table-checks-346
Aug 18, 2026
Merged

feat(checks): full check-predicate dialect (#346)#352
0x054 merged 1 commit into
feat/table-checksfrom
feat/table-checks-346

Conversation

@0x054

@0x054 0x054 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Extend compile_table_checks / _lower_node to lower the full root-column where() dialect into CheckExpr IR: comparisons, column-to-column, .in_(), .like(), enum member literals, plus existing NULL/OR/NOT combinators.
  • Reject closed-over variables (except enum classes used as Status.MEMBER spellings) and arbitrary function calls via co_freevars + AST inspection; .in_() / .like() remain allowed.
  • Add tests/test_check_predicate_dialect.py with compilation, rejection, and live enforcement pins; trim test_table_checks.py rejection cases now covered by the dialect.

Closes #346

Part of #339 (parent issue stays open).

Test plan

  • uv run pytest tests/test_check_predicate_dialect.py tests/test_table_checks.py
  • Transfer-shaped predicates unchanged (test_table_checks.py regression)
  • Live CHECK enforcement on sqlite (backend_matrix cases in new file)
  • CI green on feat/table-checks base

Exit steps

Made with Cursor

Extend table-check lowering to comparisons, column-to-column tests, in_/like,
and enum literals with closure and call validation so CHECK bodies stay
literal-only per ADR-0016 while Transfer-shaped NULL/OR predicates stay
byte-identical.

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

0x054 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Gate: clear

Read the full diff (checks.py lowering + tests/test_check_predicate_dialect.py + trimmed test_table_checks.py rejections). AC for #346 is met.

  • >= 0 and column-to-column compile to CheckExpr::Cmp and enforce live
  • .in_() / .like() lower to quoted literal tokens (no binds); .in_() also enforced live
  • Enum members inline as labels ('draft')
  • Closures fail at class definition; traversal / .exists() / aggregates still rejected by name
  • Transfer-shaped NULL/OR predicates stay in test_table_checks.py and were not rewritten

Nits, not blocking: .like() has IR coverage but no live pin (renderer already pinned in rust); AST call inspection walks the last lambda only, so a named def predicate would skip that check (docs/examples are lambda-only; co_freevars still applies).

Merging into feat/table-checks. Does not close parent #339.

@0x054
0x054 merged commit 38f8906 into feat/table-checks Aug 18, 2026
7 checks passed
@0x054 0x054 mentioned this pull request Aug 18, 2026
6 tasks
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