Skip to content

Commit 3765f67

Browse files
committed
feat: introduce migrate.create-schemas
1 parent 45c0b85 commit 3765f67

File tree

17 files changed

+384
-186
lines changed

17 files changed

+384
-186
lines changed

sqlx-cli/src/database.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::{migrate, Config};
21
use crate::opt::{ConnectOpts, MigrationSourceOpt};
2+
use crate::{migrate, Config};
33
use console::style;
44
use promptly::{prompt, ReadlineError};
55
use sqlx::any::Any;
@@ -54,7 +54,11 @@ pub async fn reset(
5454
setup(config, migration_source, connect_opts).await
5555
}
5656

57-
pub async fn setup(config: &Config, migration_source: &MigrationSourceOpt, connect_opts: &ConnectOpts) -> anyhow::Result<()> {
57+
pub async fn setup(
58+
config: &Config,
59+
migration_source: &MigrationSourceOpt,
60+
connect_opts: &ConnectOpts,
61+
) -> anyhow::Result<()> {
5862
create(connect_opts).await?;
5963
migrate::run(config, migration_source, connect_opts, false, false, None).await
6064
}

sqlx-cli/src/lib.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::io;
2-
use std::path::{PathBuf};
2+
use std::path::PathBuf;
33
use std::time::Duration;
44

55
use anyhow::{Context, Result};
@@ -28,7 +28,7 @@ pub async fn run(opt: Opt) -> Result<()> {
2828

2929
match opt.command {
3030
Command::Migrate(migrate) => match migrate.command {
31-
MigrateCommand::Add(opts)=> migrate::add(config, opts).await?,
31+
MigrateCommand::Add(opts) => migrate::add(config, opts).await?,
3232
MigrateCommand::Run {
3333
source,
3434
dry_run,
@@ -74,23 +74,25 @@ pub async fn run(opt: Opt) -> Result<()> {
7474
connect_opts.populate_db_url(config)?;
7575

7676
migrate::info(config, &source, &connect_opts).await?
77-
},
78-
MigrateCommand::BuildScript { source, force } => migrate::build_script(config, &source, force)?,
77+
}
78+
MigrateCommand::BuildScript { source, force } => {
79+
migrate::build_script(config, &source, force)?
80+
}
7981
},
8082

8183
Command::Database(database) => match database.command {
8284
DatabaseCommand::Create { mut connect_opts } => {
8385
connect_opts.populate_db_url(config)?;
8486
database::create(&connect_opts).await?
85-
},
87+
}
8688
DatabaseCommand::Drop {
8789
confirmation,
8890
mut connect_opts,
8991
force,
9092
} => {
9193
connect_opts.populate_db_url(config)?;
9294
database::drop(&connect_opts, !confirmation.yes, force).await?
93-
},
95+
}
9496
DatabaseCommand::Reset {
9597
confirmation,
9698
source,
@@ -99,14 +101,14 @@ pub async fn run(opt: Opt) -> Result<()> {
99101
} => {
100102
connect_opts.populate_db_url(config)?;
101103
database::reset(config, &source, &connect_opts, !confirmation.yes, force).await?
102-
},
104+
}
103105
DatabaseCommand::Setup {
104106
source,
105107
mut connect_opts,
106108
} => {
107109
connect_opts.populate_db_url(config)?;
108110
database::setup(config, &source, &connect_opts).await?
109-
},
111+
}
110112
},
111113

112114
Command::Prepare {
@@ -118,7 +120,7 @@ pub async fn run(opt: Opt) -> Result<()> {
118120
} => {
119121
connect_opts.populate_db_url(config)?;
120122
prepare::run(check, all, workspace, connect_opts, args).await?
121-
},
123+
}
122124

123125
#[cfg(feature = "completions")]
124126
Command::Completions { shell } => completions::run(shell),
@@ -183,6 +185,6 @@ async fn config_from_current_dir() -> anyhow::Result<&'static Config> {
183185

184186
Config::read_with_or_default(move || Ok(path))
185187
})
186-
.await
187-
.context("unexpected error loading config")
188+
.await
189+
.context("unexpected error loading config")
188190
}

sqlx-cli/src/migrate.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
1+
use crate::config::Config;
12
use crate::opt::{AddMigrationOpts, ConnectOpts, MigrationSourceOpt};
23
use anyhow::{bail, Context};
34
use console::style;
4-
use sqlx::migrate::{AppliedMigration, Migrate, MigrateError, MigrationType, Migrator, ResolveWith};
5+
use sqlx::migrate::{
6+
AppliedMigration, Migrate, MigrateError, MigrationType, Migrator, ResolveWith,
7+
};
58
use sqlx::Connection;
69
use std::borrow::Cow;
710
use std::collections::{HashMap, HashSet};
811
use std::fmt::Write;
912
use std::fs::{self, File};
1013
use std::path::Path;
1114
use std::time::Duration;
12-
use crate::config::Config;
1315

14-
pub async fn add(
15-
config: &Config,
16-
opts: AddMigrationOpts,
17-
) -> anyhow::Result<()> {
16+
pub async fn add(config: &Config, opts: AddMigrationOpts) -> anyhow::Result<()> {
1817
let source = opts.source.resolve(config);
19-
18+
2019
fs::create_dir_all(source).context("Unable to create migrations directory")?;
2120

2221
let migrator = Migrator::new(Path::new(source)).await?;
@@ -124,13 +123,27 @@ fn short_checksum(checksum: &[u8]) -> String {
124123
s
125124
}
126125

127-
pub async fn info(config: &Config, migration_source: &MigrationSourceOpt, connect_opts: &ConnectOpts) -> anyhow::Result<()> {
126+
pub async fn info(
127+
config: &Config,
128+
migration_source: &MigrationSourceOpt,
129+
connect_opts: &ConnectOpts,
130+
) -> anyhow::Result<()> {
128131
let source = migration_source.resolve(config);
129-
130-
let migrator = Migrator::new(ResolveWith(Path::new(source), config.migrate.to_resolve_config())).await?;
132+
133+
let migrator = Migrator::new(ResolveWith(
134+
Path::new(source),
135+
config.migrate.to_resolve_config(),
136+
))
137+
.await?;
131138
let mut conn = crate::connect(connect_opts).await?;
132139

133-
conn.ensure_migrations_table(config.migrate.table_name()).await?;
140+
// FIXME: we shouldn't actually be creating anything here
141+
for schema_name in &config.migrate.create_schemas {
142+
conn.create_schema_if_not_exists(schema_name).await?;
143+
}
144+
145+
conn.ensure_migrations_table(config.migrate.table_name())
146+
.await?;
134147

135148
let applied_migrations: HashMap<_, _> = conn
136149
.list_applied_migrations(config.migrate.table_name())
@@ -214,7 +227,7 @@ pub async fn run(
214227
target_version: Option<i64>,
215228
) -> anyhow::Result<()> {
216229
let source = migration_source.resolve(config);
217-
230+
218231
let migrator = Migrator::new(Path::new(source)).await?;
219232
if let Some(target_version) = target_version {
220233
if !migrator.version_exists(target_version) {
@@ -224,14 +237,21 @@ pub async fn run(
224237

225238
let mut conn = crate::connect(connect_opts).await?;
226239

227-
conn.ensure_migrations_table(config.migrate.table_name()).await?;
240+
for schema_name in &config.migrate.create_schemas {
241+
conn.create_schema_if_not_exists(schema_name).await?;
242+
}
243+
244+
conn.ensure_migrations_table(config.migrate.table_name())
245+
.await?;
228246

229247
let version = conn.dirty_version(config.migrate.table_name()).await?;
230248
if let Some(version) = version {
231249
bail!(MigrateError::Dirty(version));
232250
}
233251

234-
let applied_migrations = conn.list_applied_migrations(config.migrate.table_name()).await?;
252+
let applied_migrations = conn
253+
.list_applied_migrations(config.migrate.table_name())
254+
.await?;
235255
validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;
236256

237257
let latest_version = applied_migrations
@@ -319,14 +339,22 @@ pub async fn revert(
319339

320340
let mut conn = crate::connect(connect_opts).await?;
321341

322-
conn.ensure_migrations_table(config.migrate.table_name()).await?;
342+
// FIXME: we should not be creating anything here if it doesn't exist
343+
for schema_name in &config.migrate.create_schemas {
344+
conn.create_schema_if_not_exists(schema_name).await?;
345+
}
346+
347+
conn.ensure_migrations_table(config.migrate.table_name())
348+
.await?;
323349

324350
let version = conn.dirty_version(config.migrate.table_name()).await?;
325351
if let Some(version) = version {
326352
bail!(MigrateError::Dirty(version));
327353
}
328354

329-
let applied_migrations = conn.list_applied_migrations(config.migrate.table_name()).await?;
355+
let applied_migrations = conn
356+
.list_applied_migrations(config.migrate.table_name())
357+
.await?;
330358
validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;
331359

332360
let latest_version = applied_migrations
@@ -397,9 +425,13 @@ pub async fn revert(
397425
Ok(())
398426
}
399427

400-
pub fn build_script(config: &Config, migration_source: &MigrationSourceOpt, force: bool) -> anyhow::Result<()> {
428+
pub fn build_script(
429+
config: &Config,
430+
migration_source: &MigrationSourceOpt,
431+
force: bool,
432+
) -> anyhow::Result<()> {
401433
let source = migration_source.resolve(config);
402-
434+
403435
anyhow::ensure!(
404436
Path::new("Cargo.toml").exists(),
405437
"must be run in a Cargo project root"

sqlx-cli/src/opt.rs

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use std::env;
2-
use std::ops::{Deref, Not};
1+
use crate::config::migrate::{DefaultMigrationType, DefaultVersioning};
2+
use crate::config::Config;
33
use anyhow::Context;
44
use chrono::Utc;
55
use clap::{Args, Parser};
66
#[cfg(feature = "completions")]
77
use clap_complete::Shell;
8-
use crate::config::Config;
98
use sqlx::migrate::Migrator;
10-
use crate::config::migrate::{DefaultMigrationType, DefaultVersioning};
9+
use std::env;
10+
use std::ops::{Deref, Not};
1111

1212
#[derive(Parser, Debug)]
1313
#[clap(version, about, author)]
@@ -129,7 +129,7 @@ pub enum MigrateCommand {
129129
/// Create a new migration with the given description.
130130
///
131131
/// --------------------------------
132-
///
132+
///
133133
/// Migrations may either be simple, or reversible.
134134
///
135135
/// Reversible migrations can be reverted with `sqlx migrate revert`, simple migrations cannot.
@@ -152,7 +152,7 @@ pub enum MigrateCommand {
152152
/// It is recommended to always back up the database before running migrations.
153153
///
154154
/// --------------------------------
155-
///
155+
///
156156
/// For convenience, this command attempts to detect if reversible migrations are in-use.
157157
///
158158
/// If the latest existing migration is reversible, the new migration will also be reversible.
@@ -164,7 +164,7 @@ pub enum MigrateCommand {
164164
/// The default type to use can also be set in `sqlx.toml`.
165165
///
166166
/// --------------------------------
167-
///
167+
///
168168
/// A version number will be automatically assigned to the migration.
169169
///
170170
/// Migrations are applied in ascending order by version number.
@@ -174,9 +174,9 @@ pub enum MigrateCommand {
174174
/// less than _any_ previously applied migration.
175175
///
176176
/// Migrations should only be created with increasing version number.
177-
///
177+
///
178178
/// --------------------------------
179-
///
179+
///
180180
/// For convenience, this command will attempt to detect if sequential versioning is in use,
181181
/// and if so, continue the sequence.
182182
///
@@ -290,7 +290,7 @@ pub struct AddMigrationOpts {
290290
#[derive(Args, Debug)]
291291
pub struct MigrationSourceOpt {
292292
/// Path to folder containing migrations.
293-
///
293+
///
294294
/// Defaults to `migrations/` if not specified, but a different default may be set by `sqlx.toml`.
295295
#[clap(long)]
296296
pub source: Option<String>,
@@ -301,7 +301,7 @@ impl MigrationSourceOpt {
301301
if let Some(source) = &self.source {
302302
return source;
303303
}
304-
304+
305305
config.migrate.migrations_dir()
306306
}
307307
}
@@ -335,7 +335,9 @@ impl ConnectOpts {
335335
/// Require a database URL to be provided, otherwise
336336
/// return an error.
337337
pub fn expect_db_url(&self) -> anyhow::Result<&str> {
338-
self.database_url.as_deref().context("BUG: database_url not populated")
338+
self.database_url
339+
.as_deref()
340+
.context("BUG: database_url not populated")
339341
}
340342

341343
/// Populate `database_url` from the environment, if not set.
@@ -359,7 +361,7 @@ impl ConnectOpts {
359361
}
360362

361363
self.database_url = Some(url)
362-
},
364+
}
363365
Err(env::VarError::NotPresent) => {
364366
anyhow::bail!("`--database-url` or `{var}`{context} must be set")
365367
}
@@ -407,22 +409,20 @@ impl Not for IgnoreMissing {
407409

408410
impl AddMigrationOpts {
409411
pub fn reversible(&self, config: &Config, migrator: &Migrator) -> bool {
410-
if self.reversible { return true; }
411-
if self.simple { return false; }
412+
if self.reversible {
413+
return true;
414+
}
415+
if self.simple {
416+
return false;
417+
}
412418

413419
match config.migrate.defaults.migration_type {
414-
DefaultMigrationType::Inferred => {
415-
migrator
416-
.iter()
417-
.last()
418-
.is_some_and(|m| m.migration_type.is_reversible())
419-
}
420-
DefaultMigrationType::Simple => {
421-
false
422-
}
423-
DefaultMigrationType::Reversible => {
424-
true
425-
}
420+
DefaultMigrationType::Inferred => migrator
421+
.iter()
422+
.last()
423+
.is_some_and(|m| m.migration_type.is_reversible()),
424+
DefaultMigrationType::Simple => false,
425+
DefaultMigrationType::Reversible => true,
426426
}
427427
}
428428

@@ -434,8 +434,7 @@ impl AddMigrationOpts {
434434
}
435435

436436
if self.sequential || matches!(default_versioning, DefaultVersioning::Sequential) {
437-
return next_sequential(migrator)
438-
.unwrap_or_else(|| fmt_sequential(1));
437+
return next_sequential(migrator).unwrap_or_else(|| fmt_sequential(1));
439438
}
440439

441440
next_sequential(migrator).unwrap_or_else(next_timestamp)
@@ -455,18 +454,16 @@ fn next_sequential(migrator: &Migrator) -> Option<String> {
455454
match migrations {
456455
[previous, latest] => {
457456
// If the latest two versions differ by 1, infer sequential.
458-
(latest.version - previous.version == 1)
459-
.then_some(latest.version + 1)
460-
},
457+
(latest.version - previous.version == 1).then_some(latest.version + 1)
458+
}
461459
[latest] => {
462460
// If only one migration exists and its version is 0 or 1, infer sequential
463-
matches!(latest.version, 0 | 1)
464-
.then_some(latest.version + 1)
461+
matches!(latest.version, 0 | 1).then_some(latest.version + 1)
465462
}
466463
_ => unreachable!(),
467464
}
468465
});
469-
466+
470467
next_version.map(fmt_sequential)
471468
}
472469

0 commit comments

Comments
 (0)