use std::ops::{Deref, Not};
use clap::{
builder::{styling::AnsiColor, Styles},
Args, Parser,
};
#[cfg(feature = "completions")]
use clap_complete::Shell;
const HELP_STYLES: Styles = Styles::styled()
.header(AnsiColor::Blue.on_default().bold())
.usage(AnsiColor::Blue.on_default().bold())
.literal(AnsiColor::White.on_default())
.placeholder(AnsiColor::Green.on_default());
#[derive(Parser, Debug)]
#[clap(version, about, author, styles = HELP_STYLES)]
pub struct Opt {
#[clap(flatten)]
pub no_dotenv: NoDotenvOpt,
#[clap(subcommand)]
pub command: Command,
}
#[derive(Parser, Debug)]
pub enum Command {
#[clap(alias = "db")]
Database(DatabaseOpt),
#[clap(alias = "prep")]
Prepare {
#[clap(long)]
check: bool,
#[clap(long)]
all: bool,
#[clap(long)]
workspace: bool,
#[clap(last = true)]
args: Vec<String>,
#[clap(flatten)]
connect_opts: ConnectOpts,
},
#[clap(alias = "mig")]
Migrate(MigrateOpt),
#[cfg(feature = "completions")]
Completions { shell: Shell },
}
#[derive(Parser, Debug)]
pub struct DatabaseOpt {
#[clap(subcommand)]
pub command: DatabaseCommand,
}
#[derive(Parser, Debug)]
pub enum DatabaseCommand {
Create {
#[clap(flatten)]
connect_opts: ConnectOpts,
},
Drop {
#[clap(flatten)]
confirmation: Confirmation,
#[clap(flatten)]
connect_opts: ConnectOpts,
#[clap(long, short, default_value = "false")]
force: bool,
},
Reset {
#[clap(flatten)]
confirmation: Confirmation,
#[clap(flatten)]
source: Source,
#[clap(flatten)]
connect_opts: ConnectOpts,
#[clap(long, short, default_value = "false")]
force: bool,
},
Setup {
#[clap(flatten)]
source: Source,
#[clap(flatten)]
connect_opts: ConnectOpts,
},
}
#[derive(Parser, Debug)]
pub struct MigrateOpt {
#[clap(subcommand)]
pub command: MigrateCommand,
}
#[derive(Parser, Debug)]
pub enum MigrateCommand {
Add {
description: String,
#[clap(flatten)]
source: Source,
#[clap(short)]
reversible: bool,
#[clap(short, long)]
timestamp: bool,
#[clap(short, long, conflicts_with = "timestamp")]
sequential: bool,
},
Run {
#[clap(flatten)]
source: Source,
#[clap(long)]
dry_run: bool,
#[clap(flatten)]
ignore_missing: IgnoreMissing,
#[clap(flatten)]
connect_opts: ConnectOpts,
#[clap(long)]
target_version: Option<i64>,
},
Revert {
#[clap(flatten)]
source: Source,
#[clap(long)]
dry_run: bool,
#[clap(flatten)]
ignore_missing: IgnoreMissing,
#[clap(flatten)]
connect_opts: ConnectOpts,
#[clap(long)]
target_version: Option<i64>,
},
Info {
#[clap(flatten)]
source: Source,
#[clap(flatten)]
connect_opts: ConnectOpts,
},
BuildScript {
#[clap(flatten)]
source: Source,
#[clap(long)]
force: bool,
},
}
#[derive(Args, Debug)]
pub struct Source {
#[clap(long, default_value = "migrations")]
source: String,
}
impl Deref for Source {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.source
}
}
#[derive(Args, Debug)]
pub struct ConnectOpts {
#[clap(flatten)]
pub no_dotenv: NoDotenvOpt,
#[clap(long, short = 'D', env)]
pub database_url: Option<String>,
#[clap(long, default_value = "10")]
pub connect_timeout: u64,
#[cfg(feature = "_sqlite")]
#[clap(long, action = clap::ArgAction::Set, default_value = "true")]
pub sqlite_create_db_wal: bool,
}
#[derive(Args, Debug)]
pub struct NoDotenvOpt {
#[clap(long)]
#[allow(unused)] pub no_dotenv: bool,
}
impl ConnectOpts {
pub fn required_db_url(&self) -> anyhow::Result<&str> {
self.database_url.as_deref().ok_or_else(
|| anyhow::anyhow!(
"the `--database-url` option or the `DATABASE_URL` environment variable must be provided"
)
)
}
}
#[derive(Args, Copy, Clone, Debug)]
pub struct Confirmation {
#[clap(short)]
pub yes: bool,
}
#[derive(Args, Copy, Clone, Debug)]
pub struct IgnoreMissing {
#[clap(long)]
ignore_missing: bool,
}
impl Deref for IgnoreMissing {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.ignore_missing
}
}
impl Not for IgnoreMissing {
type Output = bool;
fn not(self) -> Self::Output {
!self.ignore_missing
}
}