Skip to main content

saola_user_facing_errors/
schema_engine.rs

1use serde::Serialize;
2use user_facing_error_macros::*;
3
4/// [spec](https://github.com/prisma/specs/tree/master/errors#p3000-database-creation-failed)
5#[derive(Debug, UserFacingError, Serialize)]
6#[user_facing(code = "P3000", message = "Failed to create database: {database_error}")]
7pub struct DatabaseCreationFailed {
8    pub database_error: String,
9}
10
11/// [spec](https://github.com/prisma/specs/tree/master/errors#p3001-destructive-migration-detected)
12/// No longer used.
13#[derive(Debug, UserFacingError, Serialize)]
14#[user_facing(
15    code = "P3001",
16    message = "Migration possible with destructive changes and possible data loss: {destructive_details}"
17)]
18#[allow(dead_code)]
19pub struct DestructiveMigrationDetected {
20    pub destructive_details: String,
21}
22
23/// No longer used.
24#[derive(Debug, UserFacingError, Serialize)]
25#[user_facing(
26    code = "P3002",
27    message = "The attempted migration was rolled back: {database_error}"
28)]
29#[allow(dead_code)]
30struct MigrationRollback {
31    pub database_error: String,
32}
33
34/// No longer used.
35#[derive(Debug, SimpleUserFacingError)]
36#[user_facing(
37    code = "P3003",
38    message = "The format of migrations changed, the saved migrations are no longer valid. To solve this problem, please follow the steps at: https://pris.ly/d/migrate"
39)]
40#[allow(dead_code)]
41pub struct DatabaseMigrationFormatChanged;
42
43#[derive(Debug, UserFacingError, Serialize)]
44#[user_facing(
45    code = "P3004",
46    message = "The `{database_name}` database is a system database, it should not be altered with prisma migrate. Please connect to another database."
47)]
48pub struct MigrateSystemDatabase {
49    pub database_name: String,
50}
51
52#[derive(Debug, SimpleUserFacingError)]
53#[user_facing(
54    code = "P3005",
55    message = "The database schema is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline"
56)]
57pub struct DatabaseSchemaNotEmpty;
58
59#[derive(Debug, Serialize)]
60pub struct MigrationDoesNotApplyCleanly {
61    pub migration_name: String,
62    pub inner_error: crate::Error,
63}
64
65impl crate::UserFacingError for MigrationDoesNotApplyCleanly {
66    const ERROR_CODE: &'static str = "P3006";
67
68    fn message(&self) -> String {
69        let error_code = match &self.inner_error.inner {
70            crate::ErrorType::Known(crate::KnownError {
71                message: _,
72                meta: _,
73                error_code,
74            }) => format!("Error code: {}\n", &error_code),
75            crate::ErrorType::Unknown(_) => String::new(),
76        };
77
78        format!(
79            "Migration `{migration_name}` failed to apply cleanly to the shadow database. \n{error_code}Error:\n{inner_error}",
80            migration_name = self.migration_name,
81            inner_error = self.inner_error.message(),
82            error_code = error_code
83        )
84    }
85}
86
87#[derive(Debug, Serialize)]
88pub struct PreviewFeaturesBlocked {
89    pub features: Vec<String>,
90}
91
92impl crate::UserFacingError for PreviewFeaturesBlocked {
93    const ERROR_CODE: &'static str = "P3007";
94
95    fn message(&self) -> String {
96        let blocked: Vec<_> = self.features.iter().map(|s| format!("`{s}`")).collect();
97
98        format!(
99            "Some of the requested preview features are not yet allowed in schema engine. Please remove them from your data model before using migrations. (blocked: {list_of_blocked_features})",
100            list_of_blocked_features = blocked.join(", "),
101        )
102    }
103}
104
105#[derive(Debug, Serialize, UserFacingError)]
106#[user_facing(
107    code = "P3008",
108    message = "The migration `{migration_name}` is already recorded as applied in the database."
109)]
110pub struct MigrationAlreadyApplied {
111    /// The name of the migration.
112    pub migration_name: String,
113}
114
115#[derive(Debug, Serialize, UserFacingError)]
116#[user_facing(
117    code = "P3009",
118    message = "migrate found failed migrations in the target database, new migrations will not be applied. Read more about how to resolve migration issues in a production database: https://pris.ly/d/migrate-resolve\n{details}"
119)]
120pub struct FoundFailedMigrations {
121    /// The details about each failed migration.
122    pub details: String,
123}
124
125#[derive(Debug, SimpleUserFacingError)]
126#[user_facing(
127    code = "P3010",
128    message = "The name of the migration is too long. It must not be longer than 200 characters (bytes)."
129)]
130pub struct MigrationNameTooLong;
131
132#[derive(Debug, Serialize, UserFacingError)]
133#[user_facing(
134    code = "P3011",
135    message = "Migration `{migration_name}` cannot be rolled back because it was never applied to the database. Hint: did you pass in the whole migration name? (example: \"20201207184859_initial_migration\")"
136)]
137pub struct CannotRollBackUnappliedMigration {
138    /// The name of the migration.
139    pub migration_name: String,
140}
141
142#[derive(Debug, Serialize, UserFacingError)]
143#[user_facing(
144    code = "P3012",
145    message = "Migration `{migration_name}` cannot be rolled back because it is not in a failed state."
146)]
147pub struct CannotRollBackSucceededMigration {
148    /// The name of the migration.
149    pub migration_name: String,
150}
151
152#[derive(Debug, SimpleUserFacingError)]
153#[user_facing(
154    code = "P3013",
155    message = "Datasource provider arrays are no longer supported in migrate. Please change your datasource to use a single provider. Read more at https://pris.ly/multi-provider-deprecation"
156)]
157pub struct DeprecatedProviderArray;
158
159#[derive(Debug, Serialize)]
160pub struct ShadowDbCreationError {
161    pub inner_error: crate::Error,
162}
163
164impl crate::UserFacingError for ShadowDbCreationError {
165    const ERROR_CODE: &'static str = "P3014";
166
167    fn message(&self) -> String {
168        let error_code = match &self.inner_error.inner {
169            crate::ErrorType::Known(crate::KnownError {
170                message: _,
171                meta: _,
172                error_code,
173            }) => format!("Error code: {}\n", &error_code),
174            crate::ErrorType::Unknown(_) => String::new(),
175        };
176
177        format!(
178            "Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at https://pris.ly/d/migrate-shadow\n\nOriginal error: {error_code}\n{inner_error}",
179            inner_error = self.inner_error.message(),
180            error_code = error_code
181        )
182    }
183}
184
185#[derive(Debug, Serialize, UserFacingError)]
186#[user_facing(
187    code = "P3015",
188    message = "Could not find the migration file at {migration_file_path}. Please delete the directory or restore the migration file."
189)]
190pub struct MigrationFileNotFound {
191    pub migration_file_path: String,
192}
193
194#[derive(Debug, Serialize)]
195pub struct SoftResetFailed {
196    pub inner_error: crate::Error,
197}
198
199impl crate::UserFacingError for SoftResetFailed {
200    const ERROR_CODE: &'static str = "P3016";
201
202    fn message(&self) -> String {
203        let error_code = match &self.inner_error.inner {
204            crate::ErrorType::Known(crate::KnownError {
205                message: _,
206                meta: _,
207                error_code,
208            }) => format!("Error code: {}\n", &error_code),
209            crate::ErrorType::Unknown(_) => String::new(),
210        };
211
212        format!(
213            "The fallback method for database resets failed, meaning Migrate could not clean up the database entirely. Original error: {error_code}\n{inner_error}",
214            inner_error = self.inner_error.message(),
215            error_code = error_code
216        )
217    }
218}
219
220#[derive(Debug, Serialize, UserFacingError)]
221#[user_facing(
222    code = "P3017",
223    message = "The migration {migration_name} could not be found. Please make sure that the migration exists, and that you included the whole name of the directory. (example: \"20201207184859_initial_migration\")"
224)]
225pub struct MigrationToMarkAppliedNotFound {
226    /// The migration name that was provided, and not found.
227    pub migration_name: String,
228}
229
230#[derive(Debug, Serialize, UserFacingError)]
231#[user_facing(
232    code = "P3018",
233    message = "A migration failed to apply. New migrations cannot be applied before the error is recovered from. Read more about how to resolve migration issues in a production database: https://pris.ly/d/migrate-resolve\n\nMigration name: {migration_name}\n\nDatabase error code: {database_error_code}\n\nDatabase error:\n{database_error}
234"
235)]
236pub struct ApplyMigrationError {
237    pub migration_name: String,
238    pub database_error_code: String,
239    pub database_error: String,
240}
241
242#[derive(Debug, Serialize)]
243pub struct ProviderSwitchedError {
244    /// The provider specified in the schema.
245    pub provider: String,
246    /// The provider from migrate.lock
247    pub expected_provider: String,
248}
249
250impl crate::UserFacingError for ProviderSwitchedError {
251    const ERROR_CODE: &'static str = "P3019";
252
253    fn message(&self) -> String {
254        let provider = &self.provider;
255        let expected_provider = &self.expected_provider;
256
257        match (provider.as_str(), expected_provider.as_str()) {
258            ("cockroachdb", "postgresql") => format!(
259                "The datasource provider `{provider}` specified in your schema does not match the one specified in the migration_lock.toml, `{expected_provider}`. Check out the following documentation for how to resolve this: https://pris.ly/d/cockroachdb-postgresql-provider"
260            ),
261            _ => format!(
262                "The datasource provider `{provider}` specified in your schema does not match the one specified in the migration_lock.toml, `{expected_provider}`. Please remove your current migration directory and start a new migration history with prisma migrate dev. Read more: https://pris.ly/d/migrate-provider-switch"
263            ),
264        }
265    }
266}
267
268#[derive(Debug, SimpleUserFacingError)]
269#[user_facing(
270    code = "P3020",
271    message = "The automatic creation of shadow databases is disabled on Azure SQL. Please set up a shadow database using the `shadowDatabaseUrl` datasource attribute.\nRead the docs page for more details: https://pris.ly/d/migrate-shadow"
272)]
273pub struct AzureMssqlShadowDb;
274
275#[derive(Debug, SimpleUserFacingError)]
276#[user_facing(
277    code = "P3021",
278    message = "Foreign keys cannot be created on this database. Learn more how to handle this: https://pris.ly/d/migrate-no-foreign-keys"
279)]
280pub struct ForeignKeyCreationNotAllowed;
281
282#[derive(Debug, SimpleUserFacingError)]
283#[user_facing(
284    code = "P3022",
285    message = "Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database. Please read more here about how to handle this: https://pris.ly/d/migrate-no-direct-ddl"
286)]
287pub struct DirectDdlNotAllowed;
288
289#[derive(Debug, SimpleUserFacingError)]
290#[user_facing(
291    code = "P3023",
292    message = "For the current database, `externalTables` & `externalEnums` in your prisma config must contain only fully qualified identifiers (e.g. `schema_name.table_name`)."
293)]
294pub struct MissingNamespaceInExternalTables;
295
296#[derive(Debug, SimpleUserFacingError)]
297#[user_facing(
298    code = "P3024",
299    message = "For the current database, `externalTables` & `externalEnums` in your prisma config must contain only simple identifiers without a schema name."
300)]
301pub struct UnexpectedNamespaceInExternalTables;
302
303#[derive(Debug, SimpleUserFacingError)]
304#[user_facing(code = "P4001", message = "The introspected database was empty.")]
305pub struct IntrospectionResultEmpty;
306
307#[derive(Debug, UserFacingError, Serialize)]
308#[user_facing(
309    code = "P4002",
310    message = "The schema of the introspected database was inconsistent: {explanation}"
311)]
312pub struct DatabaseSchemaInconsistent {
313    /// The schema was inconsistent and therefore introspection failed.
314    pub explanation: String,
315}
316
317#[cfg(test)]
318mod tests {
319    use super::*;
320    use crate::UserFacingError;
321
322    #[test]
323    fn test_user_facing_error_impl_for_database_creation_failed() {
324        assert_eq!(DatabaseCreationFailed::ERROR_CODE, "P3000");
325
326        let error = DatabaseCreationFailed {
327            database_error: "oops".to_string(),
328        };
329
330        assert_eq!(error.message(), "Failed to create database: oops")
331    }
332}