sqlx_core/config/migrate.rs
1use std::collections::BTreeSet;
2
3/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.
4///
5/// ### Note
6/// A manually constructed [`Migrator`][crate::migrate::Migrator] will not be aware of these
7/// configuration options. We recommend using `sqlx::migrate!()` instead.
8///
9/// ### Warning: Potential Data Loss or Corruption!
10/// Many of these options, if changed after migrations are set up,
11/// can result in data loss or corruption of a production database
12/// if the proper precautions are not taken.
13///
14/// Be sure you know what you are doing and that you read all relevant documentation _thoroughly_.
15#[derive(Debug, Default)]
16#[cfg_attr(
17 feature = "sqlx-toml",
18 derive(serde::Deserialize),
19 serde(default, rename_all = "kebab-case", deny_unknown_fields)
20)]
21pub struct Config {
22 /// Specify the names of schemas to create if they don't already exist.
23 ///
24 /// This is done before checking the existence of the migrations table
25 /// (`_sqlx_migrations` or overridden `table_name` below) so that it may be placed in
26 /// one of these schemas.
27 ///
28 /// ### Example
29 /// `sqlx.toml`:
30 /// ```toml
31 /// [migrate]
32 /// create-schemas = ["foo"]
33 /// ```
34 pub create_schemas: BTreeSet<Box<str>>,
35
36 /// Override the name of the table used to track executed migrations.
37 ///
38 /// May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.
39 ///
40 /// Potentially useful for multi-tenant databases.
41 ///
42 /// ### Warning: Potential Data Loss or Corruption!
43 /// Changing this option for a production database will likely result in data loss or corruption
44 /// as the migration machinery will no longer be aware of what migrations have been applied
45 /// and will attempt to re-run them.
46 ///
47 /// You should create the new table as a copy of the existing migrations table (with contents!),
48 /// and be sure all instances of your application have been migrated to the new
49 /// table before deleting the old one.
50 ///
51 /// ### Example
52 /// `sqlx.toml`:
53 /// ```toml
54 /// [migrate]
55 /// # Put `_sqlx_migrations` in schema `foo`
56 /// table-name = "foo._sqlx_migrations"
57 /// ```
58 pub table_name: Option<Box<str>>,
59
60 /// Override the directory used for migrations files.
61 ///
62 /// Relative to the crate root for `sqlx::migrate!()`, or the current directory for `sqlx-cli`.
63 pub migrations_dir: Option<Box<str>>,
64
65 /// Specify characters that should be ignored when hashing migrations.
66 ///
67 /// Any characters contained in the given array will be dropped when a migration is hashed.
68 ///
69 /// ### Warning: May Change Hashes for Existing Migrations
70 /// Changing the characters considered in hashing migrations will likely
71 /// change the output of the hash.
72 ///
73 /// This may require manual rectification for deployed databases.
74 ///
75 /// ### Example: Ignore Carriage Return (`<CR>` | `\r`)
76 /// Line ending differences between platforms can result in migrations having non-repeatable
77 /// hashes. The most common culprit is the carriage return (`<CR>` | `\r`), which Windows
78 /// uses in its line endings alongside line feed (`<LF>` | `\n`), often written `CRLF` or `\r\n`,
79 /// whereas Linux and macOS use only line feeds.
80 ///
81 /// `sqlx.toml`:
82 /// ```toml
83 /// [migrate]
84 /// ignored-chars = ["\r"]
85 /// ```
86 ///
87 /// For projects using Git, this can also be addressed using [`.gitattributes`]:
88 ///
89 /// ```text
90 /// # Force newlines in migrations to be line feeds on all platforms
91 /// migrations/*.sql text eol=lf
92 /// ```
93 ///
94 /// This may require resetting or re-checking out the migrations files to take effect.
95 ///
96 /// [`.gitattributes`]: https://git-scm.com/docs/gitattributes
97 ///
98 /// ### Example: Ignore all Whitespace Characters
99 /// To make your migrations amenable to reformatting, you may wish to tell SQLx to ignore
100 /// _all_ whitespace characters in migrations.
101 ///
102 /// ##### Warning: Beware Syntactically Significant Whitespace!
103 /// If your migrations use string literals or quoted identifiers which contain whitespace,
104 /// this configuration will cause the migration machinery to ignore some changes to these.
105 /// This may result in a mismatch between the development and production versions of
106 /// your database.
107 ///
108 /// `sqlx.toml`:
109 /// ```toml
110 /// [migrate]
111 /// # Ignore common whitespace characters when hashing
112 /// ignored-chars = [" ", "\t", "\r", "\n"] # Space, tab, CR, LF
113 /// ```
114 // Likely lower overhead for small sets than `HashSet`.
115 pub ignored_chars: BTreeSet<char>,
116
117 /// Specify default options for new migrations created with `sqlx migrate add`.
118 pub defaults: MigrationDefaults,
119}
120
121#[derive(Debug, Default)]
122#[cfg_attr(
123 feature = "sqlx-toml",
124 derive(serde::Deserialize),
125 serde(default, rename_all = "kebab-case")
126)]
127pub struct MigrationDefaults {
128 /// Specify the default type of migration that `sqlx migrate add` should create by default.
129 ///
130 /// ### Example: Use Reversible Migrations by Default
131 /// `sqlx.toml`:
132 /// ```toml
133 /// [migrate.defaults]
134 /// migration-type = "reversible"
135 /// ```
136 pub migration_type: DefaultMigrationType,
137
138 /// Specify the default scheme that `sqlx migrate add` should use for version integers.
139 ///
140 /// ### Example: Use Sequential Versioning by Default
141 /// `sqlx.toml`:
142 /// ```toml
143 /// [migrate.defaults]
144 /// migration-versioning = "sequential"
145 /// ```
146 pub migration_versioning: DefaultVersioning,
147}
148
149/// The default type of migration that `sqlx migrate add` should create by default.
150#[derive(Debug, Default, PartialEq, Eq)]
151#[cfg_attr(
152 feature = "sqlx-toml",
153 derive(serde::Deserialize),
154 serde(rename_all = "snake_case")
155)]
156pub enum DefaultMigrationType {
157 /// Create the same migration type as that of the latest existing migration,
158 /// or `Simple` otherwise.
159 #[default]
160 Inferred,
161
162 /// Create non-reversible migrations (`<VERSION>_<DESCRIPTION>.sql`) by default.
163 Simple,
164
165 /// Create reversible migrations (`<VERSION>_<DESCRIPTION>.up.sql` and `[...].down.sql`) by default.
166 Reversible,
167}
168
169/// The default scheme that `sqlx migrate add` should use for version integers.
170#[derive(Debug, Default, PartialEq, Eq)]
171#[cfg_attr(
172 feature = "sqlx-toml",
173 derive(serde::Deserialize),
174 serde(rename_all = "snake_case")
175)]
176pub enum DefaultVersioning {
177 /// Infer the versioning scheme from existing migrations:
178 ///
179 /// * If the versions of the last two migrations differ by `1`, infer `Sequential`.
180 /// * If only one migration exists and has version `1`, infer `Sequential`.
181 /// * Otherwise, infer `Timestamp`.
182 #[default]
183 Inferred,
184
185 /// Use UTC timestamps for migration versions.
186 ///
187 /// This is the recommended versioning format as it's less likely to collide when multiple
188 /// developers are creating migrations on different branches.
189 ///
190 /// The exact timestamp format is unspecified.
191 Timestamp,
192
193 /// Use sequential integers for migration versions.
194 Sequential,
195}
196
197#[cfg(feature = "migrate")]
198impl Config {
199 pub fn migrations_dir(&self) -> &str {
200 self.migrations_dir.as_deref().unwrap_or("migrations")
201 }
202
203 pub fn table_name(&self) -> &str {
204 self.table_name.as_deref().unwrap_or("_sqlx_migrations")
205 }
206
207 pub fn to_resolve_config(&self) -> crate::migrate::ResolveConfig {
208 let mut config = crate::migrate::ResolveConfig::new();
209 config.ignore_chars(self.ignored_chars.iter().copied());
210 config
211 }
212}