Skip to main content

saola_user_facing_errors/query_engine/
mod.rs

1pub mod validation;
2
3use serde::Serialize;
4use std::fmt;
5use user_facing_error_macros::*;
6
7#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
8#[serde(untagged)]
9pub enum DatabaseConstraint {
10    Fields(Vec<String>),
11    Index(String),
12    ForeignKey,
13    CannotParse,
14}
15
16impl fmt::Display for DatabaseConstraint {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        match self {
19            Self::Fields(fields) => {
20                let quoted_fields: Vec<String> = fields.iter().map(|f| format!("`{f}`")).collect();
21                write!(f, "fields: ({})", quoted_fields.join(","))
22            }
23            Self::Index(index) => write!(f, "constraint: `{index}`"),
24            Self::ForeignKey => write!(f, "foreign key"),
25            Self::CannotParse => write!(f, "(not available)"),
26        }
27    }
28}
29
30impl From<Vec<String>> for DatabaseConstraint {
31    fn from(fields: Vec<String>) -> Self {
32        Self::Fields(fields)
33    }
34}
35
36#[derive(Debug, UserFacingError, Serialize)]
37#[user_facing(
38    code = "P2000",
39    message = "The provided value for the column is too long for the column's type. Column: {column_name}"
40)]
41pub struct InputValueTooLong {
42    pub column_name: String,
43}
44
45#[derive(Debug, UserFacingError, Serialize)]
46#[user_facing(
47    code = "P2001",
48    message = "The record searched for in the where condition (`{model_name}.{argument_name} = {argument_value}`) does not exist"
49)]
50pub struct RecordNotFound {
51    /// Model name from Prisma schema
52    pub model_name: String,
53
54    /// Argument name from a supported query on a Prisma schema model
55    pub argument_name: String,
56
57    /// Concrete value provided for an argument on a query. Should be peeked/truncated if too long
58    /// to display in the error message
59    pub argument_value: String,
60}
61
62#[derive(Debug, UserFacingError, Serialize)]
63#[user_facing(code = "P2002", message = "Unique constraint failed on the {constraint}")]
64pub struct UniqueKeyViolation {
65    /// Field name from one model from Prisma schema
66    #[serde(rename = "target")]
67    pub constraint: DatabaseConstraint,
68}
69
70#[derive(Debug, UserFacingError, Serialize)]
71#[user_facing(code = "P2003", message = "Foreign key constraint violated on the {constraint}")]
72pub struct ForeignKeyViolation {
73    pub constraint: DatabaseConstraint,
74}
75
76#[derive(Debug, UserFacingError, Serialize)]
77#[user_facing(code = "P2004", message = "A constraint failed on the database: `{database_error}`")]
78pub struct ConstraintViolation {
79    /// Database error returned by the underlying data source
80    pub database_error: String,
81}
82
83#[derive(Debug, UserFacingError, Serialize)]
84#[user_facing(
85    code = "P2005",
86    message = "The value `{field_value}` stored in the database for the field `{field_name}` is invalid for the field's type"
87)]
88pub struct StoredValueIsInvalid {
89    /// Concrete value provided for a field on a model in Prisma schema. Should be peeked/truncated if too long to display in the error message
90    pub field_value: String,
91
92    /// Field name from one model from Prisma schema
93    pub field_name: String,
94}
95
96#[derive(Debug, UserFacingError, Serialize)]
97#[user_facing(
98    code = "P2006",
99    message = "The provided value `{field_value}` for `{model_name}` field `{field_name}` is not valid"
100)]
101pub struct TypeMismatch {
102    /// Concrete value provided for a field on a model in Prisma schema. Should be peeked/truncated if too long to display in the error message
103    pub field_value: String,
104
105    /// Model name from Prisma schema
106    pub model_name: String,
107
108    /// Field name from one model from Prisma schema
109    pub field_name: String,
110}
111
112#[derive(Debug, UserFacingError, Serialize)]
113#[user_facing(code = "P2007", message = "Data validation error `{database_error}`")]
114pub struct TypeMismatchInvalidCustomType {
115    /// Database error returned by the underlying data source
116    pub database_error: String,
117}
118
119#[derive(Debug, UserFacingError, Serialize)]
120#[user_facing(
121    code = "P2008",
122    message = "Failed to parse the query `{query_parsing_error}` at `{query_position}`"
123)]
124pub struct QueryParsingFailed {
125    /// Error(s) encountered when trying to parse a query in the query engine
126    pub query_parsing_error: String,
127
128    /// Location of the incorrect parsing, validation in a query. Represented by tuple or object with (line, character)
129    pub query_position: String,
130}
131
132#[derive(Debug, UserFacingError, Serialize)]
133#[user_facing(code = "P2010", message = "Raw query failed. Code: `{code}`. Message: `{message}`")]
134pub struct RawQueryFailed {
135    pub code: String,
136    pub message: String,
137}
138
139#[derive(Debug, UserFacingError, Serialize)]
140#[user_facing(code = "P2011", message = "Null constraint violation on the {constraint}")]
141pub struct NullConstraintViolation {
142    pub constraint: DatabaseConstraint,
143}
144
145#[derive(Debug, UserFacingError, Serialize)]
146#[user_facing(
147    code = "P2013",
148    message = "Missing the required argument `{argument_name}` for field `{field_name}` on `{object_name}`."
149)]
150pub struct MissingRequiredArgument {
151    pub argument_name: String,
152    pub field_name: String,
153    pub object_name: String,
154}
155
156#[derive(Debug, UserFacingError, Serialize)]
157#[user_facing(
158    code = "P2014",
159    message = "The change you are trying to make would violate the required relation '{relation_name}' between the `{model_a_name}` and `{model_b_name}` models."
160)]
161pub struct RelationViolation {
162    pub relation_name: String,
163    pub model_a_name: String,
164    pub model_b_name: String,
165}
166
167#[derive(Debug, UserFacingError, Serialize)]
168#[user_facing(code = "P2015", message = "A related record could not be found. {details}")]
169pub struct RelatedRecordNotFound {
170    pub details: String,
171}
172
173#[derive(Debug, UserFacingError, Serialize)]
174#[user_facing(code = "P2016", message = "Query interpretation error. {details}")]
175pub struct InterpretationError {
176    pub details: String,
177}
178
179#[derive(Debug, UserFacingError, Serialize)]
180#[user_facing(
181    code = "P2017",
182    message = "The records for relation `{relation_name}` between the `{parent_name}` and `{child_name}` models are not connected."
183)]
184pub struct RecordsNotConnected {
185    pub relation_name: String,
186    pub parent_name: String,
187    pub child_name: String,
188}
189
190#[derive(Debug, UserFacingError, Serialize)]
191#[user_facing(code = "P2018", message = "The required connected records were not found. {details}")]
192pub struct ConnectedRecordsNotFound {
193    pub details: String,
194}
195
196#[derive(Debug, UserFacingError, Serialize)]
197#[user_facing(code = "P2019", message = "Input error. {details}")]
198pub struct InputError {
199    pub details: String,
200}
201
202#[derive(Debug, UserFacingError, Serialize)]
203#[user_facing(code = "P2020", message = "Value out of range for the type: {details}")]
204pub struct ValueOutOfRange {
205    pub details: String,
206}
207
208#[derive(Debug, UserFacingError, Serialize)]
209#[user_facing(
210    code = "P2021",
211    message = "The table `{table}` does not exist in the current database."
212)]
213pub struct TableDoesNotExist {
214    pub table: String,
215}
216
217#[derive(Debug, UserFacingError, Serialize)]
218#[user_facing(
219    code = "P2022",
220    message = "The column `{column}` does not exist in the current database."
221)]
222pub struct ColumnDoesNotExist {
223    pub column: String,
224}
225
226#[derive(Debug, UserFacingError, Serialize)]
227#[user_facing(code = "P2023", message = "Inconsistent column data: {message}")]
228pub struct InconsistentColumnData {
229    pub message: String,
230}
231
232#[derive(Debug, UserFacingError, Serialize)]
233#[user_facing(
234    code = "P2024",
235    message = "Timed out fetching a new connection from the connection pool. More info: http://pris.ly/d/connection-pool (Current connection pool timeout: {timeout}, connection limit: {connection_limit})"
236)]
237pub struct PoolTimeout {
238    pub connection_limit: u64,
239    pub timeout: u64,
240}
241
242#[derive(Debug, UserFacingError, Serialize)]
243#[user_facing(
244    code = "P2025",
245    message = "An operation failed because it depends on one or more records that were required but not found. {cause}"
246)]
247pub struct RecordRequiredButNotFound {
248    pub cause: String,
249}
250
251#[derive(Debug, UserFacingError, Serialize)]
252#[user_facing(
253    code = "P2026",
254    message = "The current database provider doesn't support a feature that the query used: {feature}"
255)]
256pub struct UnsupportedFeature {
257    pub feature: String,
258}
259
260#[derive(Debug, UserFacingError, Serialize)]
261#[user_facing(
262    code = "P2027",
263    message = "Multiple errors occurred on the database during query execution: {errors}"
264)]
265pub struct MultiError {
266    pub errors: String, // Might want to change it to collection of user facing errors.
267}
268
269#[derive(Debug, UserFacingError, Serialize)]
270#[user_facing(code = "P2028", message = "Transaction API error: {error}")]
271pub struct InteractiveTransactionError {
272    pub error: String,
273}
274
275#[derive(Debug, UserFacingError, Serialize)]
276#[user_facing(code = "P2029", message = "Query parameter limit exceeded error: {message}.")]
277pub struct QueryParameterLimitExceeded {
278    pub message: String,
279}
280
281#[derive(Debug, UserFacingError, Serialize)]
282#[user_facing(
283    code = "P2030",
284    message = "Cannot find a fulltext index to use for the native search, try adding a @@fulltext([Fields...]) to your schema"
285)]
286pub struct MissingNativeFullTextSearchIndex {}
287
288#[derive(Debug, UserFacingError, Serialize)]
289#[user_facing(
290    code = "P2031",
291    message = "Prisma needs to perform transactions, which requires your MongoDB server to be run as a replica set. https://pris.ly/d/mongodb-replica-set"
292)]
293pub struct MongoReplicaSetRequired {}
294
295#[derive(Debug, UserFacingError, Serialize)]
296#[user_facing(
297    code = "P2032",
298    message = "Error converting field \"{field}\" of expected non-nullable type \"{expected_type}\", found incompatible value of \"{found}\"."
299)]
300pub struct MissingFieldsInModel {
301    pub field: String,
302    pub expected_type: String,
303    pub found: String,
304}
305
306#[derive(Debug, UserFacingError, Serialize)]
307#[user_facing(code = "P2033", message = "{details}")]
308pub struct ValueFitError {
309    pub details: String,
310}
311
312#[derive(Debug, UserFacingError, Serialize)]
313#[user_facing(
314    code = "P2034",
315    message = "Transaction failed due to a write conflict or a deadlock. Please retry your transaction"
316)]
317pub struct TransactionWriteConflict {}
318
319#[derive(Debug, UserFacingError, Serialize)]
320#[user_facing(code = "P2035", message = "Assertion violation on the database: `{database_error}`")]
321pub struct DatabaseAssertionViolation {
322    /// Database error returned by the underlying connector driver.
323    pub database_error: String,
324}
325
326#[derive(Debug, UserFacingError, Serialize)]
327#[user_facing(code = "P2036", message = "Error in external connector (id {id})")]
328pub struct ExternalError {
329    /// id of the error in external system, which would allow to retrieve it later
330    pub id: i32,
331}
332
333#[derive(Debug, UserFacingError, Serialize)]
334#[user_facing(code = "P2037", message = "Too many database connections opened: {message}")]
335pub struct TooManyConnections {
336    pub message: String,
337}