mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-03-19 08:39:44 +00:00
feat: no tx migration (#3181)
* test: add a failing test * feat: add no_tx to migration struct * feat: execute migration with no tx block * fix: expected string literal compilation error * test: update no tx to content comment * refactor: use the sql comment instead of file name semantics * docs: remove no_tx from file format comment * fix: remove filename matches * fix: messed up merge * refactor: dedupe migration * fix: move comment to where it makes sense * fix: linter error
This commit is contained in:
@@ -208,38 +208,25 @@ CREATE TABLE IF NOT EXISTS _sqlx_migrations (
|
||||
migration: &'m Migration,
|
||||
) -> BoxFuture<'m, Result<Duration, MigrateError>> {
|
||||
Box::pin(async move {
|
||||
let mut tx = self.begin().await?;
|
||||
let start = Instant::now();
|
||||
|
||||
// Use a single transaction for the actual migration script and the essential bookeeping so we never
|
||||
// execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.
|
||||
// The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for
|
||||
// data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1
|
||||
// and update it once the actual transaction completed.
|
||||
let _ = tx
|
||||
.execute(&*migration.sql)
|
||||
.await
|
||||
.map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;
|
||||
|
||||
// language=SQL
|
||||
let _ = query(
|
||||
r#"
|
||||
INSERT INTO _sqlx_migrations ( version, description, success, checksum, execution_time )
|
||||
VALUES ( $1, $2, TRUE, $3, -1 )
|
||||
"#,
|
||||
)
|
||||
.bind(migration.version)
|
||||
.bind(&*migration.description)
|
||||
.bind(&*migration.checksum)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
// execute migration queries
|
||||
if migration.no_tx {
|
||||
execute_migration(self, migration).await?;
|
||||
} else {
|
||||
// Use a single transaction for the actual migration script and the essential bookeeping so we never
|
||||
// execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.
|
||||
// The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for
|
||||
// data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1
|
||||
// and update it once the actual transaction completed.
|
||||
let mut tx = self.begin().await?;
|
||||
execute_migration(&mut tx, migration).await?;
|
||||
tx.commit().await?;
|
||||
}
|
||||
|
||||
// Update `elapsed_time`.
|
||||
// NOTE: The process may disconnect/die at this point, so the elapsed time value might be lost. We accept
|
||||
// this small risk since this value is not super important.
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
|
||||
// language=SQL
|
||||
@@ -286,6 +273,31 @@ CREATE TABLE IF NOT EXISTS _sqlx_migrations (
|
||||
}
|
||||
}
|
||||
|
||||
async fn execute_migration(
|
||||
conn: &mut PgConnection,
|
||||
migration: &Migration,
|
||||
) -> Result<(), MigrateError> {
|
||||
let _ = conn
|
||||
.execute(&*migration.sql)
|
||||
.await
|
||||
.map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;
|
||||
|
||||
// language=SQL
|
||||
let _ = query(
|
||||
r#"
|
||||
INSERT INTO _sqlx_migrations ( version, description, success, checksum, execution_time )
|
||||
VALUES ( $1, $2, TRUE, $3, -1 )
|
||||
"#,
|
||||
)
|
||||
.bind(migration.version)
|
||||
.bind(&*migration.description)
|
||||
.bind(&*migration.checksum)
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn current_database(conn: &mut PgConnection) -> Result<String, MigrateError> {
|
||||
// language=SQL
|
||||
Ok(query_scalar("SELECT current_database()")
|
||||
|
||||
Reference in New Issue
Block a user