Skip to content

Commit a26b60b

Browse files
committed
fix(databases): add default_catalog to Database struct; use catalog in all output
- Add `default_catalog` field to `Database` struct so `databases show` and table commands use the correct SQL alias instead of falling back to the display name - Use default_catalog (falling back to name, then "default") in databases show sql_prefix, tables list full_name, tables load, and tables delete output - Fix --catalog arg doc: remove stale 24h expiry claim - Update README and skills/hotdata/SKILL.md to document --name as display name and --catalog as the SQL alias, with corrected examples
1 parent 1b436ea commit a26b60b

4 files changed

Lines changed: 39 additions & 30 deletions

File tree

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,14 @@ hotdata connections create --name "my-conn" --type postgres --config '{"host":".
130130

131131
## Databases
132132

133-
Managed databases are Hotdata-owned catalogs you create and populate yourself (no remote source to sync). Query them with SQL as `database_name.schema.table` — the database name is the connection name.
133+
Managed databases are Hotdata-owned catalogs you create and populate yourself (no remote source to sync). Query them with SQL as `<catalog>.schema.table`.
134134

135135
```sh
136136
hotdata databases list [-w <id>] [-o table|json|yaml]
137-
hotdata databases create --name <name> [--table <table> ...] [--schema public] [-o table|json|yaml]
137+
hotdata databases create [--name <display_name>] [--catalog <alias>] [--table <table> ...] [--schema public] [--expires-at <duration|timestamp>] [-o table|json|yaml]
138138
hotdata databases <name_or_id> [-o table|json|yaml]
139139
hotdata databases delete <name_or_id>
140-
hotdata databases run [--database <id>] [--description <label>] [--schema public] [--table <table> ...] [--expires-at <duration|timestamp>] <cmd> [args...]
140+
hotdata databases run [--database <id>] [--name <label>] [--schema public] [--table <table> ...] [--expires-at <duration|timestamp>] <cmd> [args...]
141141
hotdata databases <id> run <cmd> [args...]
142142

143143
hotdata databases tables list <database> [--schema <name>] [-o table|json|yaml]
@@ -146,15 +146,15 @@ hotdata databases tables load <database> <table> --upload-id <id> [--schema publ
146146
hotdata databases tables delete <database> <table> [--schema public]
147147
```
148148

149-
- `create` registers a managed connection (`source_type: managed`) with no external credentials. Use `--table` to declare tables up front (required before `tables load` on the current API).
149+
- `create` registers a managed connection with no external credentials. `--name` is a human-readable display name; `--catalog` sets the SQL alias used in queries (`SELECT … FROM <catalog>.schema.table`) and must be `[a-z_][a-z0-9_]*`. Use `--table` to declare tables up front (required before `tables load` on the current API).
150150
- `tables load` uploads a **parquet** file (or uses a staged `upload_id` from `POST /v1/files`) and publishes it as the table generation (`replace` mode).
151-
- `run` mints a database-scoped JWT and execs `<cmd>` with `HOTDATA_DATABASE_TOKEN`, `HOTDATA_DATABASE_REFRESH_TOKEN`, `HOTDATA_DATABASE`, `HOTDATA_WORKSPACE`, and `HOTDATA_API_URL` injected into its environment. Pass a database id (group-positional `<id>` like `sandbox run`, or `--database <id>`) to scope an existing database; omit both to auto-create a scratch one using `--description` / `--schema` / `--table` / `--expires-at`. Useful for launching an agent or child process whose API access is restricted to a single database.
151+
- `run` mints a database-scoped JWT and execs `<cmd>` with `HOTDATA_DATABASE_TOKEN`, `HOTDATA_DATABASE_REFRESH_TOKEN`, `HOTDATA_DATABASE`, `HOTDATA_WORKSPACE`, and `HOTDATA_API_URL` injected into its environment. Pass a database id (group-positional `<id>` like `sandbox run`, or `--database <id>`) to scope an existing database; omit both to auto-create a scratch one using `--name` / `--schema` / `--table` / `--expires-at`. Useful for launching an agent or child process whose API access is restricted to a single database.
152152
- For CSV/JSON uploads without a managed database, use `hotdata datasets create` instead (`datasets.main.*`).
153153

154154
Example:
155155

156156
```sh
157-
hotdata databases create --name sales --table orders
157+
hotdata databases create --name "Sales reporting" --catalog sales --table orders
158158
hotdata databases tables load sales orders --file ./orders.parquet
159159
hotdata query "SELECT count(*) FROM sales.public.orders"
160160
```

skills/hotdata/SKILL.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -187,39 +187,39 @@ hotdata connections create \
187187

188188
```
189189
hotdata databases list [--workspace-id <workspace_id>] [--output table|json|yaml]
190-
hotdata databases create [--name <catalog_name>] [--table <table> ...] [--schema public] [--expires-at <duration|timestamp>] [--workspace-id <workspace_id>] [--output table|json|yaml]
191-
hotdata databases set <id_or_description>
192-
hotdata databases <id_or_description> [--workspace-id <workspace_id>] [--output table|json|yaml]
193-
hotdata databases delete <id_or_description> [--workspace-id <workspace_id>]
194-
hotdata databases run [--database <id>] [--name <catalog_name>] [--schema public] [--table <table> ...] [--expires-at <duration|timestamp>] [--workspace-id <workspace_id>] <cmd> [args...]
190+
hotdata databases create [--name <display_name>] [--catalog <alias>] [--table <table> ...] [--schema public] [--expires-at <duration|timestamp>] [--workspace-id <workspace_id>] [--output table|json|yaml]
191+
hotdata databases set <id_or_name>
192+
hotdata databases <id_or_name> [--workspace-id <workspace_id>] [--output table|json|yaml]
193+
hotdata databases delete <id_or_name> [--workspace-id <workspace_id>]
194+
hotdata databases run [--database <id>] [--name <label>] [--schema public] [--table <table> ...] [--expires-at <duration|timestamp>] [--workspace-id <workspace_id>] <cmd> [args...]
195195
hotdata databases <id> run <cmd> [args...]
196196
197197
# Dot-notation shorthand for load: database.table or database.schema.table
198198
hotdata databases load <database.table> [--file ./data.parquet] [--url <url>] [--upload-id <id>] [--workspace-id <workspace_id>]
199199
200-
hotdata databases tables list [--database <id_or_desc>] [--schema <name>] [--workspace-id <workspace_id>] [--output table|json|yaml]
201-
hotdata databases tables load <table> [--database <id_or_desc>] [--schema public] [--file ./data.parquet] [--url <url>] [--upload-id <id>] [--workspace-id <workspace_id>]
202-
hotdata databases tables delete <table> [--database <id_or_desc>] [--schema public] [--workspace-id <workspace_id>]
200+
hotdata databases tables list [--database <id_or_name>] [--schema <name>] [--workspace-id <workspace_id>] [--output table|json|yaml]
201+
hotdata databases tables load <table> [--database <id_or_name>] [--schema public] [--file ./data.parquet] [--url <url>] [--upload-id <id>] [--workspace-id <workspace_id>]
202+
hotdata databases tables delete <table> [--database <id_or_name>] [--schema public] [--workspace-id <workspace_id>]
203203
```
204204

205205
- `list` — all managed databases in the workspace.
206-
- `create` — creates a new managed database. `--name` is an optional catalog alias used in queries (`SELECT … FROM <name>.public.<table>`); must be `[a-z_][a-z0-9_]*`. `--expires-at` accepts relative durations (`24h`, `7d`, `90m`) or an RFC 3339 timestamp; defaults to `24h` when omitted. Repeat `--table` to declare tables up front.
207-
- `set` — saves `<id_or_description>` as the active database. Subsequent `databases tables` and `context` commands use it automatically.
208-
- `<id_or_description>` — inspect one database (id, description, expires_at).
206+
- `create` — creates a new managed database. `--name` is an optional human-readable display name. `--catalog` sets the SQL alias used in queries (`SELECT … FROM <catalog>.schema.table`); must be `[a-z_][a-z0-9_]*`. `--expires-at` accepts relative durations (`24h`, `7d`, `90m`) or an RFC 3339 timestamp; omitting means no expiry. Repeat `--table` to declare tables up front.
207+
- `set` — saves `<id_or_name>` as the active database. Subsequent `databases tables` and `context` commands use it automatically.
208+
- `<id_or_name>` — inspect one database (id, catalog, name, expires_at).
209209
- `delete` — removes the managed database; clears the active-database config if it matched.
210210
- `load` — shorthand with dot notation (`database.table` or `database.schema.table`). Schema defaults to `public`.
211-
- `tables list` — lists tables with `TABLE` (`<database_id>.<schema>.<table>`), `SYNCED`, `LAST_SYNC`. Uses active database when `--database` is omitted.
211+
- `tables list` — lists tables with `TABLE` (`<catalog>.<schema>.<table>`), `SYNCED`, `LAST_SYNC`. Uses active database when `--database` is omitted.
212212
- `tables load` — uploads a local parquet file (`--file`), a remote parquet URL (`--url`), or a pre-staged upload (`--upload-id`) and publishes with **replace** mode.
213213
- `tables delete` — drops a table from the managed database.
214214
- `run` — mints a database-scoped JWT (via `POST /v1/auth/database`) and execs `<cmd>` with `HOTDATA_DATABASE_TOKEN`, `HOTDATA_DATABASE_REFRESH_TOKEN`, `HOTDATA_DATABASE`, `HOTDATA_WORKSPACE`, and `HOTDATA_API_URL` injected. Pass a database id as a group positional (`hotdata databases <id> run ...`, sandbox-style) or via `--database <id>`; omit both to auto-create a scratch database using `--name` / `--schema` / `--table` / `--expires-at`. Use this to launch an agent or child process whose API access is scoped to a single database. The minted JWT carries `database`, `workspaces`, `permissions:["read","write"]`, `source:"database_token"`. The session is persisted at `~/.hotdata/database_session.json` (mode `0600`); the child's exit code is propagated.
215215

216216
Example:
217217

218218
```
219-
hotdata databases create --name sales --table orders
219+
hotdata databases create --name "Sales reporting" --catalog sales --table orders
220220
hotdata databases set <returned-id>
221221
hotdata databases tables load orders --file ./orders.parquet
222-
hotdata query "SELECT count(*) FROM <database_id>.public.orders"
222+
hotdata query "SELECT count(*) FROM sales.public.orders"
223223
```
224224

225225
### List Tables and Columns

src/command.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,7 @@ pub enum DatabasesCommands {
568568
name: Option<String>,
569569

570570
/// SQL catalog alias used in queries: SELECT … FROM <catalog>.schema.table.
571-
/// Must be [a-z_][a-z0-9_]*, globally unique. When provided the database
572-
/// defaults to no expiry; omit for an anonymous 24h sandbox.
571+
/// Must be [a-z_][a-z0-9_]*, globally unique.
573572
#[arg(long)]
574573
catalog: Option<String>,
575574

src/databases.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub struct Database {
2424
pub id: String,
2525
#[serde(default)]
2626
pub name: Option<String>,
27+
#[serde(default)]
28+
pub default_catalog: Option<String>,
2729
pub default_connection_id: String,
2830
#[serde(default)]
2931
attachments: Vec<DatabaseAttachment>,
@@ -225,11 +227,11 @@ pub fn is_parquet_path(path: &str) -> bool {
225227
|| Path::new(path).extension().and_then(|e| e.to_str()) == Some("parquet")
226228
}
227229

228-
fn table_rows(tables: Vec<InfoTable>) -> Vec<TableRow> {
230+
fn table_rows(catalog: &str, tables: Vec<InfoTable>) -> Vec<TableRow> {
229231
tables
230232
.into_iter()
231233
.map(|t| TableRow {
232-
full_name: format!("default.{}.{}", t.schema, t.table),
234+
full_name: format!("{catalog}.{}.{}", t.schema, t.table),
233235
schema: t.schema,
234236
table: t.table,
235237
synced: t.synced,
@@ -393,7 +395,7 @@ pub fn list(workspace_id: &str, format: &str) {
393395
eprintln!("{}", "No databases found.".dark_grey());
394396
eprintln!(
395397
"{}",
396-
"Create one with: hotdata databases create --name <catalog_name>".dark_grey()
398+
"Create one with: hotdata databases create --catalog <alias>".dark_grey()
397399
);
398400
} else {
399401
let rows: Vec<Vec<String>> = body
@@ -427,12 +429,17 @@ pub fn get(workspace_id: &str, id_or_name: &str, format: &str) {
427429
if let Some(n) = &db.name {
428430
println!("{}{}", label("name:"), n.clone().cyan());
429431
}
432+
if let Some(c) = &db.default_catalog {
433+
println!("{}{}", label("catalog:"), c.clone().cyan());
434+
}
430435
println!(
431436
"{}{}",
432437
label("default_connection_id:"),
433438
db.default_connection_id.clone().dark_cyan()
434439
);
435-
let catalog = db.name.as_deref().unwrap_or("default");
440+
let catalog = db.default_catalog.as_deref()
441+
.or(db.name.as_deref())
442+
.unwrap_or("default");
436443
println!(
437444
"{}{}",
438445
label("sql_prefix:"),
@@ -694,9 +701,10 @@ pub fn tables_list(workspace_id: &str, database: Option<&str>, schema: Option<&s
694701
let database = resolve_current_database(database, workspace_id);
695702
let api = ApiClient::new(Some(workspace_id));
696703
let db = resolve_database(&api, &database);
704+
let catalog = db.default_catalog.as_deref().or(db.name.as_deref()).unwrap_or("default");
697705
let tables = collect_tables(&api, &db.default_connection_id, schema);
698706

699-
let rows = table_rows(tables);
707+
let rows = table_rows(catalog, tables);
700708

701709
match format {
702710
"json" => println!("{}", serde_json::to_string_pretty(&rows).unwrap()),
@@ -785,7 +793,8 @@ pub fn tables_load(
785793
}
786794
};
787795

788-
let full_name = format!("default.{}.{}", result.schema_name, result.table_name);
796+
let catalog = db.default_catalog.as_deref().or(db.name.as_deref()).unwrap_or("default");
797+
let full_name = format!("{catalog}.{}.{}", result.schema_name, result.table_name);
789798
println!("{}", "Table loaded".green());
790799
println!("full_name: {}", full_name.clone().green());
791800
println!("rows: {}", result.row_count);
@@ -821,9 +830,10 @@ pub fn tables_delete(workspace_id: &str, database: Option<&str>, table: &str, sc
821830
std::process::exit(1);
822831
}
823832

833+
let catalog = db.default_catalog.as_deref().or(db.name.as_deref()).unwrap_or("default");
824834
println!(
825835
"{}",
826-
format!("Table 'default.{}.{}' deleted.", schema, table).green()
836+
format!("Table '{catalog}.{schema}.{table}' deleted.").green()
827837
);
828838
}
829839

@@ -1024,7 +1034,7 @@ mod tests {
10241034

10251035
#[test]
10261036
fn table_rows_uses_default_prefix() {
1027-
let rows = table_rows(vec![InfoTable {
1037+
let rows = table_rows("default", vec![InfoTable {
10281038
connection: "ignored".into(),
10291039
schema: "public".into(),
10301040
table: "orders".into(),

0 commit comments

Comments
 (0)