Skip to content

feat(warehouse): #221 Databricks adapter skeleton - #254

Merged
wjduenow merged 4 commits into
devfrom
feat/221-databricks-skeleton
Jun 25, 2026
Merged

feat(warehouse): #221 Databricks adapter skeleton#254
wjduenow merged 4 commits into
devfrom
feat/221-databricks-skeleton

Conversation

@wjduenow

@wjduenow wjduenow commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Part of epic #219 (Databricks warehouse adapter); second child after the #220 test-environment spike. Models on the Snowflake skeleton #119.

Stands up the warehouse-agnostic seam (Architectural Commitment #3) for a fourth vendor — after BigQuery, the Postgres stub, and Snowflake — with everything degrading gracefully, so the ABC + from_profile factory path is exercised by Databricks immediately. No live connectivity yet (that's #224+).

What's here

Guardrails honoured (.claude/rules/warehouse-adapters.md)

  • One shim per vendor; every databricks-sql-connector type-ignore confined to _databricks_client.py (paired confinement test).
  • Lazy SDK import inside make_real_client / the from_profile branch — import signalforge.warehouse stays SDK-free (subprocess-asserted).
  • Dialect-driven, never name-branched.
  • Graceful degrade via the existing *NotSupportedError defaults — no bare NotImplementedError escaping the orchestrator for the degrade-default methods.

Validation

uv sync --dev && uv run ruff check . && uv run ruff format --check . && uv run pyright && uv run pytest — green (pyright 0 errors; 4142 passed, 97% cov).

Collateral

  • Repointed test_from_profile_raises_for_unknown_type to redshift (databricks now dispatches).

Acceptance (per #221)

Adapter constructs without a live connection; from_profile dispatches a databricks target to it; dialect() returns the constant; degrade methods raise their typed errors; __repr__ redaction test passes; confinement-scan scaffolding present. ✅

Summary by CodeRabbit

  • New Features
    • Added optional Databricks support as an install extra and introduced databricks profile type with automatic adapter dispatch.
    • Exposed Databricks at the package level, including a Databricks SQL dialect configuration.
    • Added a Databricks adapter skeleton with safe credential redaction and consistent fallback behavior for unsupported operations.
  • Bug Fixes
    • Updated default pytest selection and added a Databricks test marker so live Databricks tests only run when enabled.
    • Adjusted the unsupported-profile test case to use redshift.
  • Tests
    • Added Databricks adapter tests and a check that vendor-specific type-ignore directives are confined to the Databricks shim.

… DATABRICKS_DIALECT + SDK shim)

Stands up the warehouse-agnostic seam for a FOURTH vendor (after BigQuery,
the Postgres stub, and Snowflake), mirroring the Snowflake skeleton #119.

- DatabricksAdapter: captures host/http_path/token/catalog/schema + forward-compat
  OAuth-M2M params (no eager connect); __repr__ redacts token/schema/client_secret;
  sample_rows/column_stats/run_test_sql raise NotImplementedError naming epic #219;
  materialise_sample/estimate_query_bytes/get_row_count/run_stats_query inherit the
  ABC typed degrade; fail-soft __exit__ cleanup.
- _databricks_client.py: one-shim-per-vendor SDK seam — duck-typed connection/cursor
  protocols, lazy make_real_client (PAT auth), minimal map_databricks_exception stub
  (auth -> WarehouseAuthError; full taxonomy in #226). Confinement test pins it.
- DATABRICKS_DIALECT: backtick quoting, identifier_case=lower (Unity Catalog), QUALIFY,
  64-bit xxhash64 sampling hash, per-component qualified quoting, Spark date-arithmetic
  fields. Provisional values certified by the #223 sqlglot parse-guard + #226 live.
- from_profile dispatches type: databricks (maps catalog<-project, schema<-dataset;
  real host/http_path/token fields land with profile parsing in #222).
- [databricks] optional extra + dev-group mirror + databricks pytest marker + addopts
  exclusion; uv.lock updated additively.
- Repoint test_from_profile_raises_for_unknown_type to redshift (databricks now dispatches).
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Databricks warehouse support as a v0.x skeleton: new dialect constants and exports, a Databricks adapter with lazy client creation and cleanup, WarehouseAdapter.from_profile dispatch, and Databricks-specific dependency, marker, and test wiring.

Changes

Databricks warehouse support

Layer / File(s) Summary
Dialect and package exports
src/signalforge/warehouse/models.py, src/signalforge/warehouse/__init__.py
Defines DATABRICKS_DIALECT and re-exports it and DatabricksAdapter from the warehouse package.
Databricks client shim
src/signalforge/warehouse/adapters/_databricks_client.py
Adds the Databricks client protocols, lazy databricks.sql.connect wrapper, and auth-exception mapping helper.
Databricks adapter skeleton
src/signalforge/warehouse/adapters/databricks.py, .claude/rules/warehouse-adapters.md
Implements DatabricksAdapter with lazy connection setup, context-manager cleanup, redacted __repr__, skeleton NotImplementedError methods, and related adapter layout notes.
Profile dispatch
src/signalforge/warehouse/base.py, tests/warehouse/test_base.py
Adds WarehouseAdapter.from_profile handling for type: databricks and updates the unsupported-type test case.
Dependency and marker wiring
pyproject.toml, tests/warehouse/test_databricks_client_confinement.py
Adds the optional Databricks dependency, pytest marker filtering, and a confinement check for Databricks-specific type-ignore directives.
Databricks adapter tests
tests/warehouse/test_databricks_stub.py
Adds tests for the Databricks dialect contract, adapter redaction, dispatch behavior, import isolation, and context-manager cleanup.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • wjduenow/SignalForge#82: Both PRs add a new WarehouseAdapter.from_profile dispatch branch and introduce a warehouse adapter/dialect pair.
  • wjduenow/SignalForge#125: Both PRs extend the same warehouse-factory surface and add a vendor-specific adapter skeleton plus shim seam.
  • wjduenow/SignalForge#127: Both PRs change the shared Dialect configuration surface with vendor-specific SQL template fields.

Poem

A rabbit hopped through spark and snow,
With redacted secrets in tow.
New dialect paths began to gleam,
And tests kept watch beside the seam.
🐰 Databricks burrow, ready to grow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a Databricks warehouse adapter skeleton.
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 docstrings
  • Create stacked PR
  • Commit on current branch

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

@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/signalforge/warehouse/models.py`:
- Line 314: The sample hash expression in DATABRICKS_DIALECT is using
ABS(xxhash64(...)), which can still produce a negative value for Long.MinValue
and skew deterministic sampling. Update the sample_row_hash_expr definition in
the relevant warehouse model to use a non-overflowing normalization approach
instead of ABS, and keep the change localized to the sample hash logic so the
sampling predicate remains stable and unbiased.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 942b2278-8843-4afd-9bff-3d6bfe65c21a

📥 Commits

Reviewing files that changed from the base of the PR and between 8e90e45 and 69b2c47.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • pyproject.toml
  • src/signalforge/warehouse/__init__.py
  • src/signalforge/warehouse/adapters/_databricks_client.py
  • src/signalforge/warehouse/adapters/databricks.py
  • src/signalforge/warehouse/base.py
  • src/signalforge/warehouse/models.py
  • tests/warehouse/test_base.py
  • tests/warehouse/test_databricks_client_confinement.py
  • tests/warehouse/test_databricks_stub.py

Comment thread src/signalforge/warehouse/models.py Outdated
wjduenow added 3 commits June 24, 2026 14:27
Compounding update for the #221 closeout. Adds the Databricks skeleton precedent
(4th adapter, mirrors Snowflake #119), the provisional-dialect/certification note
(values certified by #223 sqlglot parse-guard + #226 live, not snapshot equality),
and the load-bearing TableRef.project length gotcha for #224 (GCP project-id 6-30
char rule blocks Unity Catalog catalog names like 'main'). Also brings the adapters/
file tree current (snowflake + databricks + their shims).
… sample hash

CodeRabbit (PR #254): ABS(xxhash64(...)) can stay negative on Long.MIN_VALUE in
Spark non-ANSI mode, skewing MOD(<expr>, bucket) < 1. Replace with a sign-bit
mask (& 9223372036854775807 = Long.MAX_VALUE) — always non-negative, no overflow,
uniform, and keeps the renderer's MOD wrapper correct. Pinned by a no-ABS / mask
assertion in test_databricks_dialect_values; docstring + rules note updated.
@wjduenow

Copy link
Copy Markdown
Owner Author

PR Review Summary

Fixed (1 item)

File Line Issue Commit
src/signalforge/warehouse/models.py 314 ABS(xxhash64(...)) for the Databricks sample hash can stay negative on Long.MIN_VALUE in Spark non-ANSI mode, skewing MOD(<expr>, bucket) < 1 a36918a

Fix: replaced ABS with a sign-bit mask(xxhash64(to_json(struct(*))) & 9223372036854775807) (& Long.MAX_VALUE). Clears the sign bit → always non-negative, no overflow, uniform, and the shared renderer's MOD(<expr>, bucket) < 1 wrapper stays correct (a non-overflowing normalization, exactly as CodeRabbit suggested). Pinned against regression by a no-ABS + mask-present assertion in test_databricks_dialect_values; docstring + warehouse-adapters.md updated to match.

This value is still provisional at the skeleton stage (the compiler isn't invoked for a Databricks profile yet) and will be executed/certified by the #223 sqlglot parse-guard + the #226 gated live run — but it's now correct-by-construction rather than overflow-prone.

False Positives (0 items)

None.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.claude/rules/warehouse-adapters.md (1)

37-37: 🎯 Functional Correctness | 🟠 Major

Keep Unity Catalog catalogs out of TableRef.project. TableRef.project still follows GCP project-id validation, so a short Databricks catalog like main will fail if the #224 sampling path threads it through TableRef. Keep catalog on the Databricks field split or relax the shared validator before three-part refs land.

🤖 Prompt for 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.

In @.claude/rules/warehouse-adapters.md at line 37, Keep Unity Catalog catalog
names out of TableRef.project, because TableRef still validates project as a GCP
project id and short Databricks catalogs like main will fail construction.
Update the Databricks sampling path that builds three-part refs (the code that
threads quote_qualified_per_component into TableRef) so the catalog is stored on
the Databricks-specific field split instead of project, or relax
validate_project_id only for the Databricks dialect. Verify the TableRef
construction and any helper that maps catalog.schema.table avoid passing catalog
through project.
🤖 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.

Outside diff comments:
In @.claude/rules/warehouse-adapters.md:
- Line 37: Keep Unity Catalog catalog names out of TableRef.project, because
TableRef still validates project as a GCP project id and short Databricks
catalogs like main will fail construction. Update the Databricks sampling path
that builds three-part refs (the code that threads quote_qualified_per_component
into TableRef) so the catalog is stored on the Databricks-specific field split
instead of project, or relax validate_project_id only for the Databricks
dialect. Verify the TableRef construction and any helper that maps
catalog.schema.table avoid passing catalog through project.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 94ef1a63-3a90-4cf6-bfb8-69daf4d3adaa

📥 Commits

Reviewing files that changed from the base of the PR and between 8f00048 and a36918a.

📒 Files selected for processing (3)
  • .claude/rules/warehouse-adapters.md
  • src/signalforge/warehouse/models.py
  • tests/warehouse/test_databricks_stub.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/signalforge/warehouse/models.py
  • tests/warehouse/test_databricks_stub.py

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