Skip to content

Import a warehouse catalog when a data source is built - #282

Draft
jat255 wants to merge 2 commits into
jat255/xp65-catalog-securityfrom
jat255/xp65-source-wiring
Draft

Import a warehouse catalog when a data source is built#282
jat255 wants to merge 2 commits into
jat255/xp65-catalog-securityfrom
jat255/xp65-source-wiring

Conversation

@jat255

@jat255 jat255 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Sixth PR of the catalog import stack (kata task xp65). Stacked on #281. Python only.

Everything this catalog stack has been foundational with nothing calling it. This PR wires it in: a Snowflake or Databricks engine now imports its catalog when the source is built. The session identity is read first; relations named in tables are access-checked before anything is described, so a name the caller got wrong fails at construction rather than mid-conversation; the listing is folded into the authored dictionary; and the session is read again at the end, because a role that moved during discovery invalidates what was just learned.

A selection defaults to the namespace the connection already points at. A namespace has to be named with a Selector, because ANALYTICS.PUBLIC on its own does not say whether PUBLIC is a schema or a table; a plain string is read as a relation, the way it is everywhere else. exclude is accepted only for a warehouse, since nothing else has a listing to drop from.

The merge re-keys the dictionary to the warehouse's labels, so a table's definitions are now looked up under the name the author gave it. Definitions over a column the warehouse spells differently are refused for now: the compiler cannot yet bind an authored name to the discovered one, and lowering them as written would emit SQL against columns that do not exist. The next PR in the stack replaces that refusal with real binding.

dictionary is taken by from_engine() and from_board() because the merge needs it during construction, but definitions are lowered once, in data_source(). Both docstrings say so.

Verification

725 Python tests, ruff and pyrefly clean. A fake backend stands in for the network; the fixture-pinned row interpretation and the real dispatch from data_source() through from_engine() are both exercised. The definitions lookup was confirmed to bite by reverting it and watching the end-to-end test fail.

@jat255 jat255 added this to the py-M2: data layer milestone Sep 4, 2026
@jat255 jat255 added needs-manual-review Agent-created work that needs a human review py Affects the Python implementation labels Sep 4, 2026
@jat255
jat255 force-pushed the jat255/xp65-source-wiring branch from 63dfbf7 to 01c9608 Compare September 5, 2026 04:58
@jat255
jat255 force-pushed the jat255/xp65-source-wiring branch 2 times, most recently from 8770a5a to 75a721c Compare September 6, 2026 06:29
A Snowflake or Databricks engine now resolves its selection against the
warehouse rather than leaving the readers unused: the session identity is
read first, explicitly named relations are access-checked before anything
is described, the listing is folded into the authored dictionary, and the
session is read again at the end. A selection defaults to the namespace
the connection already points at, and exclude drops relations from it.

The merge re-keys the dictionary to the warehouse's labels, so a table's
definitions are now looked up under the name the author gave it rather
than the label it ended up with. Definitions over a column the warehouse
spells differently are refused for now, because the compiler cannot yet
bind an authored name to the discovered one.
@jat255
jat255 force-pushed the jat255/xp65-source-wiring branch from 75a721c to 234dae7 Compare September 6, 2026 19:20
…ons wherever a source is built

Review findings on this branch.

The order the import runs in is what makes the source safe, and nothing
asserted it. Three separate inversions each passed the whole suite: reading the
session identity after the registry rather than before it, probing named
relations after the merge rather than before, and moving the closing session
re-read ahead of the merge, which is the one thing it exists to cover. Four
tests now read the query log as a sequence of steps, and each inversion fails
exactly one of them.

Only Snowflake was ever exercised. The fake could not answer a Databricks query
at all, so wiring `databricks` to the Snowflake reader passed everything. There
is now a `FakeDatabricks`, and three tests drive a real Databricks import
through it. Both fakes take their row shapes from `catalog-rows.json` rather
than restating them, so a change to what a warehouse returns reaches them
instead of leaving them answering with a shape the readers no longer expect.

`from_engine()` and `from_board()` took a `dictionary` and never compiled its
definitions: only `data_source()` did, so a source built through the documented
constructors silently carried none, and the grain and unexposed-table checks
never ran. Lowering now happens at the end of every constructor.

The manifest no longer starts with the relations construction probed marked
readable. Carrying that answer forward saved a round trip on first touch at the
cost of serving a grant revoked in between, and the sibling implementation
re-probes for the same reason.

Also: `_selector()` delegates its spelling rules to `_table_entry_id()` rather
than restating them; a selection emptied by `exclude`, and a table `exclude`
dropped out from under its own definitions, each say so instead of reporting
that nothing matched; and the four warehouse-only attributes on `DataSource`
carry their real types.

Docs: `from_engine()` documents `exclude`; `data_source()` no longer claims
DuckDB is the only dialect with an emitter, and names the two refusals this
stack added; `query()` says it can now fail because the connection identity
moved; and `from_board()` says why it takes a dictionary it does not merge.

Tests also cover the four `_selector` spellings and their refusals, a named
relation the warehouse lacks, and the two `exclude` refusals that had none.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-manual-review Agent-created work that needs a human review py Affects the Python implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant