Skip to main content

diesel/migration/
mod.rs

1//! Representation of migrations
2
3use crate::backend::Backend;
4use crate::connection::{BoxableConnection, Connection};
5use crate::deserialize::{FromSql, FromSqlRow};
6use crate::expression::AsExpression;
7use crate::result::QueryResult;
8use crate::serialize::ToSql;
9use crate::sql_types::Text;
10use alloc::borrow::Cow;
11use alloc::borrow::ToOwned;
12use alloc::boxed::Box;
13use alloc::string::String;
14use alloc::vec::Vec;
15use core::error::Error;
16use core::fmt::Display;
17
18/// A specialized result type representing the result of
19/// a migration operation
20pub type Result<T> = core::result::Result<T, Box<dyn Error + Send + Sync>>;
21
22/// A migration version identifier
23///
24/// This is used by the migration harness to place migrations
25/// in order, therefore two different instances of this type
26/// must be sortable
27#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for MigrationVersion<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "MigrationVersion", &&self.0)
    }
}Debug, #[automatically_derived]
impl<'a> ::core::hash::Hash for MigrationVersion<'a> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl<'a> ::core::cmp::PartialEq for MigrationVersion<'a> {
    #[inline]
    fn eq(&self, other: &MigrationVersion<'a>) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<'a> ::core::cmp::Eq for MigrationVersion<'a> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Cow<'a, str>>;
    }
}Eq, #[automatically_derived]
impl<'a> ::core::cmp::PartialOrd for MigrationVersion<'a> {
    #[inline]
    fn partial_cmp(&self, other: &MigrationVersion<'a>)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}PartialOrd, #[automatically_derived]
impl<'a> ::core::cmp::Ord for MigrationVersion<'a> {
    #[inline]
    fn cmp(&self, other: &MigrationVersion<'a>) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, const _: () =
    {
        use diesel;
        impl<'a, __DB, __ST> diesel::deserialize::Queryable<__ST, __DB> for
            MigrationVersion<'a> where __DB: diesel::backend::Backend,
            __ST: diesel::sql_types::SingleValue,
            Self: diesel::deserialize::FromSql<__ST, __DB> {
            type Row = Self;
            fn build(row: Self) -> diesel::deserialize::Result<Self> {
                diesel::deserialize::Result::Ok(row)
            }
        }
    };FromSqlRow, const _: () =
    {
        use diesel;
        impl<'a, '__expr> diesel::expression::AsExpression<Text> for
            &'__expr MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Text, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Text>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'a, '__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>
            for &'__expr MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Text>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'a, '__expr, '__expr2> diesel::expression::AsExpression<Text> for
            &'__expr2 &'__expr MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Text, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Text>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'a, '__expr, '__expr2>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>
            for &'__expr2 &'__expr MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Text>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'a, __DB>
            diesel::serialize::ToSql<diesel::sql_types::Nullable<Text>, __DB>
            for MigrationVersion<'a> where __DB: diesel::backend::Backend,
            Self: diesel::serialize::ToSql<Text, __DB> {
            fn to_sql<'__b>(&'__b self,
                out: &mut diesel::serialize::Output<'__b, '_, __DB>)
                -> diesel::serialize::Result {
                diesel::serialize::ToSql::<Text, __DB>::to_sql(self, out)
            }
        }
        impl<'a> diesel::expression::AsExpression<Text> for
            MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Text, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Text>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'a>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>
            for MigrationVersion<'a> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Text>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Text>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
    };AsExpression)]
28#[diesel(sql_type = Text)]
29pub struct MigrationVersion<'a>(Cow<'a, str>);
30
31impl MigrationVersion<'_> {
32    /// Convert the current migration version into
33    /// an owned variant with static life time
34    pub fn as_owned(&self) -> MigrationVersion<'static> {
35        MigrationVersion(Cow::Owned(self.0.as_ref().to_owned()))
36    }
37}
38
39impl<DB> FromSql<Text, DB> for MigrationVersion<'_>
40where
41    String: FromSql<Text, DB>,
42    DB: Backend,
43{
44    fn from_sql(bytes: DB::RawValue<'_>) -> crate::deserialize::Result<Self> {
45        let s = String::from_sql(bytes)?;
46        Ok(Self(Cow::Owned(s)))
47    }
48}
49
50impl<'a, DB> ToSql<Text, DB> for MigrationVersion<'a>
51where
52    Cow<'a, str>: ToSql<Text, DB>,
53    DB: Backend,
54{
55    fn to_sql<'b>(
56        &'b self,
57        out: &mut crate::serialize::Output<'b, '_, DB>,
58    ) -> crate::serialize::Result {
59        self.0.to_sql(out)
60    }
61}
62
63impl From<String> for MigrationVersion<'_> {
64    fn from(s: String) -> Self {
65        MigrationVersion(Cow::Owned(s))
66    }
67}
68
69impl<'a> From<&'a str> for MigrationVersion<'a> {
70    fn from(s: &'a str) -> Self {
71        MigrationVersion(Cow::Borrowed(s))
72    }
73}
74
75impl<'a> From<&'a String> for MigrationVersion<'a> {
76    fn from(s: &'a String) -> Self {
77        MigrationVersion(Cow::Borrowed(s))
78    }
79}
80
81impl Display for MigrationVersion<'_> {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        f.write_str(self.0.as_ref())
84    }
85}
86
87/// Represents the name of a migration
88///
89/// Users should treat this as `impl Display` type,
90/// for implementors of custom migration types this
91/// opens the possibility to roll out their own
92/// versioning schema.
93pub trait MigrationName: Display {
94    /// The version corresponding to the current migration name
95    fn version(&self) -> MigrationVersion<'_>;
96}
97
98/// Represents a migration that interacts with diesel
99pub trait Migration<DB: Backend> {
100    /// Apply this migration
101    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()>;
102
103    /// Revert this migration
104    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()>;
105
106    /// Get a the attached metadata for this migration
107    fn metadata(&self) -> &dyn MigrationMetadata;
108
109    /// Get the name of the current migration
110    ///
111    /// The provided name is used by migration harness
112    /// to get the version of a migration and to
113    /// as something to that is displayed and allows
114    /// user to identify a specific migration
115    fn name(&self) -> &dyn MigrationName;
116}
117
118/// This trait is designed to customize the behaviour
119/// of the default migration harness of diesel
120///
121/// Any new customization option will be added
122/// as new function here. Each new function
123/// will have a default implementation
124/// returning the old a value corresponding
125/// to the old uncustomized behaviour
126pub trait MigrationMetadata {
127    /// Whether the current migration is executed in a transaction or not
128    ///
129    /// By default each migration is executed in a own transaction, but
130    /// certain operations (like creating an index on an existing column)
131    /// requires running the migration without transaction.
132    ///
133    /// By default this function returns true
134    fn run_in_transaction(&self) -> bool {
135        true
136    }
137}
138
139/// A migration source is an entity that can be used
140/// to receive a number of migrations from.
141pub trait MigrationSource<DB: Backend> {
142    /// Get a list of migrations associated with this
143    /// migration source.
144    fn migrations(&self) -> Result<Vec<Box<dyn Migration<DB>>>>;
145}
146
147impl<DB: Backend> Migration<DB> for Box<dyn Migration<DB> + '_> {
148    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
149        (**self).run(conn)
150    }
151
152    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
153        (**self).revert(conn)
154    }
155
156    fn metadata(&self) -> &dyn MigrationMetadata {
157        (**self).metadata()
158    }
159
160    fn name(&self) -> &dyn MigrationName {
161        (**self).name()
162    }
163}
164
165impl<DB: Backend> Migration<DB> for &dyn Migration<DB> {
166    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
167        (**self).run(conn)
168    }
169
170    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
171        (**self).revert(conn)
172    }
173
174    fn metadata(&self) -> &dyn MigrationMetadata {
175        (**self).metadata()
176    }
177
178    fn name(&self) -> &dyn MigrationName {
179        (**self).name()
180    }
181}
182
183/// Create table statement for the `__diesel_schema_migrations` used
184/// used by the postgresql, sqlite and mysql backend
185pub const CREATE_MIGRATIONS_TABLE: &str = "CREATE TABLE IF NOT EXISTS __diesel_schema_migrations (\n       version VARCHAR(50) PRIMARY KEY NOT NULL,\n       run_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\n"include_str!("setup_migration_table.sql");
186
187/// A trait indicating that a connection could be used to manage migrations
188///
189/// Only custom backend implementations need to think about this trait
190pub trait MigrationConnection: Connection {
191    /// Setup the following table:
192    ///
193    /// ```rust
194    /// diesel::table! {
195    ///      __diesel_schema_migrations(version) {
196    ///          version -> Text,
197    ///          /// defaults to `CURRENT_TIMESTAMP`
198    ///          run_on -> Timestamp,
199    ///      }
200    /// }
201    /// ```
202    fn setup(&mut self) -> QueryResult<usize>;
203}
204
205#[cfg(feature = "postgres")]
206impl MigrationConnection for crate::pg::PgConnection {
207    fn setup(&mut self) -> QueryResult<usize> {
208        use crate::RunQueryDsl;
209        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
210    }
211}
212
213#[cfg(feature = "mysql")]
214impl MigrationConnection for crate::mysql::MysqlConnection {
215    fn setup(&mut self) -> QueryResult<usize> {
216        use crate::RunQueryDsl;
217        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
218    }
219}
220
221#[cfg(feature = "__sqlite-shared")]
222impl MigrationConnection for crate::sqlite::SqliteConnection {
223    fn setup(&mut self) -> QueryResult<usize> {
224        use crate::RunQueryDsl;
225        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
226    }
227}