fix(ogar-adapter-clickhouse-ddl): preserve backtick-quoted dotted table names on parse#40
Merged
Conversation
…le names on parse Closes Codex P2 on PR #38 (now merged). # The bug When the emitter produces `CREATE TABLE `sale.order` (…)` for an Odoo dotted class name, the parser path went: ct.name (ObjectName) ──to_string──▶ "`sale.order`" ──last_ident──▶ rsplit('.').next() = "order`" ──trim_matches('`') = "order" ^^^^^^ WRONG The `.` was treated as a database/table separator even though it was INSIDE the quoted identifier. Result: emit + parse round-trip turned `sale.order` into `order`, breaking the round-trip the PR claimed to support for Odoo dotted names. # The fix Bypass the string round-trip entirely. sqlparser already resolves the backtick / dot ambiguity structurally: - `\`sale.order\`` → `ObjectName(vec![ObjectNamePart::Identifier( Ident { value: "sale.order", quote_style: Some('`') })])` — ONE part because the backticks group it. - `db.table` → `ObjectName(vec![db_part, table_part])` — TWO parts. The new helper accesses the last part's `Ident.value` directly (the *unquoted* text), which is correct for both cases without splitting: fn last_ident_from_object_name(name: &ObjectName) -> String { name.0.last() .and_then(|part| part.as_ident()) .map(|ident| ident.value.clone()) .unwrap_or_default() } # Verifying tests (4 new; 12 prior → 16 total) parse_backtick_quoted_dotted_table_keeps_full_name — `CREATE TABLE \`sale.order\` (…)` → name == "sale.order" (not "order" — the Codex P2 motivating case). parse_qualified_db_table_takes_last_segment — `CREATE TABLE my_db.users (…)` → name == "users" (qualified-db path still works). round_trip_odoo_dotted_table_name — build IR with Class::new("sale.order") + attribute, emit, parse, assert name + attribute survive byte-identical. round_trip_three_segment_odoo_name — `account.move.line` three-segment name round-trips. # Verification cargo test -p ogar-adapter-clickhouse-ddl -> clean cargo test -p ogar-adapter-clickhouse-ddl --features clickhouse-parser -> 16/16 cargo check --workspace --all-targets -> clean PII abort-guard (word-boundary): CLEAN. # Symmetry note This is the same class of bug ogar-adapter-surrealql shipped a fix for in PR #36 (backtick-quoting on emit + symmetric parser handling). The two adapters now follow the same discipline: - surrealql adapter: emit backtick-quotes non-bare idents; walker accesses Path.start.text directly (unquoted) — no string round-trip on the parse side. - clickhouse adapter: emit backtick-quotes non-bare idents; walker accesses ObjectNamePart.Ident.value directly (unquoted) — no string round-trip on the parse side. Same lesson: don't string-round-trip when the AST already encodes the structural distinction. https://claude.ai/code/session_01PBTGaPCSnnt6u3pjXpbLwY
AdaWorldAPI
pushed a commit
that referenced
this pull request
Jul 4, 2026
…ns — transpile-chain LEG 2 ruff PR #40 (merged) shipped the is_a input end: a frontend-agnostic `ruff_spo_triplet::Model.inherits: Vec<String>` populated by the Odoo frontend from `_inherit` (self-reopen self-edge excluded upstream). The lift previously consumed only `sti.inherits_from -> Class.parent` (Rails STI) and dropped Model.inherits, so the Odoo is_a linkage never reached the Core. Route it to Class.mixins (extend), the multi-parent Vec shelf the vocab already designates for it: Class::mixins doc names `_inherit = 'mixin.thread'`, and Class::inheritance excludes mixins ("a SEPARATE axis ... never folded in here"). So NOT parent/inheritance (STI single-parent spine) — no parent widening, no information loss, no vocab-axis violation. Multi-parent handled natively by the Vec. Frontend-agnostic: only the Odoo frontend populates Model.inherits, so it is a no-op for Rails (sti) / C++ (bases). Consequence for LEG 3 (render, D-VCW-3): the FieldMask compose must union parent U mixins for Odoo inherited fields; render_rows stays concept-local. Tests: +2 (odoo_inherit_lands_on_mixins_not_parent, empty_inherits_adds_no_mixins); 48 green in ogar-from-ruff, workspace check + clippy clean. Ledger: docs/DISCOVERY-MAP.md D-OGAR-ODOO-INHERIT-MIXINS.
AdaWorldAPI
pushed a commit
that referenced
this pull request
Jul 4, 2026
ogar-from-ruff reads ruff_spo_triplet::Model::inherits (added in ruff #40). With no committed Cargo.lock, the floating `branch = "main"` pin could resolve to a ruff rev WITHOUT that field on a clean build and fail to compile — and the prior commit's '61ce2b49' claim didn't travel. Pin all three ruff refs (ruff_spo_triplet + ruff_spo_address in ogar-from-ruff, ruff_ruby_spo in ogar-from-rails) to the exact rev 61ce2b49 (ruff main at the #40 merge). Same rev across both crates: they share ruff_spo_triplet internally, so a mismatch would double-check-out ruff. Verified: ruff re-locks to 61ce2b49; ogar-from-ruff 48 tests + ogar-from-rails green; workspace check + clippy -D warnings clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes Codex P2 on PR #38 (now merged) —
last_identsplit on.BEFORE stripping backticks, silently truncating`sale.order`toorderand breaking the round-trip the PR claimed to support for Odoo dotted names. Per your instruction, fresh PR for visibility since #38 is onmain.PR #39 had no review comments — only #38 needed a fix.
The bug
The
.was treated as a database/table separator even though it was inside the quoted identifier. Result: emit + parse round-trip turnedsale.orderintoorder, breaking the round-trip the PR claimed to support for Odoo dotted names.The fix
Bypass the string round-trip entirely. sqlparser already resolves the backtick/dot ambiguity structurally:
ObjectNameshape`sale.order`Ident { value: "sale.order", quote_style: Some('') }` — backticks group itdb.table[Ident{value:"db"}, Ident{value:"table"}]—.is the separatorNew helper accesses the last part's
Ident.valuedirectly (the unquoted text):Correct for both cases without any string splitting or backtick-trimming heuristics.
Verifying tests (4 new; 12 prior → 16 total)
parse_backtick_quoted_dotted_table_keeps_full_name`sale.order`→ name == "sale.order" (not "order" — the Codex P2 motivating case)parse_qualified_db_table_takes_last_segmentmy_db.users→ name == "users" (qualified-db path still works)round_trip_odoo_dotted_table_nameround_trip_three_segment_odoo_nameaccount.move.linethree-segment name round-tripsVerification
PII abort-guard (word-boundary): CLEAN.
Symmetry note
This is the same class of bug
ogar-adapter-surrealqlshipped a fix for in PR #36 (backtick-quoting on emit + symmetric parser handling). The two adapters now follow the same discipline:Path.start.textdirectly (unquoted text) — no string round-trip on the parse side.ObjectNamePart::Identifier.valuedirectly (unquoted text) — no string round-trip on the parse side.Same lesson: don't string-round-trip when the AST already encodes the structural distinction. Worth pinning in a future ADR if a third adapter trips the same wire (the
ogar-adapter-ttladapter doesn't have this risk because Turtle has different identifier semantics).Out of scope for this PR
The DOMAIN-INSTANCES.md §2.6 + RDF-OWL-ALIGNMENT.md §10 Phase 2c updates I was queuing for after lance-graph PR #473 lands — those are now also unblocked and will be a separate small docs PR. Per the user's instruction to ship the fix PR first for visibility, the docs PR follows.
https://claude.ai/code/session_01PBTGaPCSnnt6u3pjXpbLwY