Skip to content

#245 — accept double-quoted ref()/source() given inputs in Rust parsers - #248

Merged
cmbays merged 3 commits into
mainfrom
adapters-245-double-quote-ref-parsing
Jun 12, 2026
Merged

cmbays merged 3 commits into
mainfrom
adapters-245-double-quote-ref-parsing

Conversation

@cmbays

@cmbays cmbays commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The Rust given-input parsers in src/adapters/render.rs (parse_ref_name, parse_source_ref) stripped single quotes only. dbt accepts both quote styles in a unit-test given's input: and dbt-fusion ships the authored string verbatim on the manifest wire (verified 2026-06-11 against a real fusion 2.0.0-preview.177 compile of the dogfood project — evidence in issue #245; no re-verification needed). A double-quoted given therefore lost its bound_to_node binding and its column_meta resolution.

Fix: a new strip_matching_quotes helper strips one pair of matching string-literal quotes ('…' or "…"). Open/close must be the same character; mixed pairs (ref("x')) and unbalanced quotes stay None — fail-open. For source(a, b) the rule applies per argument (each arg is its own string literal, so mixed-style args like source("a", 'b') parse). Single-quote behavior is byte-for-byte unchanged. This is the Rust twin of the JS givenOwnerLabel fix that landed in PR #244 (same matching-quote backreference rule).

Acceptance criteria — evidence

  • parse_ref_name accepts ref("x"); mixed quotes stay None — parse_ref_name_accepts_double_quoted_name, parse_ref_name_returns_none_on_mixed_quotes, plus double-quote variants added to the unmatched/empty pins. All pre-existing single-quote pins kept unchanged.
  • parse_source_ref accepts source("a", "b") and mixed-style args per-arg — parse_source_ref_accepts_double_quoted_names, parse_source_ref_accepts_mixed_style_args, parse_source_ref_returns_none_on_mixed_quotes_within_an_arg.
  • Existing parser test family extended; the stale *_returns_none_on_double_quoted_* pins (which pinned the bug) rewritten to assert the accepting behavior, citing the adapters: parse_ref_name / parse_source_ref reject double-quoted ref()/source() given inputs (fusion ships authored quotes verbatim) #245 fusion wire evidence.
  • AC4 binding proof — in-process render-integration test render_report_binds_double_quoted_given_and_populates_column_meta: builds domain objects with a double-quoted given.input, calls render_report, asserts the rendered HTML carries "bound_to_node":"stg_payments_src" and the input model's column-description marker. (Implemented in-process per the concurrent-builder file-ownership split; tests/headless_toggle.rs untouched. Headless coverage is not irreplaceable here — the binding markers are payload facts the in-process render asserts end-to-end, and the live prdiff-preview exercises the real browser path.)
  • TDD: all four new behaviors were written first and observed RED (3 parser failures + the AC4 render failure) before the implementation landed.

Discovery answers

  1. Comma-split fail-open comment — it lives in parse_source_ref (the issue attributes it to find_source_import_node_id, but that function has no comma-split; the comment sits above the split_once(',') in the parser). The property still holds with both quote styles: a comma inside a quoted name (either style) leaves the first split fragment with an unbalanced or mismatched quote pair, which the matching-quote strip rejects — fail-open by construction. The comment was updated to say so, and the property is now pinned for the double-quoted case too (source("a,b", "c") → None in parse_source_ref_returns_none_on_unmatched_quotes).
  2. Other Rust-side verbatim-input consumers — one real gap found: src/domain/checks.rs given_input_leaf (~L977) extracts "the last single-quoted argument" via rfind('\'') (the renderer-binding twin, duplicated in domain because domain never imports adapters). For a double-quoted given it returns None, so union arm-coverage classification degrades to ArmCoverage::Unknown — fail-open (never a wrong finding), but the C3 arm-coverage check loses precision for double-quoted givens. Out of scope for this tight diff; recommend a small follow-up issue mirroring strip_matching_quotes there. Not gaps: parse_yaml_scalar (unit_test_yaml.rs) already handles both quote styles; literal_cell (unit_test_table.rs) is correct SQL-literal semantics (single-quoted = string, double-quoted = identifier) and must stay single-quote-only; the remaining ref('…') hits in checks.rs are recommendation-sketch output formatting, not input parsing. The JS twin givenOwnerLabel was already fixed in PR #240 — review-2 render defects: tooltip overflow, given-header tooltips, covered-by contrast, overrides-badge clip, baseline banner #244.

Dogfood

Exactly one given in dbt-project/models/marts/_marts__models.yml flipped from ref('stg_payments') to ref("stg_payments") (the same flip used for the fusion wire verification in #245), with a cute-dbt#245 dogfood comment. The live prdiff-preview on this PR self-renders from an ephemeral CI-compiled fusion manifest and proves the binding (bound_to_node + column_meta) on the real wire. Nothing under any target/ directory and no root_path-bearing artifact is committed.

Goldens

All four golden examples (jaffle-shop, playground, diff-showcase, explore) regenerated locally exactly as the CI example-report-check matrix does; git diff --text -U0 -- examples/ is empty (no committed project uses double quotes, as expected).

Gates (run directly — lefthook skips in fresh worktrees)

  • cargo fmt --check — pass
  • cargo clippy --all-targets --locked -- -D warnings — exit 0
  • cargo nextest run — 1232 passed
  • cargo test --test bdd — 160 scenarios / 1032 steps passed
  • cargo test --test headless_toggle --locked -- --ignored — 63 passed
  • cargo test --test headless_zero_egress --locked -- --ignored — 10 passed
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --locked — exit 0
  • cargo deny check — exit 0

Merge order: after PR for #247 (concurrent render.rs work); expect a rebase before merge.

Closes #245

🤖 Generated with Claude Code


Open in Stage

Summary by CodeRabbit

  • New Features

    • Test input parsers now accept both single- and double-quoted dbt-style ref/source calls and validate quote matching and argument structure.
  • Tests

    • Expanded unit and end-to-end tests covering double-quoted syntax, mixed/unmatched-quote failures, malformed argument cases, and binding/rendering of double-quoted inputs.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@cmbays, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 33 minutes and 33 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ccfbc1e-bd50-42f2-8d15-9a0cccc4a7ee

📥 Commits

Reviewing files that changed from the base of the PR and between 5333bec and 65bee12.

📒 Files selected for processing (1)
  • src/adapters/render.rs
📝 Walkthrough

Walkthrough

The PR extends dbt-style given input parsers to accept both single-quoted and double-quoted ref() and source() function calls, with strict per-argument quote matching and comprehensive test coverage including a new end-to-end integration test and a YAML fixture update.

Changes

Quote support in dbt-style ref() and source() given inputs

Layer / File(s) Summary
parse_ref_name with quote support
src/adapters/render.rs
parse_ref_name documentation updated to accept both single and double quotes. Implementation refactored to use strip_matching_quotes helper with fail-open behavior on empty inner names or mismatched/unbalanced quotes.
parse_source_ref with quote support
src/adapters/render.rs
parse_source_ref documentation refined to describe per-argument quote matching. Implementation reworked to perform top-level comma split and apply strip_matching_quotes independently to each argument, enabling mixed quote styles across the two parameters while rejecting malformed arity.
Unit test coverage for parsers
src/adapters/render.rs
parse_ref_name and parse_source_ref unit tests expanded to cover double-quoted inputs, mixed quote styles across arguments, and error cases including empty inner content, mismatched quotes, and unbalanced delimiters.
Integration test and YAML fixture
src/adapters/render.rs, dbt-project/models/marts/_marts__models.yml
New end-to-end render_report test verifies that double-quoted ref("...") givens bind to the correct import CTE and resolve input model column_meta. YAML test fixture updated to use double-quoted ref() syntax and explanatory comments added.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • breezy-bays-labs/cute-dbt#204: Modifies src/adapters/render.rs around given parsing and source() binding; touches the same rendering-time parsing/binding logic.

Poem

🐰 I nibble quotes both double and small,
Parsers now welcome one and all.
Ref("name") and ref('name') both play,
Tests hop through the night and day,
Rendered columns cheer—hip hip hooray! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding double-quote support to Rust parsers for dbt-style ref()/source() inputs.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch adapters-245-double-quote-ref-parsing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ghost

ghost commented Jun 11, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 4 individual chapters for you:

Title
1 Introduce matching-quote stripping utility
2 Update ref() parser for double quotes
3 Update source() parser for double quotes
4 Verify end-to-end rendering and dogfooding
Open in Stage

Chapters generated by Stage for commit 65bee12 on Jun 12, 2026 12:39am UTC.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for both single and double quotes in dbt unit test ref and source inputs, resolving issue cute-dbt#245. It introduces a helper function strip_matching_quotes to validate and strip matching quote pairs, and updates the parsing logic in parse_ref_name and parse_source_ref. Additionally, new unit and integration tests have been added to ensure correct behavior. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@github-actions

github-actions Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

📄 Rendered report preview

All golden examples regenerated cleanly.

🟡 Golden examples

Committed to examples/ and byte-identity gated — the canonical reports contributors and consumers browse. Stable across PRs.

Report View Download
diff-showcase-report.html ▶ Open ↗ ⬇ Download
playground-report.html ▶ Open ↗ ⬇ Download
jaffle-shop-report.html ▶ Open ↗ ⬇ Download

🐶 Live dogfood preview

This PR's own dbt-project/ diff, freshly compiled by fusion into an ephemeral manifest (never committed) and rendered with --pr-diff. Regenerated every PR — the live self-dogfood, not a committed example.

Report View Download
dbt-project-report.html ▶ Open ↗ ⬇ Download

▶ Open ↗ opens the report in your browser in one click —
published to this repo's GitHub Pages under /pr-248/.
⬇ Download fetches the same self-contained HTML as a workflow
artifact (auth-gated; works fully offline). Either way the report
makes zero external resource requests.

The Pages preview may take ~1 min to update after this comment
posts. On PRs from forks the Open link is unavailable (read-only
token) — use Download.

Alternative: GitHub CLI
# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 27386768645 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 65bee12f8eec26738555e6ae80375e39cce0735c. Affordance only — never blocks merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/adapters/render.rs`:
- Around line 197-199: The parsing of source(...) currently uses
inside.split_once(',') which accepts inputs with extra commas (e.g.,
source('a','b','c')); before calling split_once ensure there is exactly one
comma by checking the comma count (e.g., inside.matches(',').count() == 1) and
return an error if not, then call inside.split_once(',') and proceed to call
strip_matching_quotes on both trimmed parts; update the error path to clearly
reject malformed argument lists so strip_matching_quotes is only invoked when
there are exactly two arguments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1a133ee-0403-4e42-b8c1-8fc7c53b46ea

📥 Commits

Reviewing files that changed from the base of the PR and between 291b639 and e289432.

📒 Files selected for processing (2)
  • dbt-project/models/marts/_marts__models.yml
  • src/adapters/render.rs

Comment thread src/adapters/render.rs Outdated
cmbays pushed a commit that referenced this pull request Jun 11, 2026
CodeRabbit (PR #248): parse_source_ref used split_once(','), so a
malformed 3-arg call like source('a','b','c') split to first='a',
second='b','c' — and strip_matching_quotes only checks the end
characters, so the second fragment stripped to the garbage pair
("a", "b','c") instead of None. Probe-verified RED before fixing
(left: Some(("a", "b','c"))).

splitn(3, ',') + reject when a third part exists. Pinned for both
quote styles plus the trailing-comma shape; the existing
comma-inside-quoted-name pins are kept (that path now rejects via
the part count or, for two-part splits, the matching-quote strip —
fail-open either way).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
github-actions Bot and others added 2 commits June 11, 2026 20:13
dbt accepts both quote styles in a unit-test given's input: and
dbt-fusion ships the authored string verbatim on the manifest wire
(verified 2026-06-11 against a real fusion 2.0.0-preview.177 compile —
see issue #245). The Rust parsers (parse_ref_name / parse_source_ref)
stripped single quotes only, so a double-quoted given lost its
bound_to_node binding and its column_meta resolution.

- new strip_matching_quotes helper: one pair of MATCHING quotes
  ('…' or "…"); mixed pairs and unbalanced quotes stay None
  (fail-open), applied per argument for source(a, b)
- parser test family extended: double-quote accepts, mixed-quote
  None pins, per-arg mixed-style source args, double-quoted empty /
  unmatched variants; the stale returns_none_on_double_quoted pins
  (which pinned the bug) rewritten to assert the accepting behavior
- AC4 render-integration test: render_report binds a double-quoted
  given (bound_to_node in the payload) and populates its input
  model's column_meta
- dogfood: one given in dbt-project flipped to ref("stg_payments")
  so the live prdiff-preview proves the binding
- comma-split fail-open comment updated for both quote styles

Closes #245

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CodeRabbit (PR #248): parse_source_ref used split_once(','), so a
malformed 3-arg call like source('a','b','c') split to first='a',
second='b','c' — and strip_matching_quotes only checks the end
characters, so the second fragment stripped to the garbage pair
("a", "b','c") instead of None. Probe-verified RED before fixing
(left: Some(("a", "b','c"))).

splitn(3, ',') + reject when a third part exists. Pinned for both
quote styles plus the trailing-comma shape; the existing
comma-inside-quoted-name pins are kept (that path now rejects via
the part count or, for two-part splits, the matching-quote strip —
fail-open either way).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cmbays
cmbays force-pushed the adapters-245-double-quote-ref-parsing branch from f53365d to 5333bec Compare June 12, 2026 00:13
…t arity

PR #250 (#247 model YAML drawer) widened render_report with the
model_yaml map (arg 9); the rebase kept the AC4 in-process render
test at the old 13-arg call. Pass the same neutral &HashMap::new()
the other in-tree test call sites pass — assertions unchanged (the
test still proves the double-quoted given's bound_to_node +
column_meta binding).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cmbays
cmbays merged commit b2315c3 into main Jun 12, 2026
33 checks passed
@cmbays
cmbays deleted the adapters-245-double-quote-ref-parsing branch June 12, 2026 00:44
github-actions Bot added a commit that referenced this pull request Jun 12, 2026
cmbays added a commit that referenced this pull request Jun 12, 2026
…tion (#272)

given_input_leaf scanned for single-quoted arguments only
(rfind('\'')), so a double-quoted given input — ref("x"), which dbt
accepts and both engines ship verbatim on the manifest wire
(cute-dbt#245) — lost its leaf binding entirely. In the
union.arm-coverage check a fed arm then read as provably unfed and
degraded to a FALSE UNCOVERED nag (worse than the issue's stated
Unknown); the join checks' side_rows consumer mocked the side empty the
same way.

- the right-to-left scan now accepts either quote style under the
  matching-quote rule (open/close must be the SAME character; mixed or
  unbalanced pairs stay None, fail-open) — the domain twin of the
  renderer's strip_matching_quotes contract from PR #248, kept local
  because domain never imports adapters and the scan deliberately
  tolerates trailing non-string kwargs (ref('orders', v=2))
- TDD: leaf-extraction test family (single-quote pins stay, double-
  quote accepts, per-argument mixed styles for source(), mixed/
  unbalanced-quote None pins) + a detector-level twin pinning that a
  double-quoted given classifies arm-coverage identically to its
  single-quoted twin (RED showed Uncovered vs Covered)
- dogfood (the paired-fixture rule): both playground mart_dq_summary
  tests' stg_synthea__medications givens flipped to ref("…") in
  current+baseline manifests AND the paired source YAML (same-revision
  contract; 1:1 in-place line edits keep the pr-diff showcase hunk
  numbers unshifted), so the committed goldens prove
  union[combined_metrics] stays COVERED through a double-quoted given
- goldens regenerated: playground / diff-showcase / explore tests.html
  carry the quote flip (bound_to_node intact in the payload);
  jaffle-shop + explore dag.html byte-identical
- BDD steps' input capture widened to greedy (.+) so feature lines can
  carry a double-quoted input string; MANIFEST.toml SHAs + provenance
  notes updated

Closes #249

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

adapters: parse_ref_name / parse_source_ref reject double-quoted ref()/source() given inputs (fusion ships authored quotes verbatim)

1 participant