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}