-
Notifications
You must be signed in to change notification settings - Fork 216
/
migration_persistence.rs
108 lines (93 loc) 路 5.03 KB
/
migration_persistence.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{checksum, ConnectorError, ConnectorResult};
/// A timestamp.
pub type Timestamp = chrono::DateTime<chrono::Utc>;
/// Management of imperative migrations state in the database.
#[async_trait::async_trait]
pub trait MigrationPersistence: Send + Sync {
/// Initialize the migration persistence without checking the database first.
async fn baseline_initialize(&self) -> ConnectorResult<()>;
/// This method is responsible for checking whether the migrations
/// persistence is initialized.
///
/// If the migration persistence is not present in the target database,
/// check whether the database schema is empty. If it is, initialize the
/// migration persistence. If not, return a DatabaseSchemaNotEmpty error.
async fn initialize(&self) -> ConnectorResult<()>;
/// Implementation in the connector for the core's MarkMigrationApplied
/// command. See the docs there. Note that the started_at and finished_at
/// for the migration should be the same.
///
/// Connectors should implement mark_migration_applied_impl to avoid doing
/// the checksuming themselves.
async fn mark_migration_applied(&self, migration_name: &str, script: &str) -> ConnectorResult<String> {
self.mark_migration_applied_impl(migration_name, &checksum::render_checksum(script))
.await
}
/// Implementation in the connector for the core's MarkMigrationApplied
/// command. See the docs there. Note that the started_at and finished_at
/// for the migration should be the same.
async fn mark_migration_applied_impl(&self, migration_name: &str, checksum: &str) -> ConnectorResult<String>;
/// Mark the failed instances of the migration in the persistence as rolled
/// back, so they will be ignored by the engine in the future.
async fn mark_migration_rolled_back_by_id(&self, migration_id: &str) -> ConnectorResult<()>;
/// Record that a migration is about to be applied. Returns the unique
/// identifier for the migration.
///
/// This is a default method that computes the checksum. Implementors should
/// implement record_migration_started_impl.
async fn record_migration_started(&self, migration_name: &str, script: &str) -> ConnectorResult<String> {
self.record_migration_started_impl(migration_name, &checksum::render_checksum(script))
.await
}
/// Record that a migration is about to be applied. Returns the unique
/// identifier for the migration.
///
/// This is an implementation detail, consumers should use
/// `record_migration_started()` instead.
async fn record_migration_started_impl(&self, migration_name: &str, checksum: &str) -> ConnectorResult<String>;
/// Increase the applied_steps_count counter.
async fn record_successful_step(&self, id: &str) -> ConnectorResult<()>;
/// Report logs for a failed migration step. We assume the next steps in the
/// migration will not be applied, and the error reported.
async fn record_failed_step(&self, id: &str, logs: &str) -> ConnectorResult<()>;
/// Record that the migration completed *successfully*. This means
/// populating the `finished_at` field in the migration record.
async fn record_migration_finished(&self, id: &str) -> ConnectorResult<()>;
/// List all applied migrations, ordered by `started_at`. This should fail
/// with a PersistenceNotInitializedError when the migration persistence is
/// not initialized.
async fn list_migrations(&self) -> ConnectorResult<Result<Vec<MigrationRecord>, PersistenceNotInitializedError>>;
}
/// Error returned when the persistence is not initialized.
#[derive(Debug)]
pub struct PersistenceNotInitializedError;
impl PersistenceNotInitializedError {
/// Explicit conversion to a ConnectorError.
pub fn into_connector_error(self) -> ConnectorError {
ConnectorError::from_msg("Invariant violation: migration persistence is not initialized.".into())
}
}
/// An applied migration, as returned by list_migrations.
#[derive(Debug)]
pub struct MigrationRecord {
/// A unique, randomly generated identifier.
pub id: String,
/// The SHA-256 checksum of the migration script, to detect if it was
/// edited. It covers only the content of the script file, it does not
/// include timestamp or migration name information.
pub checksum: String,
/// The timestamp at which the migration completed *successfully*.
pub finished_at: Option<Timestamp>,
/// The name of the migration, i.e. the name of migration directory
/// containing the migration script.
pub migration_name: String,
/// The human-readable log of actions performed by the engine, up to and
/// including the point where the migration failed, with the relevant error.
pub logs: Option<String>,
/// If the migration was rolled back, and when.
pub rolled_back_at: Option<Timestamp>,
/// The time the migration started being applied.
pub started_at: Timestamp,
/// The number of migration steps that were successfully applied.
pub applied_steps_count: u32,
}