tern_cli/cli.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
use clap::{Args, Parser, ValueEnum};
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Tern {
#[clap(subcommand)]
pub commands: TernCommands,
}
#[derive(Debug, Parser)]
pub enum TernCommands {
Migrate(Migrate),
History(History),
}
/// Operations on the set of migration files.
#[derive(Debug, Parser)]
pub struct Migrate {
#[clap(subcommand)]
pub commands: MigrateCommands,
}
/// Operations on the table storing the history of these migrations.
#[derive(Debug, Parser)]
pub struct History {
#[clap(subcommand)]
pub commands: HistoryCommands,
}
#[derive(Debug, Parser)]
pub enum MigrateCommands {
/// Run any available unapplied migrations.
ApplyAll {
/// List the migrations to be applied without applying them.
#[arg(short, long)]
dryrun: bool,
#[clap(flatten)]
connect_opts: ConnectOpts,
},
/// List previously applied migrations.
ListApplied {
#[clap(flatten)]
connect_opts: ConnectOpts,
},
/// Create a new migration with an auto-selected version and the given
/// description.
New {
description: String,
/// If `true`, the annotation for not running the migration in a
/// transaction will be added to the generated file.
no_tx: bool,
/// Whether to create a SQL or Rust migration.
#[arg(long = "type", value_enum)]
migration_type: MigrationType,
#[clap(flatten)]
source: Source,
},
}
#[derive(Debug, Parser)]
pub enum HistoryCommands {
/// Create the schema history table.
Init {
#[clap(flatten)]
connect_opts: ConnectOpts,
},
/// Drop the schema history table.
Drop {
#[clap(flatten)]
connect_opts: ConnectOpts,
},
/// Do a "soft" apply of all migrations in the specified range.
/// A soft apply will add the migration to the schema history table but
/// without running the query for the migration.
SoftApply {
/// The version to start the soft apply with.
/// If not provided, the first migration is where the soft apply starts.
#[arg(long)]
from_version: Option<i64>,
/// The version to end the soft apply with.
/// If not provided, the last migration is where the soft apply ends.
#[arg(long)]
to_version: Option<i64>,
#[clap(flatten)]
connect_opts: ConnectOpts,
},
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum MigrationType {
Sql,
Rust,
}
#[derive(Debug, Args)]
pub struct Source {
/// Path to the folder containing migrations.
#[clap(long)]
pub path: PathBuf,
}
#[derive(Debug, Args)]
pub struct ConnectOpts {
/// Connection string for the database either from the command line or from
/// the environment variable `DATABASE_URL`.
#[clap(long, short = 'D', env)]
pub database_url: Option<String>,
}
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"
)
)
}
}