diff --git a/README.md b/README.md index c9bf1ac..0bc45f2 100644 --- a/README.md +++ b/README.md @@ -98,10 +98,9 @@ but the printed result is a truncated preview). Re-fetch past results with `hotdata databases results get `; browse history with `hotdata databases queries list`. -## Join across sources +## Join across databases -Attach another catalog to an instant database and join its live tables directly, -no copying: +Attach another instant database and join its live tables directly, no copying: ```sh hotdata databases attach prod-replica --alias prod @@ -109,6 +108,10 @@ hotdata query "SELECT t.id, o.total FROM demo.public.tickets t JOIN prod.public.orders o ON o.ticket_id = t.id" ``` +The attached database is read-only here: loads still go to your own database, +and `detach` withdraws visibility without deleting anything. `--alias` is +required when the other database kept the stock `default` catalog name. + ## Search Create an index once, then search server-side. Vector search auto-embeds the @@ -163,8 +166,8 @@ The full command surface. The top level has nine groups — `auth`, `workspaces` | `databases create` | Create a new instant database | | `databases fork` | Fork a database into a new, independent database | | `databases lineage` | Show a database's whole fork family tree | -| `databases attach` | Attach a catalog so its tables are queryable | -| `databases detach` | Detach a previously attached catalog | +| `databases attach` | Attach another database so its tables are queryable | +| `databases detach` | Detach a previously attached database | | `databases use` | Set the current (default) database | | `databases unset` | Clear the current database | | `databases remove` | Delete a database and all its tables | diff --git a/skills/hotdata/SKILL.md b/skills/hotdata/SKILL.md index 6b72408..382ef13 100644 --- a/skills/hotdata/SKILL.md +++ b/skills/hotdata/SKILL.md @@ -59,7 +59,7 @@ A workspace's query worker scales to zero after inactivity. The **first** comman **Agents — list before show.** Run `hotdata databases context list` (optionally `--prefix DATAMODEL`) first; run `hotdata databases context show DATAMODEL` *only if* the stem is listed. A missing stem makes `show` exit 1 — normal for a fresh database, not a failure: don't retry in a loop or run speculative `show` in parallel with other tools. Proceed without context:DATAMODEL until one exists. -**context:DATAMODEL is the durable, shared store** — entities, keys, cross-catalog joins, and the naming/query conventions the whole team relies on. Keep task-scoped exploration (scratch SQL, hypotheses, one-off join checks) in the conversation or local notes; **promote** to context:DATAMODEL only when findings should outlive the session and guide everyone — reconcile against `databases context show DATAMODEL` (if listed), write `./DATAMODEL.md`, then `hotdata databases context push DATAMODEL`. No need to update it after every ad-hoc query. What to write inside the document: [references/DATA_MODEL.template.md](references/DATA_MODEL.template.md) and [references/MODEL_BUILD.md](references/MODEL_BUILD.md). +**context:DATAMODEL is the durable, shared store** — entities, keys, cross-database joins, and the naming/query conventions the whole team relies on. Keep task-scoped exploration (scratch SQL, hypotheses, one-off join checks) in the conversation or local notes; **promote** to context:DATAMODEL only when findings should outlive the session and guide everyone — reconcile against `databases context show DATAMODEL` (if listed), write `./DATAMODEL.md`, then `hotdata databases context push DATAMODEL`. No need to update it after every ad-hoc query. What to write inside the document: [references/DATA_MODEL.template.md](references/DATA_MODEL.template.md) and [references/MODEL_BUILD.md](references/MODEL_BUILD.md). ## Multi-step workflows @@ -110,9 +110,9 @@ hotdata databases unset hotdata databases [--workspace-id ] [--output table|json|yaml] hotdata databases remove [--workspace-id ] -# Attach a catalog so its tables are queryable (enables cross-catalog queries — see below) -hotdata databases attach [--database ] [--alias ] -hotdata databases detach [--database ] +# Attach another database so its tables are queryable (enables cross-database queries — see below) +hotdata databases attach [--database ] [--alias ] # : name, catalog alias, or id +hotdata databases detach [--database ] # or the alias it was attached under # Preferred: load by catalog alias (server declares the table/schema if missing). # Loads csv, json, or parquet — format read from the extension. @@ -140,9 +140,9 @@ hotdata databases tables remove [--database ] [--schema public] [--w - `tables add` — declares a table **with its key and storage layout**, which a load cannot infer. `--key` (repeatable) is what enables the `delete`/`update`/`upsert` load modes on that table. `--sorted-by ` or `=desc` sets sort order; `--partition-by ` partitions on the value, `=month` (or `year`/`day`/`hour`) on a calendar part — one partition per calendar month needs **both** `=year` and `=month`, or every March shares a partition. Sort and partition are fixed once the table exists. `--key-determines` (repeatable) asserts a column's value is fixed by the key: it prunes keyed loads harder, and is **correctness-affecting** — declare it only where the invariant really holds, or a keyed load can leave a duplicate key behind. Re-adding an existing table is a conflict (409), and `tables remove` does not clear the declaration — the table leaves the listing but the name stays declared and still conflicts. So **a key cannot be retrofitted onto a table declared without one**: declare it with `--key` up front, or use a new table name. - `tables load` — publishes to an instant-database table from a local file (`--file`), a remote URL (`--url`), a pre-staged upload (`--upload-id`), or a saved query result (`--result-id`, must belong to the target database). Same `--mode`, `--format`, and `--key` flags as the top-level `load` above. - `tables remove` — drops a table from the instant database. -- `attach` — attaches a **catalog** to an instant database, so the catalog's **live** tables become visible inside that database's query scope. Defaults to the active database; target another with `--database`. `--alias` sets the SQL name the catalog answers to (defaults to the catalog's name). This is how you query an attached catalog's tables and **join across catalogs** — see [Querying across catalogs](#querying-across-catalogs-attach). -- `detach` — removes an attached catalog. Accepts the catalog name/id **or** the alias you attached it under. Defaults to the active database. -- `create --attach [=]` — attach one or more catalogs at creation time (repeatable), e.g. `--attach github --attach salesdb=sales`. +- `attach` — attaches **another instant database** to this one, so its **live** tables become visible inside this database's query scope. Name the other database by name, catalog alias, or id. Defaults to the active database; target another with `--database`. `--alias` sets the SQL name it answers to (defaults to the attached database's own catalog alias). **Required when that alias is `default`** — the stock name for a database created without `--catalog` — since `default` cannot be attached under its own name. This is how you **join across databases** — see [Querying across databases](#querying-across-databases-attach). Read-only: loads still target your own database, and attaching is not transitive — you see what you attached, not what it attached. +- `detach` — removes an attachment, withdrawing visibility without deleting any data. Accepts the attached database's name/id **or** the alias you attached it under. Defaults to the active database. +- `create --attach [=]` — attach one or more databases at creation time (repeatable), e.g. `--attach reference --attach salesdb=sales`. Example: @@ -175,30 +175,37 @@ hotdata databases load --catalog airbnb --table bookings --file removed.csv --mo `removed.csv` carries only the key columns. On a table already declared without a key, name one per load instead: `--mode upsert --key booking_id`. -#### Querying across catalogs (attach) +#### Querying across databases (attach) -**A `hotdata query` runs inside exactly one instant database** — the active database (`hotdata databases use `) or the one named by `--database`. With none set, the query fails with *"a database is required."* That database's query scope sees **only its own catalog plus any catalogs explicitly attached to it** — a workspace catalog is **not** visible just because it exists. Referencing an unattached catalog fails with *"table '\.\.\' not found."* +**A `hotdata query` runs inside exactly one instant database** — the active database (`hotdata databases use `) or the one named by `--database`. With none set, the query fails with *"a database is required."* That database's query scope sees **only its own catalog plus whatever is explicitly attached to it** — another database is **not** visible just because it exists. Referencing something unattached fails with *"table '\.\.\' not found."* -To query an attached catalog's tables, or **join a managed table against an attached catalog's table in one query**, attach the catalog to the database first. The catalog's data stays **live** (synced) — this is not a copy: +To read another database's tables, or **join your own tables against them in one query**, attach it first. The data stays **live** — this is not a copy: ``` -# Attach the 'github' catalog (live) to the active database under alias 'gh' -hotdata databases attach github --alias gh +# Attach the 'reference' database to the active one under alias 'ref' +hotdata databases attach reference --alias ref -# Now both the database's own tables and the attached catalog are in scope: -hotdata query "SELECT * FROM gh.github.issues WHERE state = 'OPEN' LIMIT 10" +# Now both this database's own tables and the attached one are in scope: +hotdata query "SELECT * FROM ref.public.regions LIMIT 10" -# Cross-catalog join: a managed table JOINed against the live attached-catalog table +# Cross-database join: your table JOINed against the attached one, live hotdata query " - SELECT t.id, i.title + SELECT t.id, r.name FROM mycatalog.public.tickets t - JOIN gh.github.issues i ON i.number = t.gh_issue + JOIN ref.public.regions r ON r.id = t.region_id " -hotdata databases detach gh # when finished (optional) +hotdata databases detach ref # when finished (optional) ``` -Without `--alias`, the catalog answers to its own name (`github.github.issues`). Do **not** export a catalog to parquet just to query it — attach is the live, sync-preserving path. +Without `--alias`, the attached database answers to its own catalog alias +(`reference.public.regions`). Notes worth knowing: + +- **Read-only.** Loads always target your own database's catalog, never an attached one. +- **Not transitive.** You see the database you attached, not the ones *it* has attached. +- **The source cannot be deleted while you hold it** — that delete is refused until you detach. An *expiring* source is still removed on its `expires_at`, so check that date before relying on one. + +Do **not** export a database to parquet just to query it — attach is the live path. ### Tables @@ -216,7 +223,7 @@ hotdata databases tables show [--output tabl **`databases tables show`** - Fetches column definitions (`COLUMN`, `DATA_TYPE`, `NULLABLE`) for a single table. -- **`catalog.schema.table`** — three-part form; the catalog resolves to an instant database or an attached source by name. +- **`catalog.schema.table`** — three-part form; the catalog resolves to an instant database or an attached database by name. - **`schema.table`** — two-part form; uses the active database (errors if none is set). - Copy the name directly from `databases tables list` output — both forms match what `list` prints. - **Always use `databases tables show` to inspect columns before writing queries.** @@ -247,7 +254,7 @@ hotdata query status ``` - Default output is `table` (row count and execution time). -- **A query runs inside one instant database** (active database or `--database`); with none set it fails *"a database is required."* The scope sees the database's own catalog **plus any attached catalogs only**. To query an attached catalog's tables or join across catalogs, attach the catalog first — see [Querying across catalogs (attach)](#querying-across-catalogs-attach). +- **A query runs inside one instant database** (active database or `--database`); with none set it fails *"a database is required."* The scope sees the database's own catalog **plus whatever is attached to it only**. To read another database's tables or join across databases, attach it first — see [Querying across databases (attach)](#querying-across-databases-attach). - Use `hotdata databases tables list` and `hotdata databases tables show` for discovery — not `information_schema` via `query`. (Discovery lists every workspace table; queryability still requires the table's catalog to be in the active database's scope.) - **PostgreSQL dialect.** Quote non-lowercase columns with double quotes. To write DuckDB/Postgres/Snowflake SQL instead, pass `--dialect` (server-side transpile, read-only queries) — details in **`hotdata-analytics`**. - Async runs return `query_run_id` → poll with `query status ` (do not re-run the same heavy SQL). `query status` exit codes: `0` succeeded, `1` failed, `2` still running (poll again), `3` succeeded but the result is a truncated/incomplete preview. diff --git a/skills/hotdata/references/DATA_MODEL.template.md b/skills/hotdata/references/DATA_MODEL.template.md index 3e7d514..4bd9141 100644 --- a/skills/hotdata/references/DATA_MODEL.template.md +++ b/skills/hotdata/references/DATA_MODEL.template.md @@ -48,11 +48,11 @@ For each business entity: - **Primary tables:** `catalog.schema.table` - **Key columns:** -## Cross-catalog joins +## Cross-database joins Document safe join paths and caveats (fan-out, timing, different refresh cadence, type mismatches). -> A cross-catalog join runs inside one instant database; each catalog it touches must be **attached** to that database (`hotdata databases attach `) so its live tables are in query scope. Note here which catalogs a join requires attached, and the alias each is attached under. See **`hotdata`** skill → Querying across catalogs. +> A cross-database join runs inside one instant database; every other database it touches must be **attached** to that one (`hotdata databases attach `) so its live tables are in query scope. Note here which databases a join requires attached, and the alias each is attached under. See **`hotdata`** skill → Querying across databases. ## Search & index summary (optional) diff --git a/skills/hotdata/references/MODEL_BUILD.md b/skills/hotdata/references/MODEL_BUILD.md index cf8163f..d9f1a9c 100644 --- a/skills/hotdata/references/MODEL_BUILD.md +++ b/skills/hotdata/references/MODEL_BUILD.md @@ -10,7 +10,7 @@ Optional **deep pass** for a single authoritative markdown document stored as ** ## 1. Discover catalogs and tables -List the catalogs you can query — instant databases you own and any attached catalogs — and the tables they expose: +List the catalogs you can query — your instant database and anything attached to it — and the tables they expose: ```bash hotdata databases list # instant databases (catalogs you own) @@ -74,7 +74,7 @@ For each table, capture where reasonable: 2. **Primary keys** — `id`, `_id`, or composite patterns from names + types. 3. **Foreign keys** — `_id` / `_fk` / name matches to other tables; confirm with connector docs when possible. 4. **Parent–child** — Flattened API/JSON tables (often nested names) and dlt parent keys. -5. **Cross-catalog** — Same logical entity in two catalogs (keys, type mismatches, caveats). +5. **Cross-database** — Same logical entity in two databases (keys, type mismatches, caveats). For **small** schemas (e.g. ≤5 tables in a domain), a short **ASCII diagram** helps. For larger ones, group by domain in prose (e.g. billing, identity, product). @@ -114,7 +114,7 @@ This Markdown body is what you store as **context:DATAMODEL** (`hotdata database - **Overview** — Domains and what the workspace is for. - **Per catalog** — Optional subsection per source; for **deep** models, **repeat** one block per `catalog.schema.table` (grain, column table with name/type/nullable/PK-FK/notes, relationships, queryability, caveats)—the template’s single `####` heading is a pattern to copy for each table. - **Instant databases** — Same treatment as catalog tables where relevant. -- **Cross-catalog joins** — Keys, semantics, type caveats. +- **Cross-database joins** — Keys, semantics, type caveats. - **Search / index summary** — Table, column, index status, intended use. If the workspace has **many** tables (e.g. 50+), add a **table of contents** after the overview (catalog → table counts). diff --git a/skills/hotdata/references/WORKFLOWS.md b/skills/hotdata/references/WORKFLOWS.md index 07c9f93..3def865 100644 --- a/skills/hotdata/references/WORKFLOWS.md +++ b/skills/hotdata/references/WORKFLOWS.md @@ -63,7 +63,7 @@ End-to-end checklists. Use the linked sections for command detail and guardrails 1. [ ] `hotdata databases tables list` (filter with `--schema`/`--table`) — pick text column (BM25) or embedding/text column (vector) 2. [ ] `hotdata search list` — avoid duplicate text/vector indexes on the same column 3. [ ] Create index (address by name): - - [ ] **Instant DB only:** `hotdata search create _--type text --from .public. --column ` (vector: `--type vector [--provider

]`). An external catalog must be attached to an instant database first (`hotdata databases attach`). + - [ ] **Instant DB only:** `hotdata search create _

--type text --from .public. --column ` (vector: `--type vector [--provider

]`). Indexes belong to the database that owns the table: to index a table in another database, build the index there, or load a copy into this one. Attaching does not make it indexable — an attached database is read-only. - [ ] Large build: add `--async`, then `hotdata jobs ` 4. [ ] Search (address the index by name): - [ ] `hotdata search "…" --index _

` @@ -71,20 +71,22 @@ End-to-end checklists. Use the linked sections for command detail and guardrails **Detail:** [hotdata-search INDEXES.md](../subskills/search/references/INDEXES.md) -### Cross-source query (attach a catalog) +### Cross-database query (attach another database) **Skill:** **`hotdata`** -A `hotdata query` runs inside **one** instant database; its scope sees that database's own catalog plus **attached** catalog catalogs only. To query a catalog's tables — or join a managed table against a live catalog table in one query — attach the catalog. (No instant database set → *"a database is required."*; an unattached catalog → *"table not found."*) +A `hotdata query` runs inside **one** instant database; its scope sees that database's own catalog plus whatever is **attached** to it only. To read another database's tables — or join your own tables against them in one query — attach that database. (No instant database set → *"a database is required."*; something unattached → *"table not found."*) 1. [ ] Pick/create the instant database that will be the query context (`hotdata databases use ` or `databases create --catalog `) -2. [ ] Attach the catalog(s) you need (live, sync intact): `hotdata databases attach [--alias ]` - - Or attach at creation: `hotdata databases create --catalog --attach [=]` -3. [ ] Confirm scope: `hotdata databases ` lists attached catalogs -4. [ ] Query across sources: `hotdata query "SELECT … FROM .public. JOIN ..
ON …"` -5. [ ] (Optional) `hotdata databases detach ` when finished; record required attachments in **context:DATAMODEL → Cross-catalog joins** +2. [ ] Attach the database(s) you need (live, no copy): `hotdata databases attach [--alias ]` + - Or attach at creation: `hotdata databases create --catalog --attach [=]` +3. [ ] Confirm scope: `hotdata databases ` lists what is attached +4. [ ] Query across databases: `hotdata query "SELECT … FROM .public. JOIN ..
ON …"` +5. [ ] (Optional) `hotdata databases detach ` when finished; record required attachments in **context:DATAMODEL → Cross-database joins** -**Do not** export a catalog to parquet just to query it — attach is the live, sync-preserving path. +Attaching is read-only (loads still target your own database) and not transitive (you see what you attached, not what it attached). The source cannot be deleted while you hold it, but an *expiring* source still goes on its `expires_at` — check that date before depending on one. + +**Do not** export a database to parquet just to query it — attach is the live path. --- diff --git a/skills/hotdata/subskills/analytics/SKILL.md b/skills/hotdata/subskills/analytics/SKILL.md index 9627790..578bebb 100644 --- a/skills/hotdata/subskills/analytics/SKILL.md +++ b/skills/hotdata/subskills/analytics/SKILL.md @@ -25,7 +25,7 @@ hotdata query status - **`--dialect`** (default `hotsql`): write SQL in `duckdb`/`postgres`/`snowflake` and the server transpiles it to HotSQL before running (e.g. Snowflake `IFF(...)`, DuckDB `len(...)`). Read-only queries only for a non-`hotsql` dialect. - Use **`hotdata databases tables list`** for schema discovery — not `information_schema` via `query`. - Fully qualified names: `..
`, `..
`. -- **Query scope:** every query runs inside one instant database (active or `--database`); it sees that database's own catalog plus **attached** catalogs only. To query an attached catalog's table, or **join a managed table against an attached catalog's table**, attach the catalog first: `hotdata databases attach ` — see **`hotdata`** skill → [Querying across catalogs](../../SKILL.md#querying-across-catalogs-attach). No instant database set → *"a database is required."* +- **Query scope:** every query runs inside one instant database (active or `--database`); it sees that database's own catalog plus whatever is **attached** to it only. To read another database's table, or **join your own table against one**, attach that database first: `hotdata databases attach ` — see **`hotdata`** skill → [Querying across databases](../../SKILL.md#querying-across-databases-attach). No instant database set → *"a database is required."* - Long-running queries may return `query_run_id` → poll with **`query status`** (exit `2` = still running). Do not re-run identical heavy SQL while polling. - For **workspace-wide** joins and naming, load **context:DATAMODEL** when listed (`hotdata databases context list` → `show DATAMODEL`) — see **`hotdata`** skill. diff --git a/skills/hotdata/subskills/search/SKILL.md b/skills/hotdata/subskills/search/SKILL.md index 1fac849..0d6b124 100644 --- a/skills/hotdata/subskills/search/SKILL.md +++ b/skills/hotdata/subskills/search/SKILL.md @@ -48,7 +48,7 @@ hotdata search "" --in ## Indexes (text and vector) -Indexes are an **instant-database** concept. Create names the index (positional) and attaches to a table on an instant database via `--from` — `catalog.schema.table` (the instant database's catalog), or `schema.table` with an active database set. A plain connection catalog is rejected. `list` narrows to the **active database** when one is set; without one it scans the whole workspace. `show`/`remove` resolve the index by name in the active database (or `--database `). +Indexes are an **instant-database** concept, and belong to the database's own tables — an attached database is read-only, so index its tables there rather than here. Create names the index (positional) and attaches to a table via `--from` — `catalog.schema.table` (the database's own catalog), or `schema.table` with an active database set. `list` narrows to the **active database** when one is set; without one it scans the whole workspace. `show`/`remove` resolve the index by name in the active database (or `--database `). ```bash # List — active-database scope when a DB is set, else whole-workspace scan diff --git a/skills/hotdata/subskills/search/references/INDEXES.md b/skills/hotdata/subskills/search/references/INDEXES.md index 7369c45..cc78b06 100644 --- a/skills/hotdata/subskills/search/references/INDEXES.md +++ b/skills/hotdata/subskills/search/references/INDEXES.md @@ -39,7 +39,7 @@ hotdata search create
_embedding_vec --type vector \ --from ..
--column embedding --metric cosine ``` -Indexes are created on **instant databases** only. To index a table that lives in an external catalog, attach the catalog to an instant database first (`hotdata databases attach `), then create the index with the instant database's catalog in `--from` — a bare connection/catalog is rejected. +Indexes are created on **instant databases** only, and on the database's own tables: an index is a write, and an attached database is read-only. To index a table that lives in another database, build the index there, or load a copy into this one — attaching it does not make it indexable here. Large builds: `--async`, then `hotdata jobs list` / `hotdata jobs `. diff --git a/src/commands/databases.rs b/src/commands/databases.rs index fb28145..0e0b617 100644 --- a/src/commands/databases.rs +++ b/src/commands/databases.rs @@ -66,9 +66,10 @@ pub enum DatabasesCommands { #[arg(long)] expires_at: Option, - /// Attach a catalog to the new database so its tables are queryable (repeatable). - /// Accepts a catalog name or id, optionally `catalog=alias` to set the - /// SQL alias it answers to: `--attach github --attach salesdb=sales`. + /// Attach another database to the new one so its tables are queryable + /// (repeatable). Accepts a database name, catalog alias, or id, + /// optionally `database=alias` to set the SQL alias it answers to: + /// `--attach reference --attach salesdb=sales`. #[arg(long = "attach")] attach: Vec, @@ -125,29 +126,38 @@ pub enum DatabasesCommands { output: String, }, - /// Attach a catalog to an instant database so its tables are queryable. + /// Attach another instant database so its tables are queryable here. /// - /// A `query` runs inside one instant database; attaching a catalog makes - /// its live tables visible in that database's scope, so you can join across - /// catalogs in a single query without exporting data. Reachable in SQL as - /// `..
`, or `..
` when + /// A `query` runs inside one instant database; attaching another makes its + /// live tables visible in this database's scope, so you can join across the + /// two in a single query without exporting data. Reachable in SQL as + /// `..
`, or `..
` when /// `--alias` is omitted. + /// + /// Read-only: loads still target this database's own catalog. Not + /// transitive: you see what you attached, not what it attached. Attach { - /// Catalog name or id to attach (e.g. `github`) + /// The database to attach: its name, catalog alias, or id (e.g. `reference`) + #[arg(value_name = "DATABASE")] catalog: String, /// Database id, catalog, or name to attach into (defaults to the current database) #[arg(long, short = 'd')] database: Option, - /// Alias the catalog answers to in SQL. Defaults to the catalog's name. + /// Alias the attached database answers to in SQL. Defaults to its own + /// catalog alias; required when that alias is `default`, which cannot + /// be attached under its own name. #[arg(long)] alias: Option, }, - /// Detach a previously attached catalog from an instant database. + /// Detach a previously attached database, withdrawing visibility without + /// deleting anything. Detach { - /// Catalog name or id to detach + /// The attached database: its name, catalog alias, or id, or the alias + /// it was attached under + #[arg(value_name = "DATABASE")] catalog: String, /// Database id, catalog, or name to detach from (defaults to the current database) @@ -1786,7 +1796,7 @@ pub fn get(workspace_id: &str, id_or_name: &str, format: &str) { format!("{catalog}.{{schema}}.{{table}}").green() ); if !db.attachments.is_empty() { - println!("{}({})", label("attached catalogs:"), db.attachments.len()); + println!("{}({})", label("attached databases:"), db.attachments.len()); for a in &db.attachments { let alias = a .alias @@ -1805,9 +1815,9 @@ pub fn get(workspace_id: &str, id_or_name: &str, format: &str) { } } -/// Attach a connection as a queryable catalog on an instant database, so its -/// live tables are visible inside that database's query scope (cross-source -/// joins without exporting data). Defaults to the current database. +/// Attach another instant database's catalog to this one, so its live tables +/// are visible inside this database's query scope (cross-database joins +/// without exporting data). Defaults to the current database. pub fn attach(workspace_id: &str, catalog: &str, database: Option<&str>, alias: Option<&str>) { use crossterm::style::Stylize; @@ -1831,7 +1841,7 @@ pub fn attach(workspace_id: &str, catalog: &str, database: Option<&str>, alias: Some(a) => println!( "{}", format!( - "Attached '{catalog}' to database '{where_}' as catalog '{a}'.\n\ + "Attached '{catalog}' to database '{where_}' as '{a}'.\n\ Query: hotdata query \"SELECT * FROM {a}..
LIMIT 10\" -d {where_}" ) .green() @@ -1839,16 +1849,16 @@ pub fn attach(workspace_id: &str, catalog: &str, database: Option<&str>, alias: None => println!( "{}", format!( - "Attached '{catalog}' to database '{where_}'. It is reachable by the \ - catalog's name; run `hotdata databases {where_}` to see attached catalogs." + "Attached '{catalog}' to database '{where_}'. It answers to its own \ + catalog alias; run `hotdata databases {where_}` to see what is attached." ) .green() ), } } -/// Detach a previously attached catalog from an instant database. -/// Defaults to the current database. +/// Detach a previously attached database, withdrawing visibility without +/// deleting anything. Defaults to the current database. pub fn detach(workspace_id: &str, catalog: &str, database: Option<&str>) { use crossterm::style::Stylize; diff --git a/tests/databases_cli.rs b/tests/databases_cli.rs index 830d271..b3792d5 100644 --- a/tests/databases_cli.rs +++ b/tests/databases_cli.rs @@ -46,12 +46,12 @@ fn databases_create_help_documents_attach_flag() { assert!(output.status.success()); let help = String::from_utf8_lossy(&output.stdout); assert!(help.contains("--attach"), "help: {help}"); - // The `catalog=alias` form is the documented way to set the SQL alias. - assert!(help.contains("catalog=alias"), "help: {help}"); + // The `database=alias` form is the documented way to set the SQL alias. + assert!(help.contains("database=alias"), "help: {help}"); } #[test] -fn databases_attach_help_documents_connection_and_alias() { +fn databases_attach_help_documents_database_and_alias() { let output = hotdata() .args(["databases", "attach", "--help"]) .output() @@ -63,8 +63,8 @@ fn databases_attach_help_documents_connection_and_alias() { } #[test] -fn databases_attach_requires_a_connection_argument() { - // `catalog` is a required positional — parsing must fail without it. +fn databases_attach_requires_a_database_argument() { + // the database is a required positional — parsing must fail without it. let output = hotdata().args(["databases", "attach"]).output().unwrap(); assert!(!output.status.success()); let combined = format!( @@ -73,7 +73,7 @@ fn databases_attach_requires_a_connection_argument() { String::from_utf8_lossy(&output.stderr) ); assert!( - combined.contains("required") || combined.contains("CATALOG"), + combined.contains("required") || combined.contains("DATABASE"), "output: {combined}" ); }