Skip to content

Commit 6a93e8a

Browse files
Merge pull request #40 from iamsauravsharma/fake-apply-support
2 parents 2818475 + 31c7d60 commit 6a93e8a

File tree

3 files changed

+64
-43
lines changed

3 files changed

+64
-43
lines changed

README.MD

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,25 +163,31 @@ async fn main() {
163163
# Running Migrations
164164

165165
You can run migrations directly or integrate them into a CLI:
166-
## Direct Execution
166+
## Programmatic Execution
167167
```rust
168168
use sqlx_migrator::migrator::Plan;
169169
let mut conn = pool.acquire().await?;
170170
// use apply all to apply all pending migration
171171
migrator.run(&mut *conn, Plan::apply_all()).await.unwrap();
172172
// or use revert all to revert all applied migrations
173173
migrator.run(&mut *conn, Plan::revert_all()).await.unwrap();
174+
// If you need to apply or revert to certain stage than see `Plan` docs
174175
```
175176

176177
## CLI Integration
178+
To integrate sqlx_migrator into your CLI, you can either use the built-in
179+
`MigrationCommand` or extend your own CLI with migrator support. Below are
180+
examples of both approaches:
181+
182+
#### Built-in Migration Command
177183

178184
```rust
179185
use sqlx_migrator::cli::MigrationCommand;
180186

181187
MigrationCommand::parse_and_run(&mut *conn, Box::new(migrator)).await.unwrap();
182188
```
183189

184-
Or extend your own CLI with migrator support:
190+
#### Extending Your Own CLI with Migrator Support
185191

186192
```rust
187193
#[derive(clap::Parser)]
@@ -211,31 +217,29 @@ impl Cli {
211217

212218
# Migrate from sqlx default sql based migration
213219

214-
To migrate from sqlx sql based migration you have two alternative:
220+
To migrate from sqlx sql based migration to rust migration the recommended approach
221+
is to rewrite your SQL migrations as Rust operations and migrations as explained above.
222+
After rewriting your SQL migrations, you need to mark them as applied without re-executing them.
223+
This step ensures that the migration state aligns with the existing database.
224+
There are two ways to perform a fake apply:
215225

216-
1. Rewrite SQL migrations as Rust operations and run fake apply cli command
217-
`<COMMAND_NAME> apply --fake`: Follow the usage example above.
218-
2. Create a single Rust operation to apply/revert SQL migrations:
226+
#### Programmatic Fake Apply
219227

228+
Use the fake option with the `Plan::apply_all()` function:
220229
```rust
221-
use sqlx_migrator::error::Error;
222-
use sqlx_migrator::operation::Operation;
230+
use sqlx_migrator::migrator::{Plan, Migrator};
223231

224-
pub(crate) struct SqlxOperation;
232+
migrator.run(&mut *conn, Plan::apply_all().fake(true)).await.unwrap();
233+
```
225234

226-
#[async_trait::async_trait]
227-
impl Operation<sqlx::Postgres> for SqlxOperation {
228-
async fn up(&self, connection: &mut sqlx::PgConnection) -> Result<(), Error> {
229-
sqlx::migrate!("migrations").run(connection).await?;
230-
Ok(())
231-
}
235+
#### CLI-Based Fake Apply
236+
If you're using a CLI, use the --fake flag with the apply command: `<migrator_cli_command> apply --fake`
232237

233-
async fn down(&self, connection: &mut sqlx::PgConnection) -> Result<(), Error> {
234-
sqlx::migrate!("migrations").undo(connection, 0).await?;
235-
Ok(())
236-
}
237-
}
238-
```
238+
### Note: Before writing any other migrations
239+
240+
Before adding new migrations for future updates, ensure you complete the above steps to mark existing migrations as applied. Run the fake apply only once to align the migration state. After this, remove the `fake(true)` option or the `--fake` flag to allow new migrations to execute normally.
241+
242+
By following these steps, you can seamlessly transition from SQLX SQL-based migrations to Rust migrations while maintaining an accurate migration state and ensuring compatibility for future updates.
239243

240244
[license_badge]: https://img.shields.io/github/license/iamsauravsharma/sqlx_migrator.svg?style=for-the-badge
241245
[license_link]: LICENSE

src/cli.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ impl Apply {
236236
} else {
237237
plan = Plan::apply_all();
238238
};
239+
let plan = plan.fake(self.fake);
239240
let migrations = migrator
240241
.generate_migration_plan(connection, Some(&plan))
241242
.await?;
@@ -259,18 +260,12 @@ impl Apply {
259260
);
260261
}
261262
}
262-
} else if self.fake {
263-
for migration in migrations {
264-
migrator
265-
.add_migration_to_db_table(connection, migration)
266-
.await?;
267-
}
268263
} else {
269264
let destructible_migrations = migrations
270265
.iter()
271266
.filter(|m| m.operations().iter().any(|o| o.is_destructible()))
272267
.collect::<Vec<_>>();
273-
if !self.force && !destructible_migrations.is_empty() {
268+
if !self.force && !destructible_migrations.is_empty() && !self.fake {
274269
let mut input = String::new();
275270
println!(
276271
"Do you want to apply destructible migrations {} (y/N)",
@@ -340,6 +335,7 @@ impl Revert {
340335
} else {
341336
plan = Plan::revert_count(1);
342337
};
338+
let plan = plan.fake(self.fake);
343339
let revert_migrations = migrator
344340
.generate_migration_plan(connection, Some(&plan))
345341
.await?;
@@ -361,14 +357,8 @@ impl Revert {
361357
);
362358
}
363359
}
364-
} else if self.fake {
365-
for migration in revert_migrations {
366-
migrator
367-
.delete_migration_from_db_table(connection, migration)
368-
.await?;
369-
}
370360
} else {
371-
if !self.force && !revert_migrations.is_empty() {
361+
if !self.force && !revert_migrations.is_empty() && !self.fake {
372362
let mut input = String::new();
373363
println!(
374364
"Do you want to revert {} migrations (y/N)",

src/migrator/mod.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub struct Plan {
185185
plan_type: PlanType,
186186
app_migration: Option<(String, Option<String>)>,
187187
count: Option<usize>,
188+
fake: bool,
188189
}
189190

190191
impl Plan {
@@ -197,9 +198,27 @@ impl Plan {
197198
plan_type,
198199
app_migration,
199200
count,
201+
fake: false,
200202
}
201203
}
202204

205+
/// Sets the plan as a "fake" plan.
206+
///
207+
/// When the plan is marked as fake, the migration status is updated to
208+
/// either "applied" or "reverted" without actually performing any
209+
/// migration operations. This is useful for scenarios where you want to
210+
/// simulate the effect of applying or reverting a migration, but
211+
/// without making changes to the database.
212+
///
213+
/// By default, the `fake` flag is set to `false`, and the migration
214+
/// operations are executed as expected.
215+
#[must_use]
216+
pub fn fake(self, fake: bool) -> Self {
217+
let mut plan = self;
218+
plan.fake = fake;
219+
plan
220+
}
221+
203222
/// Creates a new plan to apply all migrations.
204223
#[must_use]
205224
pub fn apply_all() -> Self {
@@ -853,15 +872,19 @@ where
853872
tracing::debug!("applying {} : {}", migration.app(), migration.name());
854873
if migration.is_atomic() {
855874
let mut transaction = connection.begin().await?;
856-
for operation in migration.operations() {
857-
operation.up(&mut transaction).await?;
875+
if !plan.fake {
876+
for operation in migration.operations() {
877+
operation.up(&mut transaction).await?;
878+
}
858879
}
859880
self.add_migration_to_db_table(&mut transaction, migration)
860881
.await?;
861882
transaction.commit().await?;
862883
} else {
863-
for operation in migration.operations() {
864-
operation.up(connection).await?;
884+
if !plan.fake {
885+
for operation in migration.operations() {
886+
operation.up(connection).await?;
887+
}
865888
}
866889
self.add_migration_to_db_table(connection, migration)
867890
.await?;
@@ -876,15 +899,19 @@ where
876899

877900
if migration.is_atomic() {
878901
let mut transaction = connection.begin().await?;
879-
for operation in operations {
880-
operation.down(&mut transaction).await?;
902+
if !plan.fake {
903+
for operation in operations {
904+
operation.down(&mut transaction).await?;
905+
}
881906
}
882907
self.delete_migration_from_db_table(&mut transaction, migration)
883908
.await?;
884909
transaction.commit().await?;
885910
} else {
886-
for operation in operations {
887-
operation.down(connection).await?;
911+
if !plan.fake {
912+
for operation in operations {
913+
operation.down(connection).await?;
914+
}
888915
}
889916
self.delete_migration_from_db_table(connection, migration)
890917
.await?;

0 commit comments

Comments
 (0)