1use crate::ast;
52use crate::collections::IndexMap;
53use crate::coordinate::FieldArgumentCoordinate;
54use crate::coordinate::TypeAttributeCoordinate;
55use crate::parser::Parser;
56use crate::parser::SourceMap;
57use crate::parser::SourceSpan;
58use crate::schema;
59use crate::validation::DiagnosticList;
60use crate::validation::Valid;
61use crate::validation::WithErrors;
62use crate::Node;
63use crate::Schema;
64use indexmap::map::Entry;
65use std::fmt;
66use std::path::Path;
67use std::sync::Arc;
68
69pub(crate) mod from_ast;
70mod serialize;
71pub(crate) mod validation;
72
73pub use self::from_ast::ExecutableDocumentBuilder;
74pub use crate::ast::Argument;
75use crate::ast::ArgumentByNameError;
76pub use crate::ast::Directive;
77pub use crate::ast::DirectiveList;
78pub use crate::ast::NamedType;
79pub use crate::ast::OperationType;
80pub use crate::ast::Type;
81pub use crate::ast::Value;
82pub use crate::ast::VariableDefinition;
83use crate::collections::HashSet;
84use crate::request::RequestError;
85pub use crate::Name;
86
87#[derive(Debug, Clone, Default)]
89pub struct ExecutableDocument {
90 pub sources: SourceMap,
95
96 pub operations: OperationMap,
97 pub fragments: FragmentMap,
98}
99
100#[derive(Debug, Clone, Default, PartialEq)]
102pub struct OperationMap {
103 pub anonymous: Option<Node<Operation>>,
104 pub named: IndexMap<Name, Node<Operation>>,
105}
106
107pub type FragmentMap = IndexMap<Name, Node<Fragment>>;
109
110#[derive(Debug, Clone)]
113pub struct FieldSet {
114 pub sources: SourceMap,
119
120 pub selection_set: SelectionSet,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct Operation {
127 pub operation_type: OperationType,
128 pub name: Option<Name>,
129 pub variables: Vec<Node<VariableDefinition>>,
130 pub directives: DirectiveList,
131 pub selection_set: SelectionSet,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Fragment {
138 pub name: Name,
139 pub directives: DirectiveList,
140 pub selection_set: SelectionSet,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, Hash)]
146pub struct SelectionSet {
147 pub ty: NamedType,
148 pub selections: Vec<Selection>,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, Hash)]
154pub enum Selection {
155 Field(Node<Field>),
156 FragmentSpread(Node<FragmentSpread>),
157 InlineFragment(Node<InlineFragment>),
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
163pub struct Field {
164 pub definition: Node<schema::FieldDefinition>,
166 pub alias: Option<Name>,
167 pub name: Name,
168 pub arguments: Vec<Node<Argument>>,
169 pub directives: DirectiveList,
170 pub selection_set: SelectionSet,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
176pub struct FragmentSpread {
177 pub fragment_name: Name,
178 pub directives: DirectiveList,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184pub struct InlineFragment {
185 pub type_condition: Option<NamedType>,
186 pub directives: DirectiveList,
187 pub selection_set: SelectionSet,
188}
189
190#[derive(thiserror::Error, Debug, Clone)]
193pub(crate) enum BuildError {
194 #[error("an executable document must not contain {describe}")]
195 TypeSystemDefinition {
196 name: Option<Name>,
197 describe: &'static str,
198 },
199
200 #[error("anonymous operation cannot be selected when the document contains other operations")]
201 AmbiguousAnonymousOperation,
202
203 #[error(
204 "the operation `{name_at_previous_location}` is defined multiple times in the document"
205 )]
206 OperationNameCollision { name_at_previous_location: Name },
207
208 #[error(
209 "the fragment `{name_at_previous_location}` is defined multiple times in the document"
210 )]
211 FragmentNameCollision { name_at_previous_location: Name },
212
213 #[error("`{operation_type}` root operation type is not defined")]
214 UndefinedRootOperation { operation_type: &'static str },
215
216 #[error(
217 "type condition `{type_name}` of fragment `{fragment_name}` \
218 is not a type defined in the schema"
219 )]
220 UndefinedTypeInNamedFragmentTypeCondition {
221 type_name: NamedType,
222 fragment_name: Name,
223 },
224
225 #[error("type condition `{type_name}` of inline fragment is not a type defined in the schema")]
226 UndefinedTypeInInlineFragmentTypeCondition {
227 type_name: NamedType,
228 path: SelectionPath,
229 },
230
231 #[error("field selection of scalar type `{type_name}` must not have subselections")]
232 SubselectionOnScalarType {
233 type_name: NamedType,
234 path: SelectionPath,
235 },
236
237 #[error("field selection of enum type `{type_name}` must not have subselections")]
238 SubselectionOnEnumType {
239 type_name: NamedType,
240 path: SelectionPath,
241 },
242
243 #[error("type `{type_name}` does not have a field `{field_name}`")]
244 UndefinedField {
245 type_name: NamedType,
246 field_name: Name,
247 path: SelectionPath,
248 },
249
250 #[error(
252 "{} can only have one root field",
253 subscription_name_or_anonymous(name)
254 )]
255 SubscriptionUsesMultipleFields {
256 name: Option<Name>,
257 fields: Vec<Name>,
258 },
259
260 #[error(
261 "{} can not have an introspection field as a root field",
262 subscription_name_or_anonymous(name)
263 )]
264 SubscriptionUsesIntrospection {
265 name: Option<Name>,
267 field: Name,
269 },
270 #[error(
271 "{} can not specify @skip or @include on root fields",
272 subscription_name_or_anonymous(name)
273 )]
274 SubscriptionUsesConditionalSelection {
275 name: Option<Name>,
277 },
278
279 #[error("`@defer` label `{label}` is not unique within the document")]
280 DuplicateDeferLabel {
281 label: String,
282 original_location: Option<SourceSpan>,
283 },
284
285 #[error("`@defer` label argument must be a static String, not a variable")]
286 DeferLabelMustNotBeVariable,
287
288 #[error(
289 "`@defer` is not allowed on root selections of {} operations",
290 operation_type.name()
291 )]
292 DeferOnRootMutationOrSubscriptionField { operation_type: OperationType },
293
294 #[error("`@defer` in a subscription operation must be disabled with an `if` argument")]
295 DeferInSubscriptionMustBeConditional,
296
297 #[error("{0}")]
298 ConflictingFieldType(Box<ConflictingFieldType>),
299 #[error("{0}")]
300 ConflictingFieldArgument(Box<ConflictingFieldArgument>),
301 #[error("{0}")]
302 ConflictingFieldName(Box<ConflictingFieldName>),
303}
304
305#[derive(thiserror::Error, Debug, Clone)]
306#[error("operation must not select different types using the same name `{alias}`")]
307pub(crate) struct ConflictingFieldType {
308 pub(crate) alias: Name,
310 pub(crate) original_location: Option<SourceSpan>,
311 pub(crate) original_coordinate: TypeAttributeCoordinate,
312 pub(crate) original_type: Type,
313 pub(crate) conflicting_location: Option<SourceSpan>,
314 pub(crate) conflicting_coordinate: TypeAttributeCoordinate,
315 pub(crate) conflicting_type: Type,
316}
317
318#[derive(thiserror::Error, Debug, Clone)]
319#[error("operation must not provide conflicting field arguments for the same name `{alias}`")]
320pub(crate) struct ConflictingFieldArgument {
321 pub(crate) alias: Name,
323 pub(crate) original_location: Option<SourceSpan>,
324 pub(crate) original_coordinate: FieldArgumentCoordinate,
325 pub(crate) original_value: Option<Value>,
326 pub(crate) conflicting_location: Option<SourceSpan>,
327 pub(crate) conflicting_coordinate: FieldArgumentCoordinate,
328 pub(crate) conflicting_value: Option<Value>,
329}
330
331#[derive(thiserror::Error, Debug, Clone)]
332#[error("cannot select different fields into the same alias `{alias}`")]
333pub(crate) struct ConflictingFieldName {
334 pub(crate) alias: Name,
336 pub(crate) original_location: Option<SourceSpan>,
337 pub(crate) original_selection: TypeAttributeCoordinate,
338 pub(crate) conflicting_location: Option<SourceSpan>,
339 pub(crate) conflicting_selection: TypeAttributeCoordinate,
340}
341
342fn subscription_name_or_anonymous(name: &Option<Name>) -> impl std::fmt::Display + '_ {
343 crate::validation::diagnostics::NameOrAnon {
344 name: name.as_ref(),
345 if_some_prefix: "subscription",
346 if_none: "anonymous subscription",
347 }
348}
349
350#[derive(Debug, Clone, PartialEq, Eq)]
351pub(crate) struct SelectionPath {
352 pub(crate) root: ExecutableDefinitionName,
353 pub(crate) nested_fields: Vec<Name>,
354}
355
356#[derive(Debug, Clone, PartialEq, Eq)]
358pub(crate) enum ExecutableDefinitionName {
359 AnonymousOperation(ast::OperationType),
360 NamedOperation(ast::OperationType, Name),
361 Fragment(Name),
362}
363
364impl ExecutableDocument {
365 pub fn new() -> Self {
367 Self::default()
368 }
369
370 pub fn builder<'schema, 'errors>(
393 schema: Option<&'schema Valid<Schema>>,
394 errors: &'errors mut DiagnosticList,
395 ) -> from_ast::ExecutableDocumentBuilder<'schema, 'errors> {
396 from_ast::ExecutableDocumentBuilder::new(schema.map(|s| s.as_ref()), errors)
397 }
398
399 #[allow(clippy::result_large_err)] pub fn parse(
407 schema: &Valid<Schema>,
408 source_text: impl Into<String>,
409 path: impl AsRef<Path>,
410 ) -> Result<Self, WithErrors<Self>> {
411 Parser::new().parse_executable(schema, source_text, path)
412 }
413
414 #[allow(clippy::result_large_err)] pub fn parse_and_validate(
418 schema: &Valid<Schema>,
419 source_text: impl Into<String>,
420 path: impl AsRef<Path>,
421 ) -> Result<Valid<Self>, WithErrors<Self>> {
422 let (doc, mut errors) = Parser::new().parse_executable_inner(schema, source_text, path);
423 Arc::make_mut(&mut errors.sources)
424 .extend(schema.sources.iter().map(|(k, v)| (*k, v.clone())));
425 validation::validate_executable_document(&mut errors, schema, &doc);
426 errors.into_valid_result(doc)
427 }
428
429 #[allow(clippy::result_large_err)] pub fn validate(self, schema: &Valid<Schema>) -> Result<Valid<Self>, WithErrors<Self>> {
431 let mut sources = IndexMap::clone(&schema.sources);
432 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
433 let mut errors = DiagnosticList::new(Arc::new(sources));
434 validation::validate_executable_document(&mut errors, schema, &self);
435 errors.into_valid_result(self)
436 }
437
438 serialize_method!();
439}
440
441impl Eq for ExecutableDocument {}
442
443impl PartialEq for ExecutableDocument {
445 fn eq(&self, other: &Self) -> bool {
446 let Self {
447 sources: _,
448 operations,
449 fragments,
450 } = self;
451 *operations == other.operations && *fragments == other.fragments
452 }
453}
454
455impl OperationMap {
456 pub fn from_one(operation: impl Into<Node<Operation>>) -> Self {
458 let mut map = Self::default();
459 map.insert(operation);
460 map
461 }
462
463 pub fn is_empty(&self) -> bool {
464 self.anonymous.is_none() && self.named.is_empty()
465 }
466
467 pub fn len(&self) -> usize {
468 self.anonymous.is_some() as usize + self.named.len()
469 }
470
471 pub fn iter(&self) -> impl Iterator<Item = &'_ Node<Operation>> {
473 self.anonymous
474 .as_ref()
475 .into_iter()
476 .chain(self.named.values())
477 }
478
479 pub fn get(&self, name_request: Option<&str>) -> Result<&Node<Operation>, RequestError> {
490 if let Some(name) = name_request {
491 self.named
493 .get(name)
494 .ok_or_else(|| format!("No operation named '{name}'"))
495 } else {
496 if let Some(op) = &self.anonymous {
498 self.named.is_empty().then_some(op)
500 } else {
501 self.named
503 .values()
504 .next()
505 .and_then(|op| (self.named.len() == 1).then_some(op))
506 }
507 .ok_or_else(|| {
508 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
509 })
510 }
511 .map_err(|message| RequestError {
512 message,
513 location: None,
514 is_suspected_validation_bug: false,
515 })
516 }
517
518 pub fn get_mut(&mut self, name_request: Option<&str>) -> Result<&mut Operation, RequestError> {
520 if let Some(name) = name_request {
521 self.named
523 .get_mut(name)
524 .ok_or_else(|| format!("No operation named '{name}'"))
525 } else {
526 if let Some(op) = &mut self.anonymous {
528 self.named.is_empty().then_some(op)
530 } else {
531 let len = self.named.len();
533 self.named
534 .values_mut()
535 .next()
536 .and_then(|op| (len == 1).then_some(op))
537 }
538 .ok_or_else(|| {
539 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
540 })
541 }
542 .map(Node::make_mut)
543 .map_err(|message| RequestError {
544 message,
545 location: None,
546 is_suspected_validation_bug: false,
547 })
548 }
549
550 pub fn insert(&mut self, operation: impl Into<Node<Operation>>) -> Option<Node<Operation>> {
553 let operation = operation.into();
554 if let Some(name) = &operation.name {
555 self.named.insert(name.clone(), operation)
556 } else {
557 self.anonymous.replace(operation)
558 }
559 }
560}
561
562impl Operation {
563 pub fn object_type(&self) -> &NamedType {
565 &self.selection_set.ty
566 }
567
568 pub fn is_query(&self) -> bool {
570 self.operation_type == OperationType::Query
571 }
572
573 pub fn is_mutation(&self) -> bool {
575 self.operation_type == OperationType::Mutation
576 }
577
578 pub fn is_subscription(&self) -> bool {
580 self.operation_type == OperationType::Subscription
581 }
582
583 pub fn is_introspection(&self, document: &ExecutableDocument) -> bool {
586 self.is_query()
587 && self
588 .root_fields(document)
589 .all(|field| matches!(field.name.as_str(), "__type" | "__schema" | "__typename"))
590 }
591
592 pub fn root_fields<'doc>(
607 &'doc self,
608 document: &'doc ExecutableDocument,
609 ) -> impl Iterator<Item = &'doc Node<Field>> {
610 self.selection_set.root_fields(document)
611 }
612
613 pub fn all_fields<'doc>(
626 &'doc self,
627 document: &'doc ExecutableDocument,
628 ) -> impl Iterator<Item = &'doc Node<Field>> {
629 self.selection_set.all_fields(document)
630 }
631
632 serialize_method!();
633}
634
635impl Fragment {
636 pub fn type_condition(&self) -> &NamedType {
637 &self.selection_set.ty
638 }
639
640 serialize_method!();
641}
642
643impl SelectionSet {
644 pub fn new(ty: NamedType) -> Self {
646 Self {
647 ty,
648 selections: Vec::new(),
649 }
650 }
651
652 pub fn is_empty(&self) -> bool {
653 self.selections.is_empty()
654 }
655
656 pub fn push(&mut self, selection: impl Into<Selection>) {
657 self.selections.push(selection.into())
658 }
659
660 pub fn extend(&mut self, selections: impl IntoIterator<Item = impl Into<Selection>>) {
661 self.selections
662 .extend(selections.into_iter().map(|sel| sel.into()))
663 }
664
665 pub fn new_field<'schema>(
670 &self,
671 schema: &'schema Schema,
672 name: Name,
673 ) -> Result<Field, schema::FieldLookupError<'schema>> {
674 let definition = schema.type_field(&self.ty, &name)?.node.clone();
675 Ok(Field::new(name, definition))
676 }
677
678 pub fn new_inline_fragment(&self, opt_type_condition: Option<NamedType>) -> InlineFragment {
680 if let Some(type_condition) = opt_type_condition {
681 InlineFragment::with_type_condition(type_condition)
682 } else {
683 InlineFragment::without_type_condition(self.ty.clone())
684 }
685 }
686
687 pub fn new_fragment_spread(&self, fragment_name: Name) -> FragmentSpread {
689 FragmentSpread::new(fragment_name)
690 }
691
692 pub fn fields(&self) -> impl Iterator<Item = &Node<Field>> {
696 self.selections.iter().filter_map(|sel| sel.as_field())
697 }
698
699 pub fn root_fields<'doc>(
714 &'doc self,
715 document: &'doc ExecutableDocument,
716 ) -> impl Iterator<Item = &'doc Node<Field>> {
717 let mut stack = vec![self.selections.iter()];
718 let mut fragments_seen = HashSet::default();
719 std::iter::from_fn(move || {
720 while let Some(selection_set_iter) = stack.last_mut() {
721 match selection_set_iter.next() {
722 Some(Selection::Field(field)) => {
723 return Some(field);
726 }
727 Some(Selection::InlineFragment(inline)) => {
728 stack.push(inline.selection_set.selections.iter())
729 }
730 Some(Selection::FragmentSpread(spread)) => {
731 if let Some(def) = document.fragments.get(&spread.fragment_name) {
732 let new = fragments_seen.insert(&spread.fragment_name);
733 if new {
734 stack.push(def.selection_set.selections.iter())
735 }
736 } else {
737 }
740 }
741 None => {
742 stack.pop();
745 }
746 }
747 }
748 None
749 })
750 }
751
752 pub fn all_fields<'doc>(
765 &'doc self,
766 document: &'doc ExecutableDocument,
767 ) -> impl Iterator<Item = &'doc Node<Field>> {
768 let mut stack = vec![self.selections.iter()];
769 let mut fragments_seen = HashSet::default();
770 std::iter::from_fn(move || {
771 while let Some(selection_set_iter) = stack.last_mut() {
772 match selection_set_iter.next() {
773 Some(Selection::Field(field)) => {
774 if !field.selection_set.is_empty() {
775 stack.push(field.selection_set.selections.iter())
777 }
778 return Some(field);
780 }
781 Some(Selection::InlineFragment(inline)) => {
782 stack.push(inline.selection_set.selections.iter())
783 }
784 Some(Selection::FragmentSpread(spread)) => {
785 if let Some(def) = document.fragments.get(&spread.fragment_name) {
786 let new = fragments_seen.insert(&spread.fragment_name);
787 if new {
788 stack.push(def.selection_set.selections.iter())
789 }
790 } else {
791 }
794 }
795 None => {
796 stack.pop();
799 }
800 }
801 }
802 None
803 })
804 }
805
806 serialize_method!();
807}
808
809impl Selection {
810 pub fn directives(&self) -> &DirectiveList {
811 match self {
812 Self::Field(sel) => &sel.directives,
813 Self::FragmentSpread(sel) => &sel.directives,
814 Self::InlineFragment(sel) => &sel.directives,
815 }
816 }
817
818 pub fn as_field(&self) -> Option<&Node<Field>> {
819 if let Self::Field(field) = self {
820 Some(field)
821 } else {
822 None
823 }
824 }
825
826 pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
827 if let Self::InlineFragment(inline) = self {
828 Some(inline)
829 } else {
830 None
831 }
832 }
833
834 pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
835 if let Self::FragmentSpread(spread) = self {
836 Some(spread)
837 } else {
838 None
839 }
840 }
841
842 serialize_method!();
843}
844
845impl From<Node<Field>> for Selection {
846 fn from(node: Node<Field>) -> Self {
847 Self::Field(node)
848 }
849}
850
851impl From<Node<InlineFragment>> for Selection {
852 fn from(node: Node<InlineFragment>) -> Self {
853 Self::InlineFragment(node)
854 }
855}
856
857impl From<Node<FragmentSpread>> for Selection {
858 fn from(node: Node<FragmentSpread>) -> Self {
859 Self::FragmentSpread(node)
860 }
861}
862
863impl From<Field> for Selection {
864 fn from(value: Field) -> Self {
865 Self::Field(Node::new(value))
866 }
867}
868
869impl From<InlineFragment> for Selection {
870 fn from(value: InlineFragment) -> Self {
871 Self::InlineFragment(Node::new(value))
872 }
873}
874
875impl From<FragmentSpread> for Selection {
876 fn from(value: FragmentSpread) -> Self {
877 Self::FragmentSpread(Node::new(value))
878 }
879}
880
881impl Field {
882 pub fn new(name: Name, definition: Node<schema::FieldDefinition>) -> Self {
886 let selection_set = SelectionSet::new(definition.ty.inner_named_type().clone());
887 Field {
888 definition,
889 alias: None,
890 name,
891 arguments: Vec::new(),
892 directives: DirectiveList::new(),
893 selection_set,
894 }
895 }
896
897 pub fn with_alias(mut self, alias: Name) -> Self {
898 self.alias = Some(alias);
899 self
900 }
901
902 pub fn with_opt_alias(mut self, alias: Option<Name>) -> Self {
903 self.alias = alias;
904 self
905 }
906
907 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
908 self.directives.push(directive.into());
909 self
910 }
911
912 pub fn with_directives(
913 mut self,
914 directives: impl IntoIterator<Item = Node<Directive>>,
915 ) -> Self {
916 self.directives.extend(directives);
917 self
918 }
919
920 pub fn with_argument(mut self, name: Name, value: impl Into<Node<Value>>) -> Self {
921 self.arguments.push((name, value).into());
922 self
923 }
924
925 pub fn with_arguments(mut self, arguments: impl IntoIterator<Item = Node<Argument>>) -> Self {
926 self.arguments.extend(arguments);
927 self
928 }
929
930 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
931 self.selection_set.push(selection);
932 self
933 }
934
935 pub fn with_selections(
936 mut self,
937 selections: impl IntoIterator<Item = impl Into<Selection>>,
938 ) -> Self {
939 self.selection_set.extend(selections);
940 self
941 }
942
943 pub fn response_key(&self) -> &Name {
945 self.alias.as_ref().unwrap_or(&self.name)
946 }
947
948 pub fn ty(&self) -> &Type {
950 &self.definition.ty
951 }
952
953 pub fn inner_type_def<'a>(&self, schema: &'a Schema) -> Option<&'a schema::ExtendedType> {
957 schema.types.get(self.ty().inner_named_type())
958 }
959
960 pub fn argument_by_name(&self, name: &str) -> Result<&Node<Value>, ArgumentByNameError> {
963 Argument::argument_by_name(&self.arguments, name, || {
964 self.definition
965 .argument_by_name(name)
966 .ok_or(ArgumentByNameError::NoSuchArgument)
967 })
968 }
969
970 pub fn specified_argument_by_name(&self, name: &str) -> Option<&Node<Value>> {
977 Argument::specified_argument_by_name(&self.arguments, name)
978 }
979
980 serialize_method!();
981}
982
983impl InlineFragment {
984 pub fn with_type_condition(type_condition: NamedType) -> Self {
985 let selection_set = SelectionSet::new(type_condition.clone());
986 Self {
987 type_condition: Some(type_condition),
988 directives: DirectiveList::new(),
989 selection_set,
990 }
991 }
992
993 pub fn without_type_condition(parent_selection_set_type: NamedType) -> Self {
994 Self {
995 type_condition: None,
996 directives: DirectiveList::new(),
997 selection_set: SelectionSet::new(parent_selection_set_type),
998 }
999 }
1000
1001 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
1002 self.directives.push(directive.into());
1003 self
1004 }
1005
1006 pub fn with_directives(
1007 mut self,
1008 directives: impl IntoIterator<Item = Node<Directive>>,
1009 ) -> Self {
1010 self.directives.extend(directives);
1011 self
1012 }
1013
1014 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
1015 self.selection_set.push(selection);
1016 self
1017 }
1018
1019 pub fn with_selections(
1020 mut self,
1021 selections: impl IntoIterator<Item = impl Into<Selection>>,
1022 ) -> Self {
1023 self.selection_set.extend(selections);
1024 self
1025 }
1026
1027 serialize_method!();
1028}
1029
1030impl FragmentSpread {
1031 pub fn new(fragment_name: Name) -> Self {
1032 Self {
1033 fragment_name,
1034 directives: DirectiveList::new(),
1035 }
1036 }
1037
1038 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
1039 self.directives.push(directive.into());
1040 self
1041 }
1042
1043 pub fn with_directives(
1044 mut self,
1045 directives: impl IntoIterator<Item = Node<Directive>>,
1046 ) -> Self {
1047 self.directives.extend(directives);
1048 self
1049 }
1050
1051 pub fn fragment_def<'a>(&self, document: &'a ExecutableDocument) -> Option<&'a Node<Fragment>> {
1052 document.fragments.get(&self.fragment_name)
1053 }
1054
1055 serialize_method!();
1056}
1057
1058impl FieldSet {
1059 pub fn parse(
1066 schema: &Valid<Schema>,
1067 type_name: NamedType,
1068 source_text: impl Into<String>,
1069 path: impl AsRef<Path>,
1070 ) -> Result<FieldSet, WithErrors<FieldSet>> {
1071 Parser::new().parse_field_set(schema, type_name, source_text, path)
1072 }
1073
1074 pub fn parse_and_validate(
1077 schema: &Valid<Schema>,
1078 type_name: NamedType,
1079 source_text: impl Into<String>,
1080 path: impl AsRef<Path>,
1081 ) -> Result<Valid<Self>, WithErrors<Self>> {
1082 let (field_set, mut errors) =
1083 Parser::new().parse_field_set_inner(schema, type_name, source_text, path);
1084 validation::validate_field_set(&mut errors, schema, &field_set);
1085 errors.into_valid_result(field_set)
1086 }
1087
1088 pub fn validate(&self, schema: &Valid<Schema>) -> Result<(), DiagnosticList> {
1089 let mut sources = IndexMap::clone(&schema.sources);
1090 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
1091 let mut errors = DiagnosticList::new(Arc::new(sources));
1092 validation::validate_field_set(&mut errors, schema, self);
1093 errors.into_result()
1094 }
1095
1096 serialize_method!();
1097}
1098
1099impl fmt::Display for SelectionPath {
1100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1101 match &self.root {
1102 ExecutableDefinitionName::AnonymousOperation(operation_type) => {
1103 write!(f, "{operation_type}")?
1104 }
1105 ExecutableDefinitionName::NamedOperation(operation_type, name) => {
1106 write!(f, "{operation_type} {name}")?
1107 }
1108 ExecutableDefinitionName::Fragment(name) => write!(f, "fragment {name}")?,
1109 }
1110 for name in &self.nested_fields {
1111 write!(f, " → {name}")?
1112 }
1113 Ok(())
1114 }
1115}