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}