Skip to content

Commit 22ef174

Browse files
committed
feat(cli): add migrate subcommand for generating a build script
suggest embedding migrations on `sqlx migrate add` in a new project
1 parent edb6b5f commit 22ef174

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

sqlx-cli/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub async fn run(opt: Opt) -> anyhow::Result<()> {
3636
ignore_missing,
3737
} => migrate::revert(&migrate.source, &database_url, dry_run, ignore_missing).await?,
3838
MigrateCommand::Info => migrate::info(&migrate.source, &database_url).await?,
39+
MigrateCommand::BuildScript { force } => migrate::build_script(&migrate.source, force)?,
3940
},
4041

4142
Command::Database(database) => match database.command {

sqlx-cli/src/migrate.rs

+57
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ pub async fn add(
4242
) -> anyhow::Result<()> {
4343
fs::create_dir_all(migration_source).context("Unable to create migrations directory")?;
4444

45+
// if the migrations directory is empty
46+
let has_existing_migrations = fs::read_dir(migration_source)
47+
.map(|mut dir| dir.next().is_some())
48+
.unwrap_or(false);
49+
4550
let migrator = Migrator::new(Path::new(migration_source)).await?;
4651
// This checks if all existing migrations are of the same type as the reverisble flag passed
4752
for migration in migrator.iter() {
@@ -74,6 +79,31 @@ pub async fn add(
7479
)?;
7580
}
7681

82+
if !has_existing_migrations {
83+
let quoted_source = if migration_source != "migrations" {
84+
format!("{:?}", migration_source)
85+
} else {
86+
"".to_string()
87+
};
88+
89+
print!(
90+
r#"
91+
Congratulations on creating your first migration!
92+
93+
Did you know you can embed your migrations in your application binary?
94+
On startup, after creating your database connection or pool, add:
95+
96+
sqlx::migrate!({}).run(<&your_pool OR &mut your_connection>).await?;
97+
98+
Note that the compiler won't pick up new migrations if no Rust source files have changed.
99+
You can create a Cargo build script to work around this with `sqlx migrate build-script`.
100+
101+
See: https://docs.rs/sqlx/0.5/sqlx/macro.migrate.html
102+
"#,
103+
quoted_source
104+
);
105+
}
106+
77107
Ok(())
78108
}
79109

@@ -245,3 +275,30 @@ pub async fn revert(
245275

246276
Ok(())
247277
}
278+
279+
pub fn build_script(migration_source: &str, force: bool) -> anyhow::Result<()> {
280+
anyhow::ensure!(
281+
Path::new("Cargo.toml").exists(),
282+
"must be run in a Cargo project root"
283+
);
284+
285+
anyhow::ensure!(
286+
(force || !Path::new("build.rs").exists()),
287+
"build.rs already exists; use --force to overwrite"
288+
);
289+
290+
let contents = format!(
291+
r#"// generated by `sqlx migrate build-script`
292+
fn main() {{
293+
// trigger recompilation when a new migration is added
294+
println!("cargo:rerun-if-changed={}");
295+
}}"#,
296+
migration_source
297+
);
298+
299+
fs::write("build.rs", contents)?;
300+
301+
println!("Created `build.rs`; be sure to check it into version control!");
302+
303+
Ok(())
304+
}

sqlx-cli/src/opt.rs

+9
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,13 @@ pub enum MigrateCommand {
130130

131131
/// List all available migrations.
132132
Info,
133+
134+
/// Generate a `build.rs` to trigger recompilation when a new migration is added.
135+
///
136+
/// Must be run in a Cargo project root.
137+
BuildScript {
138+
/// Overwrite the build script if it already exists.
139+
#[clap(long)]
140+
force: bool,
141+
},
133142
}

src/macros.rs

+2
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,8 @@ macro_rules! query_file_scalar_unchecked (
745745
/// }
746746
/// ```
747747
///
748+
/// You can also do this automatically by running `sqlx migrate build-script`.
749+
///
748750
/// See: [The Cargo Book: 3.8 Build Scripts; Outputs of the Build Script](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#outputs-of-the-build-script)
749751
///
750752
/// #### Nightly Rust: `cfg` Flag

0 commit comments

Comments
 (0)