use anyhow::Result;
use clap::Parser;
use clap_complete::engine::{ArgValueCandidates, CompletionCandidate};
use crate::output::OutputFormat;
fn complete_query_names() -> Vec<CompletionCandidate> {
cosq_core::stored_query::list_query_names()
.into_iter()
.map(|(name, desc)| {
let mut candidate = CompletionCandidate::new(name);
if let Some(d) = desc {
candidate = candidate.help(Some(d.into()));
}
candidate
})
.collect()
}
#[derive(Parser)]
#[command(name = "cosq")]
#[command(author, version, about)]
#[command(long_about = "A CLI to query your Azure Cosmos DB instances.\n\n\
Connect to your Cosmos DB accounts and run queries directly from the command line.")]
#[command(propagate_version = true)]
pub struct Cli {
#[arg(short, long, action = clap::ArgAction::Count, global = true)]
pub verbose: u8,
#[arg(short, long, global = true)]
pub quiet: bool,
#[arg(long, global = true)]
pub no_color: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(clap::Subcommand)]
pub enum Commands {
Query {
sql: String,
#[arg(long)]
db: Option<String>,
#[arg(long)]
container: Option<String>,
#[arg(long, short, value_enum)]
output: Option<OutputFormat>,
#[arg(long)]
template: Option<String>,
},
Run {
#[arg(add = ArgValueCandidates::new(complete_query_names))]
name: Option<String>,
#[arg(long)]
db: Option<String>,
#[arg(long)]
container: Option<String>,
#[arg(long, short, value_enum)]
output: Option<OutputFormat>,
#[arg(long)]
template: Option<String>,
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
params: Vec<String>,
},
Queries {
#[command(subcommand)]
command: QueriesCommands,
},
Init {
#[arg(long)]
account: Option<String>,
#[arg(long)]
subscription: Option<String>,
#[arg(long, short)]
yes: bool,
},
Auth {
#[command(subcommand)]
command: AuthCommands,
},
Completion {
#[arg(value_enum)]
shell: Shell,
},
Ai {
#[command(subcommand)]
command: AiCommands,
},
Version,
}
#[derive(clap::Subcommand)]
pub enum QueriesCommands {
List,
Create {
name: String,
#[arg(long)]
project: bool,
},
Edit {
#[arg(add = ArgValueCandidates::new(complete_query_names))]
name: String,
},
Delete {
#[arg(add = ArgValueCandidates::new(complete_query_names))]
name: String,
#[arg(long, short)]
yes: bool,
},
Show {
#[arg(add = ArgValueCandidates::new(complete_query_names))]
name: String,
},
Generate {
description: Option<String>,
#[arg(long)]
db: Option<String>,
#[arg(long)]
container: Option<String>,
#[arg(long)]
project: bool,
},
}
#[derive(clap::Subcommand)]
pub enum AiCommands {
Init,
}
#[derive(clap::Subcommand)]
pub enum AuthCommands {
Status,
Login,
Logout,
}
#[derive(Clone, clap::ValueEnum)]
pub enum Shell {
Bash,
Zsh,
Fish,
Powershell,
}
impl Cli {
pub async fn run(self) -> Result<()> {
match self.command {
Some(Commands::Query {
sql,
db,
container,
output,
template,
}) => {
crate::commands::query::run(crate::commands::query::QueryArgs {
sql,
db,
container,
output,
template,
quiet: self.quiet,
})
.await
}
Some(Commands::Run {
name,
db,
container,
output,
template,
params,
}) => {
crate::commands::run::run(crate::commands::run::RunArgs {
name,
params,
output,
db,
container,
template,
quiet: self.quiet,
})
.await
}
Some(Commands::Queries { command }) => {
crate::commands::queries::run(command, self.quiet).await
}
Some(Commands::Init {
account,
subscription,
yes,
}) => {
crate::commands::init::run(crate::commands::init::InitArgs {
account,
subscription,
yes,
})
.await
}
Some(Commands::Auth { command }) => crate::commands::auth::run(command).await,
Some(Commands::Ai { command }) => crate::commands::ai::run(command).await,
Some(Commands::Completion { shell }) => {
crate::commands::completion::generate_completions(shell);
Ok(())
}
Some(Commands::Version) => {
crate::banner::print_banner_with_version();
Ok(())
}
None => {
use clap::CommandFactory;
let mut cmd = Self::command();
cmd.print_help()?;
println!();
Ok(())
}
}
}
}