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
//! Powerful schema migration builder, that let's you write your SQL
//! migrations in Rust.
//!
//! `barrel` makes writing migrations for different databases as easy
//! as possible.  It provides you with a common API over SQL, with
//! certain features only provided for database specific
//! implementations.  This way you can focus on your Rust code, and
//! stop worrying about SQL.
//!
//! `barrel` has three primary models: the
//! [Migration](migration/struct.Migration.html) which represents all
//! changes and changes made on a database level, the
//! [Table](table/struct.Table.html) and the
//! [Type](types/struct.Type.html).
//!
//! When creating or altering tables a lambda which exposes `&mut
//! Table` is provided for initialisation. Adding columns is then as
//! easy as calling `add_column(...)` on the table.
//!
//! Each column is statically typed and some types require some
//! metadata in order to compile the migration (for example
//! `Varchar(255)`). You can also provide default types and override
//! encodings, nullability or uniqueness of columns.  Some checks are
//! performed at compile-time however most things (including) correct
//! default values) are only checked at runtime.
//!
//! **Note** Since version `0.3.0` it is required to provide a
//! database backend in order to compile `barrel`.
//!
//! The following code is a simple example of how to get going with
//! `barrel`
//!
//! ```rust
//! use barrel::{types, Migration};
//!
//! fn main() {
//!     let mut m = Migration::new();
//!     m.create_table("users", |t| {
//!         t.add_column("name", types::varchar(255));
//!         t.add_column("age", types::integer());
//!         t.add_column("owns_plushy_sharks", types::boolean());
//!     });
//! }
//! ```
//!
//! `barrel` also supports more advanced types, such as `foreign(...)`
//! and `array(...)` however currently doesn't support nested Array
//! types on foreign keys (such as `array(array(foreign(...)))`). Each
//! column addition returns a Column object which can then be used to
//! provide further configuration.
//!
//! To generate SQL strings you have two options. If you just want to
//! run the migration yourself simply run `Migration::exec()` where
//! you provide a generic `SqlGenerator` type according to your
//! database backend
//!
//! ```rust
//! # #[cfg(feature = "pg")]
//! # use barrel::backend::Pg;
//! # use barrel::Migration;
//! # let mut m = Migration::new();
//! // Example for pgsql
//! # #[cfg(feature = "pg")]
//! m.make::<Pg>();
//! ```
//!
//! Alternatively, if you're a library developer and you want to more
//! easily embed `barrel` into your library you can simply implement
//! the `DatabaseExecutor` trait for a type of yours that knows how to
//! execute SQL.  Running a migration with `barrel` is then super
//! easy.
//!
//! ```rust
//! use barrel::connectors::SqlRunner;
//! # use barrel::Migration;
//! # #[cfg(feature = "pg")]
//! # use barrel::backend::Pg;
//!
//! struct MyRunner;
//! impl SqlRunner for MyRunner {
//!     fn execute<S: Into<String>>(&mut self, sql: S) {
//!         # let s: String = sql.into();
//!         // ...
//!     }
//! }
//!
//! # let mut m = Migration::new();
//! # let mut executor = MyRunner;
//! # #[cfg(feature = "pg")]
//! m.execute::<Pg, _>(&mut executor);
//! ```
//!
//! In this case `executor` is your provided type which implements the
//! required trait. You can read more about this in the
//! [connectors](connectors/index.html) module docs.
//!
//! If you find database-specific features or documentation lacking,
//! don't hesitate to open an issue/PR about it.

#[cfg(feature = "diesel")]
pub mod integrations;
#[cfg(feature = "diesel")]
pub use integrations::*;

pub mod backend;
pub mod connectors;
pub mod functions;
pub mod migration;
pub mod table;
pub mod types;

pub use backend::SqlVariant;
pub use migration::Migration;
pub use table::{Table, TableMeta};

#[cfg(test)]
mod tests;

use std::rc::Rc;

/// An enum set that represents a single change on a table
#[derive(Clone)]
pub enum TableChange {
    /// Add a column of a name and type
    AddColumn(String, types::Type),

    /// Change an existing column
    ChangeColumn(String, types::Type, Rc<dyn Fn(&mut types::Type)>),

    /// Simply rename a column
    RenameColumn(String, String),

    /// Remove a column
    DropColumn(String),

    /// Add some custom SQL if all else fails
    CustomLine(String),
}

/// An enum set that represents a single change on a database
#[derive(Clone)]
pub enum DatabaseChange {
    /// Create a new table
    CreateTable(Table, Rc<dyn Fn(&mut Table)>),

    /// Create a new table *only* if it doesn't exist yet
    CreateTableIfNotExists(Table, Rc<dyn Fn(&mut Table)>),

    /// Change fields on an existing table
    ChangeTable(Table, Rc<dyn Fn(&mut Table)>),

    /// Rename a table
    RenameTable(String, String),

    /// Drop an existing table
    DropTable(String),

    /// Only drop a table if it exists
    DropTableIfExists(String),

    /// Add some custom SQL if all else fails
    CustomLine(String),
}

/// An enum set that represents operations done with and on indices
#[derive(Clone)]
pub enum IndexChange {
    /// Add a multi-column index
    AddIndex {
        index: String,
        table: String,
        columns: types::Type, // Should always be a `Index` type
    },

    AddPartialIndex {
        index: String,
        table: String,
        columns: types::Type, // Should always be a `Index` type
        conditions: String,
    },

    /// Remove a multi-column index
    RemoveIndex(String, String),
}

/// An enum set that represents operations done with and on constraints
#[derive(Clone)]
pub enum ConstraintChange {
    /// Add a new constraint
    AddConstraint {
        index: String,
        columns: types::Type, // Should always be a `Constraint` type
    },
}

/// An enum set that represents operations done with and on foreign keys
#[derive(Clone)]
pub enum ForeignKeyChange {
    /// Add a foreign key
    AddForeignKey {
        columns: Vec<String>,
        table: String,
        relation_columns: Vec<String>,
    },
}

/// An enum set that represents operations done to the primary key
#[derive(Clone)]
pub enum PrimaryKeyChange {
    /// Adds a primary key to the table
    AddPrimaryKey(Vec<String>),
}