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
//! Module defining migration trait
//!
//! To create own implement migration trait for type
//!
//! ### Example
//!
//! ```rust,no_run
//! use sqlx_migrator::error::Error;
//! use sqlx_migrator::migration::Migration;
//! use sqlx_migrator::operation::Operation;
//!
//! struct ExampleMigration;
//! #[async_trait::async_trait]
//! impl Migration for ExampleMigration {
//!     type Database = sqlx_migrator::sqlx::Sqlite;
//!
//!     fn app(&self) -> &str {
//!         "example"
//!     }
//!
//!     fn name(&self) -> &str {
//!         "first_migration"
//!     }
//!
//!     fn parents(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
//!         vec![]
//!     }
//!
//!     fn operations(&self) -> Vec<Box<dyn Operation<Database = Self::Database>>> {
//!         vec![]
//!     }
//!
//!     fn replaces(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
//!         vec![]
//!     }
//!
//!     fn run_before(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
//!         vec![]
//!     }
//!
//!     fn is_atomic(&self) -> bool {
//!         true
//!     }
//! }
//! ```

use std::hash::Hash;

use crate::operation::Operation;

/// Trait for migration
pub trait Migration: Send + Sync {
    /// Type of database to be used
    type Database: sqlx::Database;

    /// Migration app name. Can be name of folder or library where migration is
    /// located
    fn app(&self) -> &str;

    /// Migration name. Can be file name without extension
    fn name(&self) -> &str;

    /// Parents of migration (migrations that should be applied before this
    /// migration)
    fn parents(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
        vec![]
    }

    /// Operation performed for migration (create, drop, etc.)
    fn operations(&self) -> Vec<Box<dyn Operation<Database = Self::Database>>> {
        vec![]
    }

    /// Replace certain migrations. If any one of listed migration is applied
    /// than migration will not be applied else migration will apply instead of
    /// applying those migration.
    fn replaces(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
        vec![]
    }

    /// Run before certain migration. This can be helpful in condition where
    /// other library migration need to be applied after this migration
    fn run_before(&self) -> Vec<Box<dyn Migration<Database = Self::Database>>> {
        vec![]
    }

    /// Whether migration is atomic or not. By default it is true
    fn is_atomic(&self) -> bool {
        true
    }
}

impl<DB> PartialEq for dyn Migration<Database = DB>
where
    DB: sqlx::Database,
{
    fn eq(&self, other: &Self) -> bool {
        self.app() == other.app() && self.name() == other.name()
    }
}

impl<DB> Eq for dyn Migration<Database = DB> where DB: sqlx::Database {}

impl<DB> Hash for dyn Migration<Database = DB>
where
    DB: sqlx::Database,
{
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.app().hash(state);
        self.name().hash(state);
    }
}

impl<DB> PartialEq<(String, String)> for &Box<dyn Migration<Database = DB>>
where
    DB: sqlx::Database,
{
    fn eq(&self, other: &(String, String)) -> bool {
        self.app() == other.0 && self.name() == other.1
    }
}