diesel/migration/mod.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 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)]
#[diesel(sql_type = Text)]
pub struct MigrationVersion<'a>(Cow<'a, str>);
impl MigrationVersion<'_> {
/// 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<DB> FromSql<Text, DB> for MigrationVersion<'_>
where
String: FromSql<Text, DB>,
DB: Backend,
{
fn from_sql(bytes: DB::RawValue<'_>) -> 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<'b>(
&'b self,
out: &mut crate::serialize::Output<'b, '_, DB>,
) -> crate::serialize::Result {
self.0.to_sql(out)
}
}
impl From<String> for MigrationVersion<'_> {
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 Display for MigrationVersion<'_> {
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 source.
fn migrations(&self) -> Result<Vec<Box<dyn Migration<DB>>>>;
}
impl<DB: Backend> Migration<DB> for Box<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()
}
}
impl<DB: Backend> Migration<DB> for &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)
}
}