tern_cli/
cli.rs

1use clap::{Args, Parser, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Debug, Parser)]
5pub struct Tern {
6    #[clap(subcommand)]
7    pub commands: TernCommands,
8}
9
10#[derive(Debug, Parser)]
11pub enum TernCommands {
12    Migrate(Migrate),
13    History(History),
14}
15
16/// Operations on the set of migration files.
17#[derive(Debug, Parser)]
18pub struct Migrate {
19    #[clap(subcommand)]
20    pub commands: MigrateCommands,
21}
22
23/// Operations on the table storing the history of these migrations.
24#[derive(Debug, Parser)]
25pub struct History {
26    #[clap(subcommand)]
27    pub commands: HistoryCommands,
28}
29
30#[derive(Debug, Parser)]
31pub enum MigrateCommands {
32    /// Run the apply operation for a specific range of unapplied migrations
33    Apply {
34        /// Render the migration report without applying any migrations
35        #[arg(short, long)]
36        dryrun: bool,
37        /// Apply unapplied migrations up through this version
38        #[arg(long)]
39        target_version: Option<i64>,
40        #[clap(flatten)]
41        connect_opts: ConnectOpts,
42    },
43    /// Run any available unapplied migrations
44    ApplyAll {
45        /// Render the migration report without applying any migrations
46        #[arg(short, long)]
47        dryrun: bool,
48        #[clap(flatten)]
49        connect_opts: ConnectOpts,
50    },
51    /// Insert migrations into the history table without applying them
52    SoftApply {
53        /// Render the migration report without soft applying any migrations
54        #[arg(short, long)]
55        dryrun: bool,
56        /// Soft apply unapplied migrations up through this version
57        #[arg(long)]
58        target_version: Option<i64>,
59        #[clap(flatten)]
60        connect_opts: ConnectOpts,
61    },
62    /// List previously applied migrations
63    ListApplied {
64        #[clap(flatten)]
65        connect_opts: ConnectOpts,
66    },
67    /// Create a migration with the description and an auto-selected version
68    New {
69        /// Name of the migration
70        description: String,
71        /// If `true`, annotate the migration to not run in a transaction
72        no_tx: bool,
73        /// Whether to create a SQL or Rust migration
74        #[arg(long = "type", value_enum)]
75        migration_type: MigrationType,
76        #[clap(flatten)]
77        source: Source,
78    },
79}
80
81#[derive(Debug, Parser)]
82pub enum HistoryCommands {
83    /// Create the schema history table
84    Init {
85        #[clap(flatten)]
86        connect_opts: ConnectOpts,
87    },
88    /// Drop the schema history table
89    Drop {
90        #[clap(flatten)]
91        connect_opts: ConnectOpts,
92    },
93    /// Deprecated: use `migrate soft-apply` instead
94    SoftApply {
95        /// `--from-version` is not a valid option
96        #[arg(long)]
97        from_version: Option<i64>,
98        /// The version to end the soft apply with (defaults to the last)
99        #[arg(long)]
100        to_version: Option<i64>,
101        #[clap(flatten)]
102        connect_opts: ConnectOpts,
103    },
104}
105
106#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
107pub enum MigrationType {
108    Sql,
109    Rust,
110}
111
112#[derive(Debug, Args)]
113pub struct Source {
114    /// Path to the folder containing migrations.
115    #[clap(long)]
116    pub path: PathBuf,
117}
118
119#[derive(Debug, Args)]
120pub struct ConnectOpts {
121    /// Connection string for the database either from the command line or from
122    /// the environment variable `DATABASE_URL`.
123    #[clap(long, short = 'D', env)]
124    pub database_url: Option<String>,
125}
126
127impl ConnectOpts {
128    pub fn required_db_url(&self) -> anyhow::Result<&str> {
129        self.database_url.as_deref().ok_or_else(
130            || anyhow::anyhow!(
131                "the `--database-url/-D` option or the `DATABASE_URL` environment variable must be provided"
132            )
133        )
134    }
135}