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().clone(),
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().clone(),
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().clone(),
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().clone(),
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().clone(),
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().clone(),
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().clone(),
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().clone(),
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                        .clone(),
253                )),
254                Vec::new(),
255            ),
256            Error::InlineFragmentTargetTypeDoesNotExist { inline_fragment } => Self::new(
257                format!(
258                    "No type definition with name `{}`",
259                    inline_fragment
260                        .type_condition()
261                        .map(|tc| tc.named_type().as_ref())
262                        .unwrap_or_default()
263                ),
264                inline_fragment.type_condition().map(|tc| {
265                    Annotation::new("No type with this name", tc.named_type().span().clone())
266                }),
267                Vec::new(),
268            ),
269            Error::FragmentDefinitionTargetTypeNotComposite {
270                fragment_definition,
271            } => Self::new(
272                format!(
273                    "`{}` is not a composite type",
274                    fragment_definition.type_condition().named_type().as_ref()
275                ),
276                Some(Annotation::new(
277                    "Fragment definition target types must be composite types",
278                    fragment_definition
279                        .type_condition()
280                        .named_type()
281                        .span()
282                        .clone(),
283                )),
284                Vec::new(),
285            ),
286            Error::InlineFragmentTargetTypeNotComposite { inline_fragment } => Self::new(
287                format!(
288                    "`{}` is not a composite type",
289                    inline_fragment
290                        .type_condition()
291                        .map(|tc| tc.named_type().as_ref())
292                        .unwrap_or_default()
293                ),
294                inline_fragment.type_condition().map(|tc| {
295                    Annotation::new(
296                        "Inline fragment target types must be composite types",
297                        tc.named_type().span().clone(),
298                    )
299                }),
300                Vec::new(),
301            ),
302            Error::FragmentDefinitionUnused {
303                fragment_definition,
304            } => Self::new(
305                format!(
306                    "Fragment definition `{}` is unused",
307                    fragment_definition.name().as_ref()
308                ),
309                Some(Annotation::new(
310                    "Fragment definition is unused",
311                    fragment_definition.name().span().clone(),
312                )),
313                Vec::new(),
314            ),
315            Error::FragmentSpreadTargetUndefined { fragment_spread } => Self::new(
316                format!(
317                    "No fragment defined with name `{}`",
318                    fragment_spread.name().as_ref()
319                ),
320                Some(Annotation::new(
321                    "No fragment defined with this name",
322                    fragment_spread.name().span().clone(),
323                )),
324                Vec::new(),
325            ),
326            Error::FragmentSpreadCycle {
327                fragment_definition,
328                fragment_spread,
329            } => Self::new(
330                format!(
331                    "Cycle detected in fragment `{}`",
332                    fragment_definition.name().as_ref()
333                ),
334                Some(Annotation::new(
335                    "Cycle introduced by fragment spread",
336                    fragment_spread.name().span().clone(),
337                )),
338                vec![Annotation::new(
339                    "Affected fragment definition",
340                    fragment_definition.name().span().clone(),
341                )],
342            ),
343            Error::FieldSelectionsDoNotMergeDifferingArguments {
344                selection_set,
345                field_a,
346                field_b,
347            } => Self::new(
348                "Fields in selection set do not merge due to unequal arguments",
349                Some(Annotation::new(
350                    "Fields in selection set do not merge",
351                    selection_set.span().clone(),
352                )),
353                vec![
354                    Annotation::new("First field", field_a.name().span().clone()),
355                    Annotation::new("Second field", field_b.name().span().clone()),
356                ],
357            ),
358            Error::FieldSelectionsDoNotMergeDifferingNames {
359                selection_set,
360                field_a,
361                field_b,
362            } => Self::new(
363                "Fields in selection set do not merge due to unequal field names",
364                Some(Annotation::new(
365                    "Fields in selection set do not merge",
366                    selection_set.span().clone(),
367                )),
368                vec![
369                    Annotation::new("First field", field_a.name().span().clone()),
370                    Annotation::new("Second field", field_b.name().span().clone()),
371                ],
372            ),
373            Error::FieldSelectionsDoNotMergeIncompatibleTypes {
374                selection_set,
375                field_a,
376                field_definition_a,
377                field_b,
378                field_definition_b,
379            } => Self::new(
380                "Fields in selection set do not merge due to incompatible types",
381                Some(Annotation::new(
382                    "Fields in selection set do not merge",
383                    selection_set.span().clone(),
384                )),
385                vec![
386                    Annotation::new(
387                        format!(
388                            "First field has type {}",
389                            field_definition_a.r#type().display_name(),
390                        ),
391                        field_a.name().span().clone(),
392                    ),
393                    Annotation::new(
394                        format!(
395                            "Second field has type {}",
396                            field_definition_b.r#type().display_name(),
397                        ),
398                        field_b.name().span().clone(),
399                    ),
400                ],
401            ),
402            Error::FragmentSpreadIsNotPossible {
403                fragment_spread,
404                parent_type,
405            } => Self::new(
406                format!(
407                    "Fragment `{}` cannot be spread for type {}",
408                    fragment_spread.name().as_ref(),
409                    parent_type.name()
410                ),
411                Some(Annotation::new(
412                    format!("Cannot be spread for type {}", parent_type.name()),
413                    fragment_spread.name().span().clone(),
414                )),
415                Vec::new(),
416            ),
417            Error::InlineFragmentSpreadIsNotPossible {
418                inline_fragment,
419                parent_type,
420            } => Self::new(
421                format!(
422                    "Fragment targeting type {} cannot be spread for type {}",
423                    inline_fragment
424                        .type_condition()
425                        .map(|type_condition| type_condition.named_type().as_ref())
426                        .unwrap_or_else(|| parent_type.name()),
427                    parent_type.name(),
428                ),
429                Some(Annotation::new(
430                    format!("Cannot be spread for type {}", parent_type.name()),
431                    inline_fragment.span().clone(),
432                )),
433                Vec::new(),
434            ),
435            Error::InvalidConstValue(error) => Self::from(error),
436            Error::InvalidVariableValue(error) => Self::from(error),
437            Error::InvalidConstDirective(error) => Self::from(error),
438            Error::InvalidVariableDirective(error) => Self::from(error),
439            Error::InvalidConstArgument(error) => Self::from(error),
440            Error::InvalidVariableArgument(error) => Self::from(error),
441            Error::NonUniqueVariableDefinitionNames {
442                name,
443                variable_definitions,
444            } => Self::new(
445                format!("Multiple variable definitions named ${name}"),
446                None,
447                variable_definitions
448                    .iter()
449                    .map(|variable_definition| {
450                        Annotation::new(
451                            format!("Variable definition with name ${name}"),
452                            variable_definition.variable().span().clone(),
453                        )
454                    })
455                    .collect(),
456            ),
457            Error::VariableDefinitionTypeNotInput {
458                variable_definition,
459            } => Self::new(
460                format!(
461                    "Type of variable ${}, {}, is not an input type",
462                    variable_definition.variable().name(),
463                    variable_definition.r#type().as_ref().name()
464                ),
465                Some(Annotation::new(
466                    "Not an input type",
467                    variable_definition.r#type().span().clone(),
468                )),
469                Vec::new(),
470            ),
471            Error::VariableNotDefined {
472                variable,
473                operation_definition,
474            } => {
475                let operation_name = match operation_definition.as_ref().name() {
476                    Some(name) => Cow::Owned(format!("operation {name}")),
477                    None => Cow::Borrowed("anonymous operation"),
478                };
479                Self::new(
480                    format!(
481                        "Variable ${} not defined in {operation_name}",
482                        variable.name(),
483                    ),
484                    Some(Annotation::new(
485                        format!(
486                            "No variable definition with this name defined in {operation_name}",
487                        ),
488                        variable.span().clone(),
489                    )),
490                    Vec::new(),
491                )
492            }
493            Error::VariableDefinitionUnused {
494                variable_definition,
495            } => Self::new(
496                format!(
497                    "Variable definition ${} not used",
498                    variable_definition.variable().name(),
499                ),
500                Some(Annotation::new(
501                    "Variable definition not used",
502                    variable_definition.variable().span().clone(),
503                )),
504                Vec::new(),
505            ),
506            Error::InvalidVariableUsage {
507                variable,
508                variable_type,
509                location_type,
510            } => Self::new(
511                format!(
512                    "Variable ${} of type {} cannot be used here, where {} is expected",
513                    variable.name(),
514                    variable_type.as_ref().display_name(),
515                    location_type.display_name(),
516                ),
517                Some(Annotation::new(
518                    format!(
519                        "Cannot use variable of type {} where {} is expected",
520                        variable_type.as_ref().display_name(),
521                        location_type.display_name(),
522                    ),
523                    variable.span().clone(),
524                )),
525                Vec::new(),
526            ),
527            Error::InvalidOneOfVariableUsage {
528                variable,
529                variable_type,
530                parent_type_name,
531            } => Self::new(
532                format!(
533                    "Variable ${} is of type {} but must be non-nullable to be used for OneOf Input Object {}",
534                    variable.name(),
535                    variable_type.as_ref().display_name(),
536                    parent_type_name,
537                ),
538                Some(Annotation::new(
539                    format!(
540                        "Variable ${} is of type {} but must be non-nullable to be used for OneOf Input Object {}",
541                        variable.name(),
542                        variable_type.as_ref().display_name(),
543                        parent_type_name,
544                    ),
545                    variable.span().clone(),
546                )),
547                Vec::new(),
548            ),
549        }
550    }
551}