@@ -664,9 +664,11 @@ fn main() {
664664 & output,
665665 ) ,
666666 IndexesCommands :: Create {
667- target,
667+ catalog,
668+ schema,
669+ table,
670+ column,
668671 dataset_id,
669- columns,
670672 name,
671673 r#type,
672674 metric,
@@ -678,46 +680,42 @@ fn main() {
678680 } => {
679681 let api = api:: ApiClient :: new ( Some ( & workspace_id) ) ;
680682 let ( scope, resolved_columns, auto_name) =
681- match ( target. as_deref ( ) , dataset_id. as_deref ( ) ) {
682- ( Some ( tgt) , None ) => {
683- let ( conn_name, schema, table, cols) =
684- parse_index_target ( tgt) ;
685- let conn_id =
686- connections:: resolve_connection_id ( & api, & conn_name) ;
683+ match ( catalog. as_deref ( ) . or ( table. as_deref ( ) ) , dataset_id. as_deref ( ) ) {
684+ ( Some ( _) , None ) => {
685+ let catalog_or_conn = catalog. as_deref ( ) . unwrap_or_else ( || {
686+ eprintln ! ( "error: --catalog is required" ) ;
687+ std:: process:: exit ( 1 ) ;
688+ } ) ;
689+ let tbl = table. as_deref ( ) . unwrap_or_else ( || {
690+ eprintln ! ( "error: --table is required" ) ;
691+ std:: process:: exit ( 1 ) ;
692+ } ) ;
693+ let cols = column. as_deref ( ) . unwrap_or_else ( || {
694+ eprintln ! ( "error: --column is required" ) ;
695+ std:: process:: exit ( 1 ) ;
696+ } ) ;
697+ let conn_id = connections:: resolve_connection_id ( & api, catalog_or_conn) ;
687698 let auto = format ! (
688- "{table }_{cols}_{type}" ,
689- cols = cols. join ( "_" ) ,
699+ "{tbl }_{cols}_{type}" ,
700+ cols = cols. replace ( ',' , "_" ) ,
690701 type = r#type
691702 ) ;
692- (
693- ( conn_id, schema, table) ,
694- cols. join ( "," ) ,
695- auto,
696- )
703+ ( ( conn_id, schema, tbl. to_string ( ) ) , cols. to_string ( ) , auto)
697704 }
698705 ( None , Some ( did) ) => {
699- let cols =
700- columns. as_deref ( ) . unwrap_or_else ( || {
701- eprintln ! (
702- "error: --columns is required with --dataset-id"
703- ) ;
704- std:: process:: exit ( 1 ) ;
705- } ) ;
706+ let cols = column. as_deref ( ) . unwrap_or_else ( || {
707+ eprintln ! ( "error: --column is required with --dataset-id" ) ;
708+ std:: process:: exit ( 1 ) ;
709+ } ) ;
706710 let auto = format ! (
707711 "dataset_{cols}_{type}" ,
708712 cols = cols. replace( ',' , "_" ) ,
709713 type = r#type
710714 ) ;
711- (
712- ( did. to_string ( ) , String :: new ( ) , String :: new ( ) ) ,
713- cols. to_string ( ) ,
714- auto,
715- )
715+ ( ( did. to_string ( ) , String :: new ( ) , String :: new ( ) ) , cols. to_string ( ) , auto)
716716 }
717717 _ => {
718- eprintln ! (
719- "error: provide either <target> (e.g. airbnb.listings[col1,col2]) or --dataset-id with --columns"
720- ) ;
718+ eprintln ! ( "error: provide --catalog and --table, or --dataset-id with --column" ) ;
721719 std:: process:: exit ( 1 ) ;
722720 }
723721 } ;
@@ -1065,87 +1063,9 @@ fn main() {
10651063}
10661064
10671065
1068- /// Parse an index target like `airbnb.listings[col1,col2]` or
1069- /// `airbnb.public.listings[col1,col2]` into `(conn_name, schema, table, columns)`.
1070- /// Schema defaults to `public` when only two dot-parts are given.
1071- fn parse_index_target ( target : & str ) -> ( String , String , String , Vec < String > ) {
1072- let Some ( bracket_pos) = target. find ( '[' ) else {
1073- eprintln ! (
1074- "error: target must include columns in brackets, e.g. airbnb.listings[col1,col2]"
1075- ) ;
1076- std:: process:: exit ( 1 ) ;
1077- } ;
1078- if !target. ends_with ( ']' ) {
1079- eprintln ! (
1080- "error: target bracket is not closed — use e.g. 'airbnb.listings[col1,col2]'"
1081- ) ;
1082- std:: process:: exit ( 1 ) ;
1083- }
1084- let table_part = & target[ ..bracket_pos] ;
1085- let cols_raw = & target[ bracket_pos + 1 ..target. len ( ) - 1 ] ;
1086-
1087- let parts: Vec < & str > = table_part. splitn ( 4 , '.' ) . collect ( ) ;
1088- let ( conn, schema, table) = match parts. as_slice ( ) {
1089- [ c, t] => ( c. to_string ( ) , "public" . to_string ( ) , t. to_string ( ) ) ,
1090- [ c, s, t] => ( c. to_string ( ) , s. to_string ( ) , t. to_string ( ) ) ,
1091- _ => {
1092- eprintln ! (
1093- "error: target must be 'connection.table[cols]' or 'connection.schema.table[cols]'"
1094- ) ;
1095- std:: process:: exit ( 1 ) ;
1096- }
1097- } ;
1098-
1099- let columns: Vec < String > = cols_raw
1100- . split ( ',' )
1101- . map ( |s| s. trim ( ) . to_string ( ) )
1102- . filter ( |s| !s. is_empty ( ) )
1103- . collect ( ) ;
1104-
1105- if columns. is_empty ( ) {
1106- eprintln ! ( "error: no columns specified in brackets" ) ;
1107- std:: process:: exit ( 1 ) ;
1108- }
1109-
1110- ( conn, schema, table, columns)
1111- }
1112-
11131066#[ cfg( test) ]
11141067mod tests {
11151068 use super :: * ;
1116-
1117- // --- parse_index_target ---
1118-
1119- #[ test]
1120- fn index_target_two_parts_defaults_schema_to_public ( ) {
1121- let ( conn, schema, table, cols) = parse_index_target ( "airbnb.listings[description]" ) ;
1122- assert_eq ! ( conn, "airbnb" ) ;
1123- assert_eq ! ( schema, "public" ) ;
1124- assert_eq ! ( table, "listings" ) ;
1125- assert_eq ! ( cols, vec![ "description" ] ) ;
1126- }
1127-
1128- #[ test]
1129- fn index_target_three_parts_uses_explicit_schema ( ) {
1130- let ( conn, schema, table, cols) =
1131- parse_index_target ( "airbnb.public.listings[name,description]" ) ;
1132- assert_eq ! ( conn, "airbnb" ) ;
1133- assert_eq ! ( schema, "public" ) ;
1134- assert_eq ! ( table, "listings" ) ;
1135- assert_eq ! ( cols, vec![ "name" , "description" ] ) ;
1136- }
1137-
1138- #[ test]
1139- fn index_target_multiple_columns ( ) {
1140- let ( _, _, _, cols) = parse_index_target ( "db.tbl[a,b,c]" ) ;
1141- assert_eq ! ( cols, vec![ "a" , "b" , "c" ] ) ;
1142- }
1143-
1144- #[ test]
1145- fn index_target_trims_column_whitespace ( ) {
1146- let ( _, _, _, cols) = parse_index_target ( "db.tbl[a, b]" ) ;
1147- assert_eq ! ( cols, vec![ "a" , "b" ] ) ;
1148- }
11491069}
11501070
11511071pub fn get_styles ( ) -> clap:: builder:: Styles {
0 commit comments