Skip to content

Commit 04f1c70

Browse files
committed
feat(databases): explicit flags for load, unset command, and star in list
- Replace dot-notation positional <TARGET> on `databases load` with explicit --catalog, --schema, --table flags - Add `databases unset` to clear the active database from config - Show * marker on the active database in `databases list` - Remove parse_db_target and its tests (no longer needed)
1 parent 4a253d8 commit 04f1c70

3 files changed

Lines changed: 43 additions & 51 deletions

File tree

src/command.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -600,17 +600,28 @@ pub enum DatabasesCommands {
600600
id: String,
601601
},
602602

603+
/// Clear the current database
604+
Unset,
605+
603606
/// Delete a managed database and its tables
604607
Delete {
605608
/// Database name or connection ID
606609
name_or_id: String,
607610
},
608611

609-
/// Load a parquet file into a table using dot notation: `database.table` or `database.schema.table`
612+
/// Load a parquet file into a managed database table
610613
Load {
611-
/// Table to load into: `database.table` or `database.schema.table`.
612-
/// Schema defaults to `public` when omitted.
613-
target: String,
614+
/// SQL catalog alias of the target database (e.g. `--catalog airbnb`)
615+
#[arg(long)]
616+
catalog: String,
617+
618+
/// Schema to load into (default: public)
619+
#[arg(long, default_value = "public")]
620+
schema: String,
621+
622+
/// Table name to load into
623+
#[arg(long)]
624+
table: String,
614625

615626
/// Path to a local parquet file to upload and load
616627
#[arg(long, conflicts_with_all = ["upload_id", "url"])]

src/databases.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,17 +398,20 @@ pub fn list(workspace_id: &str, format: &str) {
398398
"Create one with: hotdata databases create --catalog <alias>".dark_grey()
399399
);
400400
} else {
401+
let current = crate::config::load_current_database("default", workspace_id);
401402
let rows: Vec<Vec<String>> = body
402403
.databases
403404
.iter()
404405
.map(|d| {
406+
let marker = if current.as_deref() == Some(d.id.as_str()) { "*" } else { "" };
405407
vec![
408+
marker.to_string(),
406409
d.id.clone(),
407410
d.name.as_deref().unwrap_or("-").to_string(),
408411
]
409412
})
410413
.collect();
411-
crate::table::print(&["ID", "NAME"], &rows);
414+
crate::table::print(&["", "ID", "NAME"], &rows);
412415
}
413416
}
414417
_ => unreachable!(),
@@ -644,6 +647,15 @@ pub fn create(
644647
}
645648
}
646649

650+
pub fn unset(workspace_id: &str) {
651+
use crossterm::style::Stylize;
652+
if let Err(e) = crate::config::clear_current_database("default", workspace_id) {
653+
eprintln!("{}", format!("error clearing current database: {e}").red());
654+
std::process::exit(1);
655+
}
656+
println!("{}", "Current database cleared.".green());
657+
}
658+
647659
pub fn set(workspace_id: &str, id: &str) {
648660
use crossterm::style::Stylize;
649661
let api = ApiClient::new(Some(workspace_id));

src/main.rs

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -449,26 +449,28 @@ fn main() {
449449
Some(DatabasesCommands::Set { id }) => {
450450
databases::set(&workspace_id, &id)
451451
}
452+
Some(DatabasesCommands::Unset) => {
453+
databases::unset(&workspace_id)
454+
}
452455
Some(DatabasesCommands::Delete { name_or_id }) => {
453456
databases::delete(&workspace_id, &name_or_id)
454457
}
455458
Some(DatabasesCommands::Load {
456-
target,
459+
catalog,
460+
schema,
461+
table,
457462
file,
458463
url,
459464
upload_id,
460-
}) => {
461-
let (database, schema, table) = parse_db_target(&target);
462-
databases::tables_load(
463-
&workspace_id,
464-
Some(database.as_str()),
465-
&table,
466-
Some(schema.as_str()),
467-
file.as_deref(),
468-
url.as_deref(),
469-
upload_id.as_deref(),
470-
)
471-
}
465+
}) => databases::tables_load(
466+
&workspace_id,
467+
Some(catalog.as_str()),
468+
&table,
469+
Some(schema.as_str()),
470+
file.as_deref(),
471+
url.as_deref(),
472+
upload_id.as_deref(),
473+
),
472474
Some(DatabasesCommands::Tables { database, command }) => match command {
473475
Some(DatabaseTablesCommands::List {
474476
database: db_flag,
@@ -1059,21 +1061,6 @@ fn main() {
10591061
update::maybe_print_update_notice(update_handle);
10601062
}
10611063

1062-
/// Parse a database target like `airbnb.listings` or `airbnb.public.listings`
1063-
/// into `(database, schema, table)`. Schema defaults to `public`.
1064-
fn parse_db_target(target: &str) -> (String, String, String) {
1065-
let parts: Vec<&str> = target.splitn(4, '.').collect();
1066-
match parts.as_slice() {
1067-
[db, tbl] => (db.to_string(), "public".to_string(), tbl.to_string()),
1068-
[db, schema, tbl] => (db.to_string(), schema.to_string(), tbl.to_string()),
1069-
_ => {
1070-
eprintln!(
1071-
"error: target must be 'database.table' or 'database.schema.table'"
1072-
);
1073-
std::process::exit(1);
1074-
}
1075-
}
1076-
}
10771064

10781065
/// Parse an index target like `airbnb.listings[col1,col2]` or
10791066
/// `airbnb.public.listings[col1,col2]` into `(conn_name, schema, table, columns)`.
@@ -1124,24 +1111,6 @@ fn parse_index_target(target: &str) -> (String, String, String, Vec<String>) {
11241111
mod tests {
11251112
use super::*;
11261113

1127-
// --- parse_db_target ---
1128-
1129-
#[test]
1130-
fn db_target_two_parts_defaults_schema_to_public() {
1131-
let (db, schema, table) = parse_db_target("airbnb.listings");
1132-
assert_eq!(db, "airbnb");
1133-
assert_eq!(schema, "public");
1134-
assert_eq!(table, "listings");
1135-
}
1136-
1137-
#[test]
1138-
fn db_target_three_parts_uses_explicit_schema() {
1139-
let (db, schema, table) = parse_db_target("airbnb.staging.listings");
1140-
assert_eq!(db, "airbnb");
1141-
assert_eq!(schema, "staging");
1142-
assert_eq!(table, "listings");
1143-
}
1144-
11451114
// --- parse_index_target ---
11461115

11471116
#[test]

0 commit comments

Comments
 (0)