Skip to content

Commit ca02e32

Browse files
authored
feat(connections): Add connection command to list/view/create connections via the CLI
1 parent 1604a4a commit ca02e32

File tree

9 files changed

+827
-47
lines changed

9 files changed

+827
-47
lines changed

Cargo.lock

Lines changed: 83 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rand = "0.8"
2727
sha2 = "0.10"
2828
tiny_http = "0.12"
2929
comfy-table = "7"
30+
inquire = "0.9.4"
3031
indicatif = "0.17"
3132
nix = { version = "0.29", features = ["fs"] }
3233
flate2 = "1"

skills/hotdata-cli/SKILL.md

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: hotdata-cli
3-
description: Use this skill when the user wants to run hotdata CLI commands, query the HotData API, list workspaces, list connections, list tables, manage datasets, execute SQL queries, or interact with the hotdata service. Activate when the user says "run hotdata", "query hotdata", "list workspaces", "list connections", "list tables", "list datasets", "create a dataset", "upload a dataset", "execute a query", or asks you to use the hotdata CLI.
3+
description: Use this skill when the user wants to run hotdata CLI commands, query the HotData API, list workspaces, list connections, create connections, list tables, manage datasets, execute SQL queries, or interact with the hotdata service. Activate when the user says "run hotdata", "query hotdata", "list workspaces", "list connections", "create a connection", "list tables", "list datasets", "create a dataset", "upload a dataset", "execute a query", or asks you to use the hotdata CLI.
44
version: 0.1.3
55
---
66

@@ -36,7 +36,66 @@ Returns workspaces with `public_id`, `name`, `active`, `favorite`, `provision_st
3636
```
3737
hotdata connections list [--workspace-id <workspace_id>] [--format table|json|yaml]
3838
```
39-
Routes via API gateway using `X-Workspace-Id` header.
39+
Returns `id`, `name`, `source_type` for each connection in the workspace.
40+
41+
### Create a Connection
42+
43+
#### Step 1 — Discover available connection types
44+
```
45+
hotdata connections create list [--workspace-id <workspace_id>] [--format table|json|yaml]
46+
```
47+
Returns all available connection types with `name` and `label`.
48+
49+
#### Step 2 — Inspect the schema for a specific type
50+
```
51+
hotdata connections create list <name> [--workspace-id <workspace_id>] [--format json]
52+
```
53+
Returns `config` and `auth` JSON Schema objects describing all required and optional fields for that connection type. Use `--format json` to get the full schema detail.
54+
55+
- `config` — connection configuration fields (host, port, database, etc.). May be `null` for services that need no configuration.
56+
- `auth` — authentication fields (password, token, credentials, etc.). May be `null` for services that need no authentication. May be a `oneOf` with multiple authentication method options.
57+
58+
#### Step 3 — Create the connection
59+
```
60+
hotdata connections create \
61+
--name "my-connection" \
62+
--type <source_type> \
63+
--config '<json object>' \
64+
[--workspace-id <workspace_id>]
65+
```
66+
67+
The `--config` JSON object must contain all **required** fields from `config` plus the **auth fields** merged in at the top level. Auth fields are not nested — they sit alongside config fields in the same object.
68+
69+
Example for PostgreSQL (required: `host`, `port`, `user`, `database` + auth field `password`):
70+
```
71+
hotdata connections create \
72+
--name "my-postgres" \
73+
--type postgres \
74+
--config '{"host":"db.example.com","port":5432,"user":"myuser","database":"mydb","password":"..."}'
75+
```
76+
77+
**Security: never expose credentials in plain text.** Passwords, tokens, API keys, and any field with `"format": "password"` in the schema must never be hardcoded as literal strings in CLI commands. Always use one of these safe approaches:
78+
79+
- Read from an environment variable:
80+
```
81+
--config "{\"host\":\"db.example.com\",\"port\":5432,\"user\":\"myuser\",\"database\":\"mydb\",\"password\":\"$DB_PASSWORD\"}"
82+
```
83+
- Read a credential from a file and inject it:
84+
```
85+
--config "{\"token\":\"$(cat ~/.secrets/my-token)\"}"
86+
```
87+
88+
**Field-building rules from the schema:**
89+
90+
- Include all fields listed in `config.required` — these are mandatory.
91+
- Include optional config fields only if the user provides values for them.
92+
- For `auth` with a single method (no `oneOf`): include all `auth.required` fields in the config object.
93+
- For `auth` with `oneOf`: pick one authentication method and include only its required fields.
94+
- Fields with `"format": "password"` are credentials — apply the security rules above.
95+
- Fields with `"type": "integer"` must be JSON numbers, not strings (e.g. `"port": 5432` not `"port": "5432"`).
96+
- Fields with `"type": "boolean"` must be JSON booleans (e.g. `"use_tls": true`).
97+
- Fields with `"type": "array"` must be JSON arrays (e.g. `"spreadsheet_ids": ["abc", "def"]`).
98+
- Nested `oneOf` fields must be a JSON object including a `"type"` discriminator field matching the chosen variant's `const` value.
4099

41100
### List Tables and Columns
42101
```
@@ -136,3 +195,19 @@ hotdata init # Create ~/.hotdata/config.yml
136195
```
137196
hotdata query "SELECT 1"
138197
```
198+
199+
## Workflow: Creating a Connection
200+
201+
1. List available connection types:
202+
```
203+
hotdata connections create list
204+
```
205+
2. Inspect the schema for the desired type:
206+
```
207+
hotdata connections create list <type_name> --format json
208+
```
209+
3. Collect required config and auth field values from the user or environment. **Never hardcode credentials — use env vars or files.**
210+
4. Create the connection:
211+
```
212+
hotdata connections create --name "my-connection" --type <type_name> --config '<json>'
213+
```

src/command.rs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub enum Commands {
2020
id: Option<String>,
2121

2222
/// Workspace ID (defaults to first workspace from login)
23-
#[arg(long)]
23+
#[arg(long, global = true)]
2424
workspace_id: Option<String>,
2525

2626
/// Output format (used with dataset ID)
@@ -63,6 +63,10 @@ pub enum Commands {
6363

6464
/// Manage workspace connections
6565
Connections {
66+
/// Workspace ID (defaults to first workspace from login)
67+
#[arg(long, global = true)]
68+
workspace_id: Option<String>,
69+
6670
#[command(subcommand)]
6771
command: ConnectionsCommands,
6872
},
@@ -285,25 +289,33 @@ pub enum WorkspaceCommands {
285289
},
286290
}
287291

292+
#[derive(Subcommand)]
293+
pub enum ConnectionsCreateCommands {
294+
/// List available connection types, or get details for a specific type
295+
List {
296+
/// Connection type name (e.g. postgres, mysql); omit to list all
297+
name: Option<String>,
298+
299+
/// Output format
300+
#[arg(long, default_value = "table", value_parser = ["table", "json", "yaml"])]
301+
format: String,
302+
},
303+
}
304+
288305
#[derive(Subcommand)]
289306
pub enum ConnectionsCommands {
307+
/// Interactively create a new connection
308+
New,
309+
290310
/// List all connections for a workspace
291311
List {
292-
/// Workspace ID (defaults to first workspace from login)
293-
#[arg(long)]
294-
workspace_id: Option<String>,
295-
296312
/// Output format
297313
#[arg(long, default_value = "table", value_parser = ["table", "json", "yaml"])]
298314
format: String,
299315
},
300316

301317
/// Get details for a specific connection
302318
Get {
303-
/// Workspace ID (defaults to first workspace from login)
304-
#[arg(long)]
305-
workspace_id: Option<String>,
306-
307319
/// Connection ID
308320
connection_id: String,
309321

@@ -312,35 +324,30 @@ pub enum ConnectionsCommands {
312324
format: String,
313325
},
314326

315-
/// Create a new connection in a workspace
327+
/// Create a new connection, or list/inspect available connection types
316328
Create {
317-
/// Workspace ID (defaults to first workspace from login)
318-
#[arg(long)]
319-
workspace_id: Option<String>,
329+
#[command(subcommand)]
330+
command: Option<ConnectionsCreateCommands>,
320331

321332
/// Connection name
322333
#[arg(long)]
323-
name: String,
334+
name: Option<String>,
324335

325-
/// Connection type
336+
/// Connection source type (e.g. postgres, mysql, snowflake)
326337
#[arg(long = "type")]
327-
conn_type: String,
338+
source_type: Option<String>,
328339

329-
/// Connection config as JSON string
340+
/// Connection config as a JSON object
330341
#[arg(long)]
331-
config: String,
342+
config: Option<String>,
332343

333344
/// Output format
334-
#[arg(long, default_value = "yaml", value_parser = ["table", "json", "yaml"])]
345+
#[arg(long, default_value = "table", value_parser = ["table", "json", "yaml"])]
335346
format: String,
336347
},
337348

338349
/// Update a connection in a workspace
339350
Update {
340-
/// Workspace ID (defaults to first workspace from login)
341-
#[arg(long)]
342-
workspace_id: Option<String>,
343-
344351
/// Connection ID
345352
connection_id: String,
346353

@@ -363,10 +370,6 @@ pub enum ConnectionsCommands {
363370

364371
/// Delete a connection from a workspace
365372
Delete {
366-
/// Workspace ID (defaults to first workspace from login)
367-
#[arg(long)]
368-
workspace_id: Option<String>,
369-
370373
/// Connection ID
371374
connection_id: String,
372375
},

0 commit comments

Comments
 (0)