diff --git a/src/commands/indexes.rs b/src/commands/indexes.rs index 48e77ef..6bd2476 100644 --- a/src/commands/indexes.rs +++ b/src/commands/indexes.rs @@ -81,19 +81,29 @@ pub enum IndexesCommands { /// Delete an index from a table /// - /// Pass connection scope: --connection-id + --schema + --table. + /// Scope with `--catalog ` (the same flag as `indexes create`) or + /// `--connection-id `, plus `--table` (and `--schema`, default `public`). Delete { - /// Connection ID (use with --schema and --table) - #[arg(long, short = 'c', requires_all = ["schema", "table"])] + /// SQL catalog alias of the target database (e.g. `--catalog airbnb`) — + /// resolved to the backing connection, the same flag `indexes create` uses + #[arg( + long, + conflicts_with = "connection_id", + required_unless_present = "connection_id" + )] + catalog: Option, + + /// Connection ID (advanced; prefer --catalog) + #[arg(long, short = 'c', required_unless_present = "catalog")] connection_id: Option, - /// Schema name (requires --connection-id) - #[arg(long, requires = "connection_id")] - schema: Option, + /// Schema name (default: public) + #[arg(long, default_value = "public")] + schema: String, - /// Table name (requires --connection-id) - #[arg(long, requires = "connection_id")] - table: Option, + /// Table name + #[arg(long)] + table: String, /// Index name #[arg(long)] @@ -1325,4 +1335,96 @@ mod tests { assert!(result.is_err()); assert!(result.unwrap_err().contains("has no columns")); } + + mod delete_args { + use crate::commands::indexes::IndexesCommands; + use clap::Parser; + + #[derive(Parser)] + struct Wrapper { + #[command(subcommand)] + cmd: IndexesCommands, + } + + fn parse(args: &[&str]) -> Result { + Wrapper::try_parse_from(std::iter::once("t").chain(args.iter().copied())).map(|w| w.cmd) + } + + #[test] + fn delete_catalog_defaults_schema_to_public() { + let cmd = parse(&[ + "delete", + "--catalog", + "vtest", + "--table", + "hits", + "--name", + "idx", + ]) + .unwrap(); + match cmd { + IndexesCommands::Delete { + catalog, + connection_id, + schema, + table, + name, + } => { + assert_eq!(catalog.as_deref(), Some("vtest")); + assert_eq!(connection_id, None); + assert_eq!(schema, "public"); // defaulted, parity with `create` + assert_eq!(table, "hits"); + assert_eq!(name, "idx"); + } + _ => panic!("expected Delete"), + } + } + + #[test] + fn delete_accepts_raw_connection_id() { + let cmd = parse(&[ + "delete", + "--connection-id", + "conn_x", + "--table", + "hits", + "--name", + "idx", + ]) + .unwrap(); + assert!(matches!( + cmd, + IndexesCommands::Delete { connection_id, catalog: None, .. } if connection_id.as_deref() == Some("conn_x") + )); + } + + #[test] + fn delete_requires_a_scope_flag() { + // neither --catalog nor --connection-id + assert!(parse(&["delete", "--table", "hits", "--name", "idx"]).is_err()); + } + + #[test] + fn delete_rejects_catalog_and_connection_id_together() { + assert!( + parse(&[ + "delete", + "--catalog", + "x", + "--connection-id", + "c", + "--table", + "t", + "--name", + "n" + ]) + .is_err() + ); + } + + #[test] + fn delete_requires_table() { + assert!(parse(&["delete", "--catalog", "x", "--name", "idx"]).is_err()); + } + } } diff --git a/src/main.rs b/src/main.rs index 1e7b53e..2bc9260 100644 --- a/src/main.rs +++ b/src/main.rs @@ -651,29 +651,36 @@ fn main() { ) } IndexesCommands::Delete { + catalog, connection_id, schema, table, name, } => { - let scope = match ( - connection_id.as_deref(), - schema.as_deref(), - table.as_deref(), - ) { - (Some(cid), Some(sch), Some(tbl)) => indexes::IndexScope::Connection { - connection_id: cid, - schema: sch, - table: tbl, - }, - _ => { - eprintln!( - "error: provide all three of --connection-id, --schema, --table" - ); - std::process::exit(1); + // clap guarantees exactly one of --catalog / --connection-id + // plus --table and --name; --schema defaults to "public". + // A `--catalog` alias resolves to the backing connection + // (incl. a managed database's default connection), the same + // way `indexes create` does; `--connection-id` is used as-is. + let conn_id = match (catalog, connection_id) { + (Some(cat), _) => { + let api = sdk::Api::new(Some(&workspace_id)); + connections::resolve_connection_id(&api, &cat) + } + (None, Some(cid)) => cid, + (None, None) => { + unreachable!("clap requires --catalog or --connection-id") } }; - indexes::delete(&workspace_id, scope, &name); + indexes::delete( + &workspace_id, + indexes::IndexScope::Connection { + connection_id: &conn_id, + schema: &schema, + table: &table, + }, + &name, + ); } } }