sqlx_cli/
opt.rs

1use std::ops::{Deref, Not};
2
3use clap::{Args, Parser};
4#[cfg(feature = "completions")]
5use clap_complete::Shell;
6
7#[derive(Parser, Debug)]
8#[clap(version, about, author)]
9pub struct Opt {
10    #[clap(subcommand)]
11    pub command: Command,
12}
13
14#[derive(Parser, Debug)]
15pub enum Command {
16    #[clap(alias = "db")]
17    Database(DatabaseOpt),
18
19    /// Generate query metadata to support offline compile-time verification.
20    ///
21    /// Saves metadata for all invocations of `query!` and related macros to a `.sqlx` directory
22    /// in the current directory (or workspace root with `--workspace`), overwriting if needed.
23    ///
24    /// During project compilation, the absence of the `DATABASE_URL` environment variable or
25    /// the presence of `SQLX_OFFLINE` (with a value of `true` or `1`) will constrain the
26    /// compile-time verification to only read from the cached query metadata.
27    #[clap(alias = "prep")]
28    Prepare {
29        /// Run in 'check' mode. Exits with 0 if the query metadata is up-to-date. Exits with
30        /// 1 if the query metadata needs updating.
31        #[clap(long)]
32        check: bool,
33
34        /// Prepare query macros in dependencies that exist outside the current crate or workspace.
35        #[clap(long)]
36        all: bool,
37
38        /// Generate a single workspace-level `.sqlx` folder.
39        ///
40        /// This option is intended for workspaces where multiple crates use SQLx. If there is only
41        /// one, it is better to run `cargo sqlx prepare` without this option inside that crate.
42        #[clap(long)]
43        workspace: bool,
44
45        /// Arguments to be passed to `cargo rustc ...`.
46        #[clap(last = true)]
47        args: Vec<String>,
48
49        #[clap(flatten)]
50        connect_opts: ConnectOpts,
51    },
52
53    #[clap(alias = "mig")]
54    Migrate(MigrateOpt),
55
56    #[cfg(feature = "completions")]
57    /// Generate shell completions for the specified shell
58    Completions { shell: Shell },
59}
60
61/// Group of commands for creating and dropping your database.
62#[derive(Parser, Debug)]
63pub struct DatabaseOpt {
64    #[clap(subcommand)]
65    pub command: DatabaseCommand,
66}
67
68#[derive(Parser, Debug)]
69pub enum DatabaseCommand {
70    /// Creates the database specified in your DATABASE_URL.
71    Create {
72        #[clap(flatten)]
73        connect_opts: ConnectOpts,
74    },
75
76    /// Drops the database specified in your DATABASE_URL.
77    Drop {
78        #[clap(flatten)]
79        confirmation: Confirmation,
80
81        #[clap(flatten)]
82        connect_opts: ConnectOpts,
83
84        /// PostgreSQL only: force drops the database.
85        #[clap(long, short, default_value = "false")]
86        force: bool,
87    },
88
89    /// Drops the database specified in your DATABASE_URL, re-creates it, and runs any pending migrations.
90    Reset {
91        #[clap(flatten)]
92        confirmation: Confirmation,
93
94        #[clap(flatten)]
95        source: Source,
96
97        #[clap(flatten)]
98        connect_opts: ConnectOpts,
99
100        /// PostgreSQL only: force drops the database.
101        #[clap(long, short, default_value = "false")]
102        force: bool,
103    },
104
105    /// Creates the database specified in your DATABASE_URL and runs any pending migrations.
106    Setup {
107        #[clap(flatten)]
108        source: Source,
109
110        #[clap(flatten)]
111        connect_opts: ConnectOpts,
112    },
113}
114
115/// Group of commands for creating and running migrations.
116#[derive(Parser, Debug)]
117pub struct MigrateOpt {
118    #[clap(subcommand)]
119    pub command: MigrateCommand,
120}
121
122#[derive(Parser, Debug)]
123pub enum MigrateCommand {
124    /// Create a new migration with the given description.
125    ///
126    /// A version number will be automatically assigned to the migration.
127    ///
128    /// For convenience, this command will attempt to detect if sequential versioning is in use,
129    /// and if so, continue the sequence.
130    ///
131    /// Sequential versioning is inferred if:
132    ///
133    /// * The version numbers of the last two migrations differ by exactly 1, or:
134    ///
135    /// * only one migration exists and its version number is either 0 or 1.
136    ///
137    /// Otherwise timestamp versioning is assumed.
138    ///
139    /// This behavior can overridden by `--sequential` or `--timestamp`, respectively.
140    Add {
141        description: String,
142
143        #[clap(flatten)]
144        source: Source,
145
146        /// If true, creates a pair of up and down migration files with same version
147        /// else creates a single sql file
148        #[clap(short)]
149        reversible: bool,
150
151        /// If set, use timestamp versioning for the new migration. Conflicts with `--sequential`.
152        #[clap(short, long)]
153        timestamp: bool,
154
155        /// If set, use sequential versioning for the new migration. Conflicts with `--timestamp`.
156        #[clap(short, long, conflicts_with = "timestamp")]
157        sequential: bool,
158    },
159
160    /// Run all pending migrations.
161    Run {
162        #[clap(flatten)]
163        source: Source,
164
165        /// List all the migrations to be run without applying
166        #[clap(long)]
167        dry_run: bool,
168
169        #[clap(flatten)]
170        ignore_missing: IgnoreMissing,
171
172        #[clap(flatten)]
173        connect_opts: ConnectOpts,
174
175        /// Apply migrations up to the specified version. If unspecified, apply all
176        /// pending migrations. If already at the target version, then no-op.
177        #[clap(long)]
178        target_version: Option<i64>,
179    },
180
181    /// Revert the latest migration with a down file.
182    Revert {
183        #[clap(flatten)]
184        source: Source,
185
186        /// List the migration to be reverted without applying
187        #[clap(long)]
188        dry_run: bool,
189
190        #[clap(flatten)]
191        ignore_missing: IgnoreMissing,
192
193        #[clap(flatten)]
194        connect_opts: ConnectOpts,
195
196        /// Revert migrations down to the specified version. If unspecified, revert
197        /// only the last migration. Set to 0 to revert all migrations. If already
198        /// at the target version, then no-op.
199        #[clap(long)]
200        target_version: Option<i64>,
201    },
202
203    /// List all available migrations.
204    Info {
205        #[clap(flatten)]
206        source: Source,
207
208        #[clap(flatten)]
209        connect_opts: ConnectOpts,
210    },
211
212    /// Generate a `build.rs` to trigger recompilation when a new migration is added.
213    ///
214    /// Must be run in a Cargo project root.
215    BuildScript {
216        #[clap(flatten)]
217        source: Source,
218
219        /// Overwrite the build script if it already exists.
220        #[clap(long)]
221        force: bool,
222    },
223}
224
225/// Argument for the migration scripts source.
226#[derive(Args, Debug)]
227pub struct Source {
228    /// Path to folder containing migrations.
229    #[clap(long, default_value = "migrations")]
230    source: String,
231}
232
233impl Deref for Source {
234    type Target = String;
235
236    fn deref(&self) -> &Self::Target {
237        &self.source
238    }
239}
240
241/// Argument for the database URL.
242#[derive(Args, Debug)]
243pub struct ConnectOpts {
244    /// Location of the DB, by default will be read from the DATABASE_URL env var or `.env` files.
245    #[clap(long, short = 'D', env)]
246    pub database_url: Option<String>,
247
248    /// The maximum time, in seconds, to try connecting to the database server before
249    /// returning an error.
250    #[clap(long, default_value = "10")]
251    pub connect_timeout: u64,
252
253    /// Set whether or not to create SQLite databases in Write-Ahead Log (WAL) mode:
254    /// https://www.sqlite.org/wal.html
255    ///
256    /// WAL mode is enabled by default for SQLite databases created by `sqlx-cli`.
257    ///
258    /// However, if your application sets a `journal_mode` on `SqliteConnectOptions` to something
259    /// other than `Wal`, then it will have to take the database file out of WAL mode on connecting,
260    /// which requires an exclusive lock and may return a `database is locked` (`SQLITE_BUSY`) error.
261    #[cfg(feature = "_sqlite")]
262    #[clap(long, action = clap::ArgAction::Set, default_value = "true")]
263    pub sqlite_create_db_wal: bool,
264}
265
266impl ConnectOpts {
267    /// Require a database URL to be provided, otherwise
268    /// return an error.
269    pub fn required_db_url(&self) -> anyhow::Result<&str> {
270        self.database_url.as_deref().ok_or_else(
271            || anyhow::anyhow!(
272                "the `--database-url` option or the `DATABASE_URL` environment variable must be provided"
273            )
274        )
275    }
276}
277
278/// Argument for automatic confirmation.
279#[derive(Args, Copy, Clone, Debug)]
280pub struct Confirmation {
281    /// Automatic confirmation. Without this option, you will be prompted before dropping
282    /// your database.
283    #[clap(short)]
284    pub yes: bool,
285}
286
287/// Argument for ignoring applied migrations that were not resolved.
288#[derive(Args, Copy, Clone, Debug)]
289pub struct IgnoreMissing {
290    /// Ignore applied migrations that are missing in the resolved migrations
291    #[clap(long)]
292    ignore_missing: bool,
293}
294
295impl Deref for IgnoreMissing {
296    type Target = bool;
297
298    fn deref(&self) -> &Self::Target {
299        &self.ignore_missing
300    }
301}
302
303impl Not for IgnoreMissing {
304    type Output = bool;
305
306    fn not(self) -> Self::Output {
307        !self.ignore_missing
308    }
309}