bluejay_validator/executable/document/
error.rs

1use crate::value::input_coercion::Error as InputCoercionError;
2use bluejay_core::definition::{
3    FieldDefinition, InputType, OutputType, SchemaDefinition, TypeDefinitionReference,
4};
5use bluejay_core::executable::{ExecutableDocument, OperationDefinition, VariableType};
6use bluejay_core::{OperationType, Value};
7#[cfg(feature = "parser-integration")]
8use bluejay_parser::{
9    ast::executable::ExecutableDocument as ParserExecutableDocument,
10    error::{Annotation, Error as ParserError},
11    HasSpan,
12};
13use std::borrow::Cow;
14
15mod argument_error;
16mod directive_error;
17
18pub use argument_error::ArgumentError;
19pub use directive_error::DirectiveError;
20
21pub enum Error<'a, E: ExecutableDocument, S: SchemaDefinition> {
22    NonUniqueOperationNames {
23        name: &'a str,
24        operations: Vec<&'a E::ExplicitOperationDefinition>,
25    },
26    NotLoneAnonymousOperation {
27        anonymous_operations: Vec<&'a E::OperationDefinition>,
28    },
29    SubscriptionRootNotSingleField {
30        operation: &'a E::OperationDefinition,
31    },
32    FieldDoesNotExistOnType {
33        field: &'a E::Field,
34        r#type: TypeDefinitionReference<'a, S::TypeDefinition>,
35    },
36    OperationTypeNotDefined {
37        operation: &'a E::ExplicitOperationDefinition,
38    },
39    LeafFieldSelectionNotEmpty {
40        selection_set: &'a E::SelectionSet,
41        r#type: &'a S::OutputType,
42    },
43    NonLeafFieldSelectionEmpty {
44        field: &'a E::Field,
45        r#type: &'a S::OutputType,
46    },
47    NonUniqueFragmentDefinitionNames {
48        name: &'a str,
49        fragment_definitions: Vec<&'a E::FragmentDefinition>,
50    },
51    FragmentDefinitionTargetTypeDoesNotExist {
52        fragment_definition: &'a E::FragmentDefinition,
53    },
54    InlineFragmentTargetTypeDoesNotExist {
55        inline_fragment: &'a E::InlineFragment,
56    },
57    FragmentDefinitionTargetTypeNotComposite {
58        fragment_definition: &'a E::FragmentDefinition,
59    },
60    InlineFragmentTargetTypeNotComposite {
61        inline_fragment: &'a E::InlineFragment,
62    },
63    FragmentDefinitionUnused {
64        fragment_definition: &'a E::FragmentDefinition,
65    },
66    FragmentSpreadTargetUndefined {
67        fragment_spread: &'a E::FragmentSpread,
68    },
69    FragmentSpreadCycle {
70        fragment_definition: &'a E::FragmentDefinition,
71        fragment_spread: &'a E::FragmentSpread,
72    },
73    FieldSelectionsDoNotMergeIncompatibleTypes {
74        selection_set: &'a E::SelectionSet,
75        field_a: &'a E::Field,
76        field_definition_a: &'a S::FieldDefinition,
77        field_b: &'a E::Field,
78        field_definition_b: &'a S::FieldDefinition,
79    },
80    FieldSelectionsDoNotMergeDifferingNames {
81        selection_set: &'a E::SelectionSet,
82        field_a: &'a E::Field,
83        field_b: &'a E::Field,
84    },
85    FieldSelectionsDoNotMergeDifferingArguments {
86        selection_set: &'a E::SelectionSet,
87        field_a: &'a E::Field,
88        field_b: &'a E::Field,
89    },
90    FragmentSpreadIsNotPossible {
91        fragment_spread: &'a E::FragmentSpread,
92        parent_type: TypeDefinitionReference<'a, S::TypeDefinition>,
93    },
94    InlineFragmentSpreadIsNotPossible {
95        inline_fragment: &'a E::InlineFragment,
96        parent_type: TypeDefinitionReference<'a, S::TypeDefinition>,
97    },
98    InvalidConstValue(InputCoercionError<'a, true, E::Value<true>>),
99    InvalidVariableValue(InputCoercionError<'a, false, E::Value<false>>),
100    InvalidConstDirective(DirectiveError<'a, true, E, S>),
101    InvalidVariableDirective(DirectiveError<'a, false, E, S>),
102    InvalidConstArgument(ArgumentError<'a, true, E, S>),
103    InvalidVariableArgument(ArgumentError<'a, false, E, S>),
104    NonUniqueVariableDefinitionNames {
105        name: &'a str,
106        variable_definitions: Vec<&'a E::VariableDefinition>,
107    },
108    VariableDefinitionTypeNotInput {
109        variable_definition: &'a E::VariableDefinition,
110    },
111    VariableNotDefined {
112        variable: &'a <E::Value<false> as Value<false>>::Variable,
113        operation_definition: &'a E::OperationDefinition,
114    },
115    VariableDefinitionUnused {
116        variable_definition: &'a E::VariableDefinition,
117    },
118    InvalidVariableUsage {
119        variable: &'a <E::Value<false> as Value<false>>::Variable,
120        variable_type: &'a E::VariableType,
121        location_type: &'a S::InputType,
122    },
123}
124
125#[cfg(feature = "parser-integration")]
126impl<'a, S: SchemaDefinition> From<Error<'a, ParserExecutableDocument<'a>, S>> for ParserError {
127    fn from(value: Error<'a, ParserExecutableDocument<'a>, S>) -> Self {
128        match value {
129            Error::NonUniqueOperationNames { name, operations } => Self::new(
130                format!("Multiple operation definitions named `{name}`"),
131                None,
132                operations
133                    .iter()
134                    .filter_map(|operation| {
135                        operation.name().map(|operation_name| {
136                            Annotation::new(
137                                format!("Operation definition with name `{name}`"),
138                                operation_name.span().clone(),
139                            )
140                        })
141                    })
142                    .collect(),
143            ),
144            Error::NotLoneAnonymousOperation {
145                anonymous_operations,
146            } => Self::new(
147                "Anonymous operation not lone operation in document",
148                None,
149                anonymous_operations
150                    .iter()
151                    .map(|operation| {
152                        Annotation::new(
153                            "Anonymous operation definition",
154                            operation.as_ref().selection_set().span().clone(),
155                        )
156                    })
157                    .collect(),
158            ),
159            Error::SubscriptionRootNotSingleField { operation } => Self::new(
160                "Subscription root is not a single field",
161                Some(Annotation::new(
162                    "Selection set contains multiple fields",
163                    operation.as_ref().selection_set().span().clone(),
164                )),
165                Vec::new(),
166            ),
167            Error::FieldDoesNotExistOnType { field, r#type } => Self::new(
168                format!(
169                    "Field `{}` does not exist on type `{}`",
170                    field.name().as_ref(),
171                    r#type.name()
172                ),
173                Some(Annotation::new(
174                    format!("Field does not exist on type `{}`", r#type.name()),
175                    field.name().span().clone(),
176                )),
177                Vec::new(),
178            ),
179            Error::OperationTypeNotDefined { operation } => Self::new(
180                format!(
181                    "Schema does not define a {} root",
182                    OperationType::from(operation.operation_type()),
183                ),
184                Some(Annotation::new(
185                    format!(
186                        "Schema does not define a {} root",
187                        OperationType::from(operation.operation_type()),
188                    ),
189                    operation.operation_type().span().clone(),
190                )),
191                Vec::new(),
192            ),
193            Error::LeafFieldSelectionNotEmpty {
194                selection_set,
195                r#type,
196            } => Self::new(
197                format!(
198                    "Selection on field of leaf type `{}` was not empty",
199                    r#type.display_name()
200                ),
201                Some(Annotation::new(
202                    "Selection set on field of leaf type must be empty",
203                    selection_set.span().clone(),
204                )),
205                Vec::new(),
206            ),
207            Error::NonLeafFieldSelectionEmpty { field, r#type } => Self::new(
208                format!(
209                    "No selection on field of non-leaf type `{}`",
210                    r#type.display_name()
211                ),
212                Some(Annotation::new(
213                    "Fields of non-leaf types must have a selection",
214                    field.name().span().clone(),
215                )),
216                Vec::new(),
217            ),
218            Error::NonUniqueFragmentDefinitionNames {
219                name,
220                fragment_definitions,
221            } => Self::new(
222                format!("Multiple fragment definitions named `{name}`"),
223                None,
224                fragment_definitions
225                    .iter()
226                    .map(|fragment_definition| {
227                        Annotation::new(
228                            format!("Fragment definition with name `{name}`"),
229                            fragment_definition.name().span().clone(),
230                        )
231                    })
232                    .collect(),
233            ),
234            Error::FragmentDefinitionTargetTypeDoesNotExist {
235                fragment_definition,
236            } => Self::new(
237                format!(
238                    "No type definition with name `{}`",
239                    fragment_definition.type_condition().named_type().as_ref()
240                ),
241                Some(Annotation::new(
242                    "No type with this name",
243                    fragment_definition
244                        .type_condition()
245                        .named_type()
246                        .span()
247                        .clone(),
248                )),
249                Vec::new(),
250            ),
251            Error::InlineFragmentTargetTypeDoesNotExist { inline_fragment } => Self::new(
252                format!(
253                    "No type definition with name `{}`",
254                    inline_fragment
255                        .type_condition()
256                        .map(|tc| tc.named_type().as_ref())
257                        .unwrap_or_default()
258                ),
259                inline_fragment.type_condition().map(|tc| {
260                    Annotation::new("No type with this name", tc.named_type().span().clone())
261                }),
262                Vec::new(),
263            ),
264            Error::FragmentDefinitionTargetTypeNotComposite {
265                fragment_definition,
266            } => Self::new(
267                format!(
268                    "`{}` is not a composite type",
269                    fragment_definition.type_condition().named_type().as_ref()
270                ),
271                Some(Annotation::new(
272                    "Fragment definition target types must be composite types",
273                    fragment_definition
274                        .type_condition()
275                        .named_type()
276                        .span()
277                        .clone(),
278                )),
279                Vec::new(),
280            ),
281            Error::InlineFragmentTargetTypeNotComposite { inline_fragment } => Self::new(
282                format!(
283                    "`{}` is not a composite type",
284                    inline_fragment
285                        .type_condition()
286                        .map(|tc| tc.named_type().as_ref())
287                        .unwrap_or_default()
288                ),
289                inline_fragment.type_condition().map(|tc| {
290                    Annotation::new(
291                        "Inline fragment target types must be composite types",
292                        tc.named_type().span().clone(),
293                    )
294                }),
295                Vec::new(),
296            ),
297            Error::FragmentDefinitionUnused {
298                fragment_definition,
299            } => Self::new(
300                format!(
301                    "Fragment definition `{}` is unused",
302                    fragment_definition.name().as_ref()
303                ),
304                Some(Annotation::new(
305                    "Fragment definition is unused",
306                    fragment_definition.name().span().clone(),
307                )),
308                Vec::new(),
309            ),
310            Error::FragmentSpreadTargetUndefined { fragment_spread } => Self::new(
311                format!(
312                    "No fragment defined with name `{}`",
313                    fragment_spread.name().as_ref()
314                ),
315                Some(Annotation::new(
316                    "No fragment defined with this name",
317                    fragment_spread.name().span().clone(),
318                )),
319                Vec::new(),
320            ),
321            Error::FragmentSpreadCycle {
322                fragment_definition,
323                fragment_spread,
324            } => Self::new(
325                format!(
326                    "Cycle detected in fragment `{}`",
327                    fragment_definition.name().as_ref()
328                ),
329                Some(Annotation::new(
330                    "Cycle introduced by fragment spread",
331                    fragment_spread.name().span().clone(),
332                )),
333                vec![Annotation::new(
334                    "Affected fragment definition",
335                    fragment_definition.name().span().clone(),
336                )],
337            ),
338            Error::FieldSelectionsDoNotMergeDifferingArguments {
339                selection_set,
340                field_a,
341                field_b,
342            } => Self::new(
343                "Fields in selection set do not merge due to unequal arguments",
344                Some(Annotation::new(
345                    "Fields in selection set do not merge",
346                    selection_set.span().clone(),
347                )),
348                vec![
349                    Annotation::new("First field", field_a.name().span().clone()),
350                    Annotation::new("Second field", field_b.name().span().clone()),
351                ],
352            ),
353            Error::FieldSelectionsDoNotMergeDifferingNames {
354                selection_set,
355                field_a,
356                field_b,
357            } => Self::new(
358                "Fields in selection set do not merge due to unequal field names",
359                Some(Annotation::new(
360                    "Fields in selection set do not merge",
361                    selection_set.span().clone(),
362                )),
363                vec![
364                    Annotation::new("First field", field_a.name().span().clone()),
365                    Annotation::new("Second field", field_b.name().span().clone()),
366                ],
367            ),
368            Error::FieldSelectionsDoNotMergeIncompatibleTypes {
369                selection_set,
370                field_a,
371                field_definition_a,
372                field_b,
373                field_definition_b,
374            } => Self::new(
375                "Fields in selection set do not merge due to incompatible types",
376                Some(Annotation::new(
377                    "Fields in selection set do not merge",
378                    selection_set.span().clone(),
379                )),
380                vec![
381                    Annotation::new(
382                        format!(
383                            "First field has type {}",
384                            field_definition_a.r#type().display_name(),
385                        ),
386                        field_a.name().span().clone(),
387                    ),
388                    Annotation::new(
389                        format!(
390                            "Second field has type {}",
391                            field_definition_b.r#type().display_name(),
392                        ),
393                        field_b.name().span().clone(),
394                    ),
395                ],
396            ),
397            Error::FragmentSpreadIsNotPossible {
398                fragment_spread,
399                parent_type,
400            } => Self::new(
401                format!(
402                    "Fragment `{}` cannot be spread for type {}",
403                    fragment_spread.name().as_ref(),
404                    parent_type.name()
405                ),
406                Some(Annotation::new(
407                    format!("Cannot be spread for type {}", parent_type.name()),
408                    fragment_spread.name().span().clone(),
409                )),
410                Vec::new(),
411            ),
412            Error::InlineFragmentSpreadIsNotPossible {
413                inline_fragment,
414                parent_type,
415            } => Self::new(
416                format!(
417                    "Fragment targeting type {} cannot be spread for type {}",
418                    inline_fragment
419                        .type_condition()
420                        .map(|type_condition| type_condition.named_type().as_ref())
421                        .unwrap_or_else(|| parent_type.name()),
422                    parent_type.name(),
423                ),
424                Some(Annotation::new(
425                    format!("Cannot be spread for type {}", parent_type.name()),
426                    inline_fragment.span().clone(),
427                )),
428                Vec::new(),
429            ),
430            Error::InvalidConstValue(error) => Self::from(error),
431            Error::InvalidVariableValue(error) => Self::from(error),
432            Error::InvalidConstDirective(error) => Self::from(error),
433            Error::InvalidVariableDirective(error) => Self::from(error),
434            Error::InvalidConstArgument(error) => Self::from(error),
435            Error::InvalidVariableArgument(error) => Self::from(error),
436            Error::NonUniqueVariableDefinitionNames {
437                name,
438                variable_definitions,
439            } => Self::new(
440                format!("Multiple variable definitions named ${name}"),
441                None,
442                variable_definitions
443                    .iter()
444                    .map(|variable_definition| {
445                        Annotation::new(
446                            format!("Variable definition with name ${name}"),
447                            variable_definition.variable().span().clone(),
448                        )
449                    })
450                    .collect(),
451            ),
452            Error::VariableDefinitionTypeNotInput {
453                variable_definition,
454            } => Self::new(
455                format!(
456                    "Type of variable ${}, {}, is not an input type",
457                    variable_definition.variable().name(),
458                    variable_definition.r#type().as_ref().name()
459                ),
460                Some(Annotation::new(
461                    "Not an input type",
462                    variable_definition.r#type().span().clone(),
463                )),
464                Vec::new(),
465            ),
466            Error::VariableNotDefined {
467                variable,
468                operation_definition,
469            } => {
470                let operation_name = match operation_definition.as_ref().name() {
471                    Some(name) => Cow::Owned(format!("operation {name}")),
472                    None => Cow::Borrowed("anonymous operation"),
473                };
474                Self::new(
475                    format!(
476                        "Variable ${} not defined in {operation_name}",
477                        variable.name(),
478                    ),
479                    Some(Annotation::new(
480                        format!(
481                            "No variable definition with this name defined in {operation_name}",
482                        ),
483                        variable.span().clone(),
484                    )),
485                    Vec::new(),
486                )
487            }
488            Error::VariableDefinitionUnused {
489                variable_definition,
490            } => Self::new(
491                format!(
492                    "Variable definition ${} not used",
493                    variable_definition.variable().name(),
494                ),
495                Some(Annotation::new(
496                    "Variable definition not used",
497                    variable_definition.variable().span().clone(),
498                )),
499                Vec::new(),
500            ),
501            Error::InvalidVariableUsage {
502                variable,
503                variable_type,
504                location_type,
505            } => Self::new(
506                format!(
507                    "Variable ${} of type {} cannot be used here, where {} is expected",
508                    variable.name(),
509                    variable_type.as_ref().display_name(),
510                    location_type.display_name(),
511                ),
512                Some(Annotation::new(
513                    format!(
514                        "Cannot use variable of type {} where {} is expected",
515                        variable_type.as_ref().display_name(),
516                        location_type.display_name(),
517                    ),
518                    variable.span().clone(),
519                )),
520                Vec::new(),
521            ),
522        }
523    }
524}