icydb_core/db/schema_evolution/
execution.rs1use crate::{
7 db::{
8 Db,
9 migration::{self, MigrationRunOutcome, MigrationRunState},
10 schema_evolution::{MigrationRegistry, SchemaMigrationDescriptor, SchemaMigrationPlanner},
11 },
12 error::InternalError,
13 traits::CanisterKind,
14};
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub enum SchemaMigrationExecutionOutcome {
26 AlreadyApplied,
27 Executed(MigrationRunOutcome),
28}
29
30impl SchemaMigrationExecutionOutcome {
31 #[must_use]
34 pub const fn already_applied(self) -> bool {
35 matches!(self, Self::AlreadyApplied)
36 }
37
38 #[must_use]
40 pub const fn migration_outcome(self) -> Option<MigrationRunOutcome> {
41 match self {
42 Self::AlreadyApplied => None,
43 Self::Executed(outcome) => Some(outcome),
44 }
45 }
46}
47
48pub(in crate::db) fn execute_schema_migration_descriptor<C: CanisterKind>(
50 db: &Db<C>,
51 registry: &mut MigrationRegistry,
52 planner: &SchemaMigrationPlanner,
53 descriptor: &SchemaMigrationDescriptor,
54 max_steps: usize,
55) -> Result<SchemaMigrationExecutionOutcome, InternalError> {
56 if registry.is_applied(descriptor.migration_id(), descriptor.version()) {
59 return Ok(SchemaMigrationExecutionOutcome::AlreadyApplied);
60 }
61
62 let plan = planner.plan(descriptor)?;
65 let outcome = migration::execute_migration_plan(db, &plan, max_steps)?;
66
67 if matches!(outcome.state(), MigrationRunState::Complete) {
70 registry.record_applied(descriptor.migration_id(), descriptor.version());
71 }
72
73 Ok(SchemaMigrationExecutionOutcome::Executed(outcome))
74}