Skip to content

Commit b451f72

Browse files
committed
clean up connections commands and include getter
1 parent 398f839 commit b451f72

5 files changed

Lines changed: 91 additions & 130 deletions

File tree

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ API key priority (lowest to highest): config file → `HOTDATA_API_KEY` env var
5151
| Command | Subcommands | Description |
5252
| :-- | :-- | :-- |
5353
| `auth` | `status`, `logout` | Authenticate (run without subcommand to log in) |
54-
| `workspaces` | `list`, `set`, `get`, `create`, `update` | Manage workspaces |
55-
| `connections` | `list`, `get`, `create`, `refresh`, `update`, `delete`, `new` | Manage connections |
54+
| `workspaces` | `list`, `set` | Manage workspaces |
55+
| `connections` | `list`, `create`, `refresh`, `new` | Manage connections |
5656
| `tables` | `list` | List tables and columns |
5757
| `datasets` | `list`, `create` | Manage uploaded datasets |
5858
| `query` | | Execute a SQL query |
@@ -85,13 +85,14 @@ hotdata workspaces set [<workspace_id>]
8585
## Connections
8686

8787
```sh
88-
hotdata connections list [--workspace-id <id>] [--format table|json|yaml]
89-
hotdata connections get <connection_id> [--workspace-id <id>] [--format yaml|json|table]
90-
hotdata connections refresh <connection_id> [--workspace-id <id>]
91-
hotdata connections new [--workspace-id <id>]
88+
hotdata connections list [-w <id>] [-o table|json|yaml]
89+
hotdata connections <connection_id> [-w <id>] [-o table|json|yaml]
90+
hotdata connections refresh <connection_id> [-w <id>]
91+
hotdata connections new [-w <id>]
9292
```
9393

9494
- `list` returns `id`, `name`, `source_type` for each connection.
95+
- Pass a connection ID to view details (id, name, source type, table counts).
9596
- `refresh` triggers a schema refresh for a connection.
9697
- `new` launches an interactive connection creation wizard.
9798

skills/hotdata-cli/SKILL.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ Returns workspaces with `public_id`, `name`, `active`, `favorite`, `provision_st
3939

4040
### List Connections
4141
```
42-
hotdata connections list [--workspace-id <workspace_id>] [--format table|json|yaml]
42+
hotdata connections list [-w <workspace_id>] [-o table|json|yaml]
43+
hotdata connections <connection_id> [-w <workspace_id>] [-o table|json|yaml]
4344
```
44-
Returns `id`, `name`, `source_type` for each connection in the workspace.
45+
- `list` returns `id`, `name`, `source_type` for each connection.
46+
- Pass a connection ID to view details (id, name, source type, table counts).
4547

4648
### Create a Connection
4749

src/command.rs

Lines changed: 8 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,19 @@ pub enum Commands {
5151

5252
/// Manage workspace connections
5353
Connections {
54+
/// Connection ID to show details
55+
id: Option<String>,
56+
5457
/// Workspace ID (defaults to first workspace from login)
5558
#[arg(long, short = 'w', global = true)]
5659
workspace_id: Option<String>,
5760

61+
/// Output format (used with connection ID)
62+
#[arg(long = "output", short = 'o', default_value = "table", value_parser = ["table", "json", "yaml"])]
63+
output: String,
64+
5865
#[command(subcommand)]
59-
command: ConnectionsCommands,
66+
command: Option<ConnectionsCommands>,
6067
},
6168

6269
/// Manage tables in a workspace
@@ -351,55 +358,6 @@ pub enum WorkspaceCommands {
351358
/// Workspace ID to set as default (omit for interactive selection)
352359
workspace_id: Option<String>,
353360
},
354-
355-
/// Get details for a workspace
356-
Get {
357-
/// Workspace ID (defaults to first workspace from login)
358-
#[arg(long, short = 'w')]
359-
workspace_id: Option<String>,
360-
361-
/// Output format
362-
#[arg(long = "output", short = 'o', default_value = "yaml", value_parser = ["table", "json", "yaml"])]
363-
output: String,
364-
},
365-
366-
/// Create a new workspace
367-
Create {
368-
/// Workspace name
369-
#[arg(long)]
370-
name: String,
371-
372-
/// Workspace description
373-
#[arg(long, default_value = "")]
374-
description: String,
375-
376-
/// Organization ID for the workspace
377-
#[arg(long)]
378-
organization_id: String,
379-
380-
/// Output format
381-
#[arg(long = "output", short = 'o', default_value = "yaml", value_parser = ["table", "json", "yaml"])]
382-
output: String,
383-
},
384-
385-
/// Update an existing workspace
386-
Update {
387-
/// Workspace ID (defaults to first workspace from login)
388-
#[arg(long, short = 'w')]
389-
workspace_id: Option<String>,
390-
391-
/// New workspace name
392-
#[arg(long)]
393-
name: Option<String>,
394-
395-
/// New workspace description
396-
#[arg(long)]
397-
description: Option<String>,
398-
399-
/// Output format
400-
#[arg(long = "output", short = 'o', default_value = "yaml", value_parser = ["table", "json", "yaml"])]
401-
output: String,
402-
},
403361
}
404362

405363
#[derive(Subcommand)]
@@ -427,16 +385,6 @@ pub enum ConnectionsCommands {
427385
output: String,
428386
},
429387

430-
/// Get details for a specific connection
431-
Get {
432-
/// Connection ID
433-
connection_id: String,
434-
435-
/// Output format
436-
#[arg(long = "output", short = 'o', default_value = "yaml", value_parser = ["table", "json", "yaml"])]
437-
output: String,
438-
},
439-
440388
/// Create a new connection, or list/inspect available connection types
441389
Create {
442390
#[command(subcommand)]
@@ -459,39 +407,11 @@ pub enum ConnectionsCommands {
459407
output: String,
460408
},
461409

462-
/// Update a connection in a workspace
463-
Update {
464-
/// Connection ID
465-
connection_id: String,
466-
467-
/// New connection name
468-
#[arg(long)]
469-
name: Option<String>,
470-
471-
/// New connection type
472-
#[arg(long = "type")]
473-
conn_type: Option<String>,
474-
475-
/// New connection config as JSON string
476-
#[arg(long)]
477-
config: Option<String>,
478-
479-
/// Output format
480-
#[arg(long = "output", short = 'o', default_value = "yaml", value_parser = ["table", "json", "yaml"])]
481-
output: String,
482-
},
483-
484410
/// Refresh a connection's schema
485411
Refresh {
486412
/// Connection ID
487413
connection_id: String,
488414
},
489-
490-
/// Delete a connection from a workspace
491-
Delete {
492-
/// Connection ID
493-
connection_id: String,
494-
},
495415
}
496416

497417
#[derive(Subcommand)]

src/connections.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,41 @@ struct Connection {
7070
source_type: String,
7171
}
7272

73+
#[derive(Deserialize, Serialize)]
74+
struct ConnectionDetail {
75+
id: String,
76+
name: String,
77+
source_type: String,
78+
#[serde(default)]
79+
table_count: u64,
80+
#[serde(default)]
81+
synced_table_count: u64,
82+
}
83+
7384
#[derive(Deserialize)]
7485
struct ListResponse {
7586
connections: Vec<Connection>,
7687
}
7788

89+
pub fn get(workspace_id: &str, connection_id: &str, format: &str) {
90+
let api = ApiClient::new(Some(workspace_id));
91+
let detail: ConnectionDetail = api.get(&format!("/connections/{connection_id}"));
92+
93+
match format {
94+
"json" => println!("{}", serde_json::to_string_pretty(&detail).unwrap()),
95+
"yaml" => print!("{}", serde_yaml::to_string(&detail).unwrap()),
96+
"table" => {
97+
use crossterm::style::Stylize;
98+
let label = |l: &str| format!("{:<16}", l).dark_grey().to_string();
99+
println!("{}{}", label("id:"), detail.id.dark_cyan());
100+
println!("{}{}", label("name:"), detail.name.white());
101+
println!("{}{}", label("source_type:"), detail.source_type.green());
102+
println!("{}{}", label("tables:"), format!("{} synced / {} total", detail.synced_table_count.to_string().cyan(), detail.table_count.to_string().cyan()));
103+
}
104+
_ => unreachable!(),
105+
}
106+
}
107+
78108
pub fn create(
79109
workspace_id: &str,
80110
name: &str,

src/main.rs

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -116,47 +116,55 @@ fn main() {
116116
Commands::Workspaces { command } => match command {
117117
WorkspaceCommands::List { output } => workspace::list(&output),
118118
WorkspaceCommands::Set { workspace_id } => workspace::set(workspace_id.as_deref()),
119-
_ => eprintln!("not yet implemented"),
120119
},
121-
Commands::Connections { workspace_id, command } => {
120+
Commands::Connections { id, workspace_id, output, command } => {
122121
let workspace_id = resolve_workspace(workspace_id);
123-
match command {
124-
ConnectionsCommands::New => connections_new::run(&workspace_id),
125-
ConnectionsCommands::List { output } => {
126-
connections::list(&workspace_id, &output)
127-
}
128-
ConnectionsCommands::Create { command, name, source_type, config, output } => {
129-
match command {
130-
Some(ConnectionsCreateCommands::List { name, output }) => {
131-
match name.as_deref() {
132-
Some(name) => connections::types_get(&workspace_id, name, &output),
133-
None => connections::types_list(&workspace_id, &output),
122+
if let Some(id) = id {
123+
connections::get(&workspace_id, &id, &output)
124+
} else {
125+
match command {
126+
Some(ConnectionsCommands::New) => connections_new::run(&workspace_id),
127+
Some(ConnectionsCommands::List { output }) => {
128+
connections::list(&workspace_id, &output)
129+
}
130+
Some(ConnectionsCommands::Create { command, name, source_type, config, output }) => {
131+
match command {
132+
Some(ConnectionsCreateCommands::List { name, output }) => {
133+
match name.as_deref() {
134+
Some(name) => connections::types_get(&workspace_id, name, &output),
135+
None => connections::types_list(&workspace_id, &output),
136+
}
134137
}
135-
}
136-
None => {
137-
let missing: Vec<&str> = [
138-
name.is_none().then_some("--name"),
139-
source_type.is_none().then_some("--type"),
140-
config.is_none().then_some("--config"),
141-
].into_iter().flatten().collect();
142-
if !missing.is_empty() {
143-
eprintln!("error: missing required arguments: {}", missing.join(", "));
144-
std::process::exit(1);
138+
None => {
139+
let missing: Vec<&str> = [
140+
name.is_none().then_some("--name"),
141+
source_type.is_none().then_some("--type"),
142+
config.is_none().then_some("--config"),
143+
].into_iter().flatten().collect();
144+
if !missing.is_empty() {
145+
eprintln!("error: missing required arguments: {}", missing.join(", "));
146+
std::process::exit(1);
147+
}
148+
connections::create(
149+
&workspace_id,
150+
&name.unwrap(),
151+
&source_type.unwrap(),
152+
&config.unwrap(),
153+
&output,
154+
)
145155
}
146-
connections::create(
147-
&workspace_id,
148-
&name.unwrap(),
149-
&source_type.unwrap(),
150-
&config.unwrap(),
151-
&output,
152-
)
153156
}
154157
}
158+
Some(ConnectionsCommands::Refresh { connection_id }) => {
159+
connections::refresh(&workspace_id, &connection_id)
160+
}
161+
None => {
162+
use clap::CommandFactory;
163+
let mut cmd = Cli::command();
164+
cmd.build();
165+
cmd.find_subcommand_mut("connections").unwrap().print_help().unwrap();
166+
}
155167
}
156-
ConnectionsCommands::Refresh { connection_id } => {
157-
connections::refresh(&workspace_id, &connection_id)
158-
}
159-
_ => eprintln!("not yet implemented"),
160168
}
161169
},
162170
Commands::Tables { command } => match command {

0 commit comments

Comments
 (0)