Skip to main content

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    InvalidOneOfVariableUsage {
124        variable: &'a <E::Value<false> as Value<false>>::Variable,
125        variable_type: &'a E::VariableType,
126        parent_type_name: &'a str,
127    },
128}
129
130#[cfg(feature = "parser-integration")]
131impl<'a, S: SchemaDefinition> From<Error<'a, ParserExecutableDocument<'a>, S>> for ParserError {
132    fn from(value: Error<'a, ParserExecutableDocument<'a>, S>) -> Self {
133        match value {
134            Error::NonUniqueOperationNames { name, operations } => Self::new(
135                format!("Multiple operation definitions named `{name}`"),
136                None,
137                operations
138                    .iter()
139                    .filter_map(|operation| {
140                        operation.name().map(|operation_name| {
141                            Annotation::new(
142                                format!("Operation definition with name `{name}`"),
143                                *operation_name.span(),
144                            )
145                        })
146                    })
147                    .collect(),
148            ),
149            Error::NotLoneAnonymousOperation {
150                anonymous_operations,
151            } => Self::new(
152                "Anonymous operation not lone operation in document",
153                None,
154                anonymous_operations
155                    .iter()
156                    .map(|operation| {
157                        Annotation::new(
158                            "Anonymous operation definition",
159                            *operation.as_ref().selection_set().span(),
160                        )
161                    })
162                    .collect(),
163            ),
164            Error::SubscriptionRootNotSingleField { operation } => Self::new(
165                "Subscription root is not a single field",
166                Some(Annotation::new(
167                    "Selection set contains multiple fields",
168                    *operation.as_ref().selection_set().span(),
169                )),
170                Vec::new(),
171            ),
172            Error::FieldDoesNotExistOnType { field, r#type } => Self::new(
173                format!(
174                    "Field `{}` does not exist on type `{}`",
175                    field.name().as_ref(),
176                    r#type.name()
177                ),
178                Some(Annotation::new(
179                    format!("Field does not exist on type `{}`", r#type.name()),
180                    *field.name().span(),
181                )),
182                Vec::new(),
183            ),
184            Error::OperationTypeNotDefined { operation } => Self::new(
185                format!(
186                    "Schema does not define a {} root",
187                    OperationType::from(operation.operation_type()),
188                ),
189                Some(Annotation::new(
190                    format!(
191                        "Schema does not define a {} root",
192                        OperationType::from(operation.operation_type()),
193                    ),
194                    *operation.operation_type().span(),
195                )),
196                Vec::new(),
197            ),
198            Error::LeafFieldSelectionNotEmpty {
199                selection_set,
200                r#type,
201            } => Self::new(
202                format!(
203                    "Selection on field of leaf type `{}` was not empty",
204                    r#type.display_name()
205                ),
206                Some(Annotation::new(
207                    "Selection set on field of leaf type must be empty",
208                    *selection_set.span(),
209                )),
210                Vec::new(),
211            ),
212            Error::NonLeafFieldSelectionEmpty { field, r#type } => Self::new(
213                format!(
214                    "No selection on field of non-leaf type `{}`",
215                    r#type.display_name()
216                ),
217                Some(Annotation::new(
218                    "Fields of non-leaf types must have a selection",
219                    *field.name().span(),
220                )),
221                Vec::new(),
222            ),
223            Error::NonUniqueFragmentDefinitionNames {
224                name,
225                fragment_definitions,
226            } => Self::new(
227                format!("Multiple fragment definitions named `{name}`"),
228                None,
229                fragment_definitions
230                    .iter()
231                    .map(|fragment_definition| {
232                        Annotation::new(
233                            format!("Fragment definition with name `{name}`"),
234                            *fragment_definition.name().span(),
235                        )
236                    })
237                    .collect(),
238            ),
239            Error::FragmentDefinitionTargetTypeDoesNotExist {
240                fragment_definition,
241            } => Self::new(
242                format!(
243                    "No type definition with name `{}`",
244                    fragment_definition.type_condition().named_type().as_ref()
245                ),
246                Some(Annotation::new(
247                    "No type with this name",
248                    *fragment_definition
249                        .type_condition()
250                        .named_type()
251                        .span(),
252                )),
253                Vec::new(),
254            ),
255            Error::InlineFragmentTargetTypeDoesNotExist { inline_fragment } => Self::new(
256                format!(
257                    "No type definition with name `{}`",
258                    inline_fragment
259                        .type_condition()
260                        .map(|tc| tc.named_type().as_ref())
261                        .unwrap_or_default()
262                ),
263                inline_fragment.type_condition().map(|tc| {
264                    Annotation::new("No type with this name", *tc.named_type().span())
265                }),
266                Vec::new(),
267            ),
268            Error::FragmentDefinitionTargetTypeNotComposite {
269                fragment_definition,
270            } => Self::new(
271                format!(
272                    "`{}` is not a composite type",
273                    fragment_definition.type_condition().named_type().as_ref()
274                ),
275                Some(Annotation::new(
276                    "Fragment definition target types must be composite types",
277                    *fragment_definition
278                        .type_condition()
279                        .named_type()
280                        .span(),
281                )),
282                Vec::new(),
283            ),
284            Error::InlineFragmentTargetTypeNotComposite { inline_fragment } => Self::new(
285                format!(
286                    "`{}` is not a composite type",
287                    inline_fragment
288                        .type_condition()
289                        .map(|tc| tc.named_type().as_ref())
290                        .unwrap_or_default()
291                ),
292                inline_fragment.type_condition().map(|tc| {
293                    Annotation::new(
294                        "Inline fragment target types must be composite types",
295                        *tc.named_type().span(),
296                    )
297                }),
298                Vec::new(),
299            ),
300            Error::FragmentDefinitionUnused {
301                fragment_definition,
302            } => Self::new(
303                format!(
304                    "Fragment definition `{}` is unused",
305                    fragment_definition.name().as_ref()
306                ),
307                Some(Annotation::new(
308                    "Fragment definition is unused",
309                    *fragment_definition.name().span(),
310                )),
311                Vec::new(),
312            ),
313            Error::FragmentSpreadTargetUndefined { fragment_spread } => Self::new(
314                format!(
315                    "No fragment defined with name `{}`",
316                    fragment_spread.name().as_ref()
317                ),
318                Some(Annotation::new(
319                    "No fragment defined with this name",
320                    *fragment_spread.name().span(),
321                )),
322                Vec::new(),
323            ),
324            Error::FragmentSpreadCycle {
325                fragment_definition,
326                fragment_spread,
327            } => Self::new(
328                format!(
329                    "Cycle detected in fragment `{}`",
330                    fragment_definition.name().as_ref()
331                ),
332                Some(Annotation::new(
333                    "Cycle introduced by fragment spread",
334                    *fragment_spread.name().span(),
335                )),
336                vec![Annotation::new(
337                    "Affected fragment definition",
338                    *fragment_definition.name().span(),
339                )],
340            ),
341            Error::FieldSelectionsDoNotMergeDifferingArguments {
342                selection_set,
343                field_a,
344                field_b,
345            } => Self::new(
346                "Fields in selection set do not merge due to unequal arguments",
347                Some(Annotation::new(
348                    "Fields in selection set do not merge",
349                    *selection_set.span(),
350                )),
351                vec![
352                    Annotation::new("First field", *field_a.name().span()),
353                    Annotation::new("Second field", *field_b.name().span()),
354                ],
355            ),
356            Error::FieldSelectionsDoNotMergeDifferingNames {
357                selection_set,
358                field_a,
359                field_b,
360            } => Self::new(
361                "Fields in selection set do not merge due to unequal field names",
362                Some(Annotation::new(
363                    "Fields in selection set do not merge",
364                    *selection_set.span(),
365                )),
366                vec![
367                    Annotation::new("First field", *field_a.name().span()),
368                    Annotation::new("Second field", *field_b.name().span()),
369                ],
370            ),
371            Error::FieldSelectionsDoNotMergeIncompatibleTypes {
372                selection_set,
373                field_a,
374                field_definition_a,
375                field_b,
376                field_definition_b,
377            } => Self::new(
378                "Fields in selection set do not merge due to incompatible types",
379                Some(Annotation::new(
380                    "Fields in selection set do not merge",
381                    *selection_set.span(),
382                )),
383                vec![
384                    Annotation::new(
385                        format!(
386                            "First field has type {}",
387                            field_definition_a.r#type().display_name(),
388                        ),
389                        *field_a.name().span(),
390                    ),
391                    Annotation::new(
392                        format!(
393                            "Second field has type {}",
394                            field_definition_b.r#type().display_name(),
395                        ),
396                        *field_b.name().span(),
397                    ),
398                ],
399            ),
400            Error::FragmentSpreadIsNotPossible {
401                fragment_spread,
402                parent_type,
403            } => Self::new(
404                format!(
405                    "Fragment `{}` cannot be spread for type {}",
406                    fragment_spread.name().as_ref(),
407                    parent_type.name()
408                ),
409                Some(Annotation::new(
410                    format!("Cannot be spread for type {}", parent_type.name()),
411                    *fragment_spread.name().span(),
412                )),
413                Vec::new(),
414            ),
415            Error::InlineFragmentSpreadIsNotPossible {
416                inline_fragment,
417                parent_type,
418            } => Self::new(
419                format!(
420                    "Fragment targeting type {} cannot be spread for type {}",
421                    inline_fragment
422                        .type_condition()
423                        .map(|type_condition| type_condition.named_type().as_ref())
424                        .unwrap_or_else(|| parent_type.name()),
425                    parent_type.name(),
426                ),
427                Some(Annotation::new(
428                    format!("Cannot be spread for type {}", parent_type.name()),
429                    *inline_fragment.span(),
430                )),
431                Vec::new(),
432            ),
433            Error::InvalidConstValue(error) => Self::from(error),
434            Error::InvalidVariableValue(error) => Self::from(error),
435            Error::InvalidConstDirective(error) => Self::from(error),
436            Error::InvalidVariableDirective(error) => Self::from(error),
437            Error::InvalidConstArgument(error) => Self::from(error),
438            Error::InvalidVariableArgument(error) => Self::from(error),
439            Error::NonUniqueVariableDefinitionNames {
440                name,
441                variable_definitions,
442            } => Self::new(
443                format!("Multiple variable definitions named ${name}"),
444                None,
445                variable_definitions
446                    .iter()
447                    .map(|variable_definition| {
448                        Annotation::new(
449                            format!("Variable definition with name ${name}"),
450                            *variable_definition.variable().span(),
451                        )
452                    })
453                    .collect(),
454            ),
455            Error::VariableDefinitionTypeNotInput {
456                variable_definition,
457            } => Self::new(
458                format!(
459                    "Type of variable ${}, {}, is not an input type",
460                    variable_definition.variable().name(),
461                    variable_definition.r#type().as_ref().name()
462                ),
463                Some(Annotation::new(
464                    "Not an input type",
465                    *variable_definition.r#type().span(),
466                )),
467                Vec::new(),
468            ),
469            Error::VariableNotDefined {
470                variable,
471                operation_definition,
472            } => {
473                let operation_name = match operation_definition.as_ref().name() {
474                    Some(name) => Cow::Owned(format!("operation {name}")),
475                    None => Cow::Borrowed("anonymous operation"),
476                };
477                Self::new(
478                    format!(
479                        "Variable ${} not defined in {operation_name}",
480                        variable.name(),
481                    ),
482                    Some(Annotation::new(
483                        format!(
484                            "No variable definition with this name defined in {operation_name}",
485                        ),
486                        *variable.span(),
487                    )),
488                    Vec::new(),
489                )
490            }
491            Error::VariableDefinitionUnused {
492                variable_definition,
493            } => Self::new(
494                format!(
495                    "Variable definition ${} not used",
496                    variable_definition.variable().name(),
497                ),
498                Some(Annotation::new(
499                    "Variable definition not used",
500                    *variable_definition.variable().span(),
501                )),
502                Vec::new(),
503            ),
504            Error::InvalidVariableUsage {
505                variable,
506                variable_type,
507                location_type,
508            } => Self::new(
509                format!(
510                    "Variable ${} of type {} cannot be used here, where {} is expected",
511                    variable.name(),
512                    variable_type.as_ref().display_name(),
513                    location_type.display_name(),
514                ),
515                Some(Annotation::new(
516                    format!(
517                        "Cannot use variable of type {} where {} is expected",
518                        variable_type.as_ref().display_name(),
519                        location_type.display_name(),
520                    ),
521                    *variable.span(),
522                )),
523                Vec::new(),
524            ),
525            Error::InvalidOneOfVariableUsage {
526                variable,
527                variable_type,
528                parent_type_name,
529            } => Self::new(
530                format!(
531                    "Variable ${} is of type {} but must be non-nullable to be used for OneOf Input Object {}",
532                    variable.name(),
533                    variable_type.as_ref().display_name(),
534                    parent_type_name,
535                ),
536                Some(Annotation::new(
537                    format!(
538                        "Variable ${} is of type {} but must be non-nullable to be used for OneOf Input Object {}",
539                        variable.name(),
540                        variable_type.as_ref().display_name(),
541                        parent_type_name,
542                    ),
543                    *variable.span(),
544                )),
545                Vec::new(),
546            ),
547        }
548    }
549}