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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! Representation of migrations

use crate::backend::Backend;
use crate::connection::{BoxableConnection, Connection};
use crate::deserialize::{FromSql, FromSqlRow};
use crate::expression::AsExpression;
use crate::result::QueryResult;
use crate::serialize::ToSql;
use crate::sql_types::Text;
use std::borrow::Cow;
use std::error::Error;
use std::fmt::Display;

/// A specialized result type representing the result of
/// a migration operation
pub type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

/// A migration version identifier
///
/// This is used by the migration harness to place migrations
/// in order, therefore two different instances of this type
/// must be sortable
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)]
#[sql_type = "Text"]
pub struct MigrationVersion<'a>(Cow<'a, str>);

impl<'a> MigrationVersion<'a> {
    /// Convert the current migration version into
    /// an owned variant with static life time
    pub fn as_owned(&self) -> MigrationVersion<'static> {
        MigrationVersion(Cow::Owned(self.0.as_ref().to_owned()))
    }
}

impl<'a, DB> FromSql<Text, DB> for MigrationVersion<'a>
where
    String: FromSql<Text, DB>,
    DB: Backend,
{
    fn from_sql(bytes: crate::backend::RawValue<DB>) -> crate::deserialize::Result<Self> {
        let s = String::from_sql(bytes)?;
        Ok(Self(Cow::Owned(s)))
    }
}

impl<'a, DB> ToSql<Text, DB> for MigrationVersion<'a>
where
    Cow<'a, str>: ToSql<Text, DB>,
    DB: Backend,
{
    fn to_sql<W: std::io::Write>(
        &self,
        out: &mut crate::serialize::Output<W, DB>,
    ) -> crate::serialize::Result {
        self.0.to_sql(out)
    }
}

impl<'a> From<String> for MigrationVersion<'a> {
    fn from(s: String) -> Self {
        MigrationVersion(Cow::Owned(s))
    }
}

impl<'a> From<&'a str> for MigrationVersion<'a> {
    fn from(s: &'a str) -> Self {
        MigrationVersion(Cow::Borrowed(s))
    }
}

impl<'a> From<&'a String> for MigrationVersion<'a> {
    fn from(s: &'a String) -> Self {
        MigrationVersion(Cow::Borrowed(s))
    }
}

impl<'a> Display for MigrationVersion<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.0.as_ref())
    }
}

/// Represents the name of a migration
///
/// Users should threat this as `impl Display` type,
/// for implementors of custom migration types
/// this opens the possibility to roll out their own versioning
/// schema.
pub trait MigrationName: Display {
    /// The version corresponding to the current migration name
    fn version(&self) -> MigrationVersion;
}

/// Represents a migration that interacts with diesel
pub trait Migration<DB: Backend> {
    /// Apply this migration
    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()>;

    /// Revert this migration
    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()>;

    /// Get a the attached metadata for this migration
    fn metadata(&self) -> &dyn MigrationMetadata;

    /// Get the name of the current migration
    ///
    /// The provided name is used by migration harness
    /// to get the version of a migration and to
    /// as something to that is displayed and allows
    /// user to identify a specific migration
    fn name(&self) -> &dyn MigrationName;
}

/// This trait is designed to customize the behaviour
/// of the default migration harness of diesel
///
/// Any new customization option will be added
/// as new function here. Each new function
/// will have a default implementation
/// returning the old a value corresponding
/// to the old uncustomized behaviour
pub trait MigrationMetadata {
    /// Whether the current migration is executed in a transaction or not
    ///
    /// By default each migration is executed in a own transaction, but
    /// certain operations (like creating an index on an existing column)
    /// requires running the migration without transaction.
    ///
    /// By default this function returns true
    fn run_in_transaction(&self) -> bool {
        true
    }
}

/// A migration source is an entity that can be used
/// to receive a number of migrations from.
pub trait MigrationSource<DB: Backend> {
    /// Get a list of migrations associated with this
    /// migration soucre.
    fn migrations(&self) -> Result<Vec<Box<dyn Migration<DB>>>>;
}

impl<'a, DB: Backend> Migration<DB> for Box<dyn Migration<DB> + 'a> {
    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
        (&**self).run(conn)
    }

    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
        (&**self).revert(conn)
    }

    fn metadata(&self) -> &dyn MigrationMetadata {
        (&**self).metadata()
    }

    fn name(&self) -> &dyn MigrationName {
        (&**self).name()
    }
}

impl<'a, DB: Backend> Migration<DB> for &'a dyn Migration<DB> {
    fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
        (&**self).run(conn)
    }

    fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
        (&**self).revert(conn)
    }

    fn metadata(&self) -> &dyn MigrationMetadata {
        (&**self).metadata()
    }

    fn name(&self) -> &dyn MigrationName {
        (&**self).name()
    }
}

/// Create table statement for the `__diesel_schema_migrations` used
/// used by the postgresql, sqlite and mysql backend
pub const CREATE_MIGRATIONS_TABLE: &str = include_str!("setup_migration_table.sql");

/// A trait indicating that a connection could be used to manage migrations
///
/// Only custom backend implementations need to think about this trait
pub trait MigrationConnection: Connection {
    /// Setup the following table:
    ///
    /// ```rust
    /// diesel::table! {
    ///      __diesel_schema_migrations(version) {
    ///          version -> Text,
    ///          /// defaults to `CURRENT_TIMESTAMP`
    ///          run_on -> Timestamp,
    ///      }
    /// }
    /// ```
    fn setup(&mut self) -> QueryResult<usize>;
}

#[cfg(feature = "postgres")]
impl MigrationConnection for crate::pg::PgConnection {
    fn setup(&mut self) -> QueryResult<usize> {
        use crate::RunQueryDsl;
        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
    }
}

#[cfg(feature = "mysql")]
impl MigrationConnection for crate::mysql::MysqlConnection {
    fn setup(&mut self) -> QueryResult<usize> {
        use crate::RunQueryDsl;
        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
    }
}

#[cfg(feature = "sqlite")]
impl MigrationConnection for crate::sqlite::SqliteConnection {
    fn setup(&mut self) -> QueryResult<usize> {
        use crate::RunQueryDsl;
        crate::sql_query(CREATE_MIGRATIONS_TABLE).execute(self)
    }
}