diff --git a/skills/hotdata/references/WORKFLOWS.md b/skills/hotdata/references/WORKFLOWS.md index 0fe5b04..24ae0e4 100644 --- a/skills/hotdata/references/WORKFLOWS.md +++ b/skills/hotdata/references/WORKFLOWS.md @@ -106,6 +106,8 @@ End-to-end checklists. Use the linked sections for command detail and guardrails hotdata databases load --catalog sales --table customers --url https://example.com/customers.parquet ``` + > Auto-declaring a *new* table recreates the database (no add-table API), which **changes its `id`**. Always reference a managed database by its **catalog** (stable), not the `id` returned by `databases create` — that id goes stale after the next `load` of an undeclared table. Declare tables up front (`databases create --table orders --table customers`) to avoid the recreate. + 3. Confirm and query: ```bash diff --git a/src/databases.rs b/src/databases.rs index c8b0f18..829dbe7 100644 --- a/src/databases.rs +++ b/src/databases.rs @@ -1013,6 +1013,29 @@ pub fn tables_load( } }; let _ = crate::config::save_current_database("default", workspace_id, &new_db.id); + // Managed databases have no add-table endpoint, so declaring a new table + // is a delete + recreate — which mints a NEW database id. Surface that + // explicitly: the id printed by `databases create` is now stale, and + // id-based automation (e.g. `databases delete `) would + // otherwise fail with "no database with id". Reference by catalog instead. + { + use crossterm::style::Stylize; + let catalog = db + .default_catalog + .as_deref() + .or(db.name.as_deref()) + .unwrap_or(&db.id); + eprintln!( + "{}", + format!( + "note: table '{table}' was not declared — recreated database '{catalog}' to add it \ + (id {} → {}). Managed databases are recreated when a new table is loaded; \ + reference them by catalog ('{catalog}'), not the create-time id.", + db.id, new_db.id + ) + .yellow() + ); + } let new_path = managed_table_load_path(&new_db.default_connection_id, schema, table); let spinner = crate::util::spinner("Loading table..."); let result = api.post_raw(&new_path, &body).unwrap_or_else(|e| {