Skip to content

Compile field conversions into the expression tree rules already execute - #1133

Merged
WaylandYang merged 2 commits into
deeplethe:devfrom
Aschenbath:feat/alignment-expression-tree
Oct 9, 2026
Merged

WaylandYang merged 2 commits into
deeplethe:devfrom
Aschenbath:feat/alignment-expression-tree

Conversation

@Aschenbath

@Aschenbath Aschenbath commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Why

An amount in cents, a channel code and a creation month need conversions that the numeric rule-expression tree cannot express. ADR 0036 makes these conversions part of that tree so an alignment can store a definition with attribute references rather than a dialect-specific SQL string.

Closes #555.

What changes

  • Add a finite numeric cast, simple literal CASE and UTC year/month/day truncation to the shared expression tree. Case results have one scalar type, with at most 32 literal arms; every referenced reading remains a premise. Missing inputs, invalid conversions and unmatched cases without ELSE produce no result. Numeric evaluation keeps the existing floating-point semantics.
  • Accept {"expression":"CAST(amount AS DOUBLE PRECISION) / 100"} in a computed conclusion or comparison operand. The existing SQL parser compiles an allowlisted scalar expression, resolves attribute keys within the current base and stores only its UUID tree, including in definition history. The four-edge tree limit remains; text input is capped at 8192 bytes. Statements, subqueries, aggregates, searched cases, arbitrary casts/functions and function modifiers are refused.
  • Share JSON decoding between write validation, materialization and dependency analysis. Computed results can carry text and calendar dates through the existing derivation, interval, revision and chaining paths. Canonical numerical trees and numeric threshold strings retain their meanings; mixed or unknown JSON fields are now rejected instead of being read by field precedence.
  • Render the new nodes in the read-only rule display and follow their input attributes in the dependency view. The experimental arithmetic picker declines conversions it cannot round-trip. ADR 0036 and the rules design describe the grammar, the code-to-label versus named-business-rule distinction, and the limits.

Table alignment/adoption and SQL rendering remain #554 and #556. Declaration/unit validation remains the proposal in ADR 0049. This change adds no migration and does not provide fixed-scale decimal accounting or a new expression editor.

How it was checked

All six upstream CI checks passed for 1cbbe25e76f5a77d97b69922b9df767daf2e6b20.

  • cargo test --offline --locked --workspace: 1,474 passed, six existing opt-in tests ignored. The run used PostgreSQL/pgvector with UTOPIA_TEST_REQUIRE_DB=1 and UTOPIA_TEST_REQUIRE_PDFTOTEXT=1; fresh database migrations passed.
  • The 107-test reasoner suite includes new conversion, UTC boundary, invalid-value, shape/depth and premise/interval cases. Parser tests execute the issue's examples and reject unsupported SQL. The authenticated API regression creates and rereads stored trees, checks monetary/text/date results and chained conclusions, changes a definition and checks retirement/history, rejects invalid and foreign references without partial updates, and verifies inaccessible-base and viewer boundaries.
  • cargo fmt --all --check, workspace clippy for all targets with -D warnings, and cargo build --offline --locked --workspace passed.
  • Web production build, TypeScript/style checks and 235 tests passed, including conversion notation, English/Chinese labels, dependency references and the arithmetic draft guard.

The ignored cases are live OCR/RSS acceptance and dedicated materialization-delivery experiments. No real-model benchmark, external SQL-engine acceptance or browser interaction run is claimed here.

Before review

  • Every commit is signed off (git commit -s)
  • cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace pass
  • For changes under web/: pnpm build and pnpm test pass
  • Store behavior was tested with UTOPIA_DATABASE_URL set
  • The expression/API change follows ADR 0036, extending ADR 0032

Signed-off-by: Nash Aschenbath <wwh86696@163.com>
…ranch

Signed-off-by: Nash Aschenbath <wwh86696@163.com>

@WaylandYang WaylandYang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Unlike #1131 this one has a written scope, #555, and it stays inside it: the three node kinds the issue names, text accepted at write time and only the tree stored, MAX_EXPR_DEPTH unchanged, no migration and no new external dependency.

Read in full: expressions.rs and rule_expression_input.rs. The compiler is an allowlist that falls through to "unsupported", resolves names to attribute ids of the current base, and re-validates its own output through Expr::from_json, so the text and JSON entries cannot drift apart. Sharing one decoder also removed three copies of it.

Checked on a real server built from 1cbbe25:

Input Result
CAST(amount_cents AS DOUBLE PRECISION) / 100 stored as a tree of attribute ids, shown readably in Business rules
CASE channel_code WHEN 1 THEN 'app' WHEN 2 THEN 'web' ELSE 'other' END the same
amount_cents; DROP TABLE facts, (SELECT 1), lower(amount_cents), CAST(… AS TEXT), a searched CASE 422 bad_expression
no_such_attr / 100 422 unknown_expression_attribute

One thing to know, not a request: a CASE key is compared by type, so a code stored as the text "1" does not match WHEN 1 and the rule yields nothing. That is consistent with "a failed conversion is absent"; it may deserve a line in docs/design/rules.md when alignment (#554) starts feeding it real columns.

Merging. Thanks again.

@WaylandYang
WaylandYang merged commit 0e24b32 into deeplethe:dev Oct 9, 2026
6 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.

2 participants