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("{0}")]
280 ConflictingFieldType(Box<ConflictingFieldType>),
281 #[error("{0}")]
282 ConflictingFieldArgument(Box<ConflictingFieldArgument>),
283 #[error("{0}")]
284 ConflictingFieldName(Box<ConflictingFieldName>),
285}
286
287#[derive(thiserror::Error, Debug, Clone)]
288#[error("operation must not select different types using the same name `{alias}`")]
289pub(crate) struct ConflictingFieldType {
290 pub(crate) alias: Name,
292 pub(crate) original_location: Option<SourceSpan>,
293 pub(crate) original_coordinate: TypeAttributeCoordinate,
294 pub(crate) original_type: Type,
295 pub(crate) conflicting_location: Option<SourceSpan>,
296 pub(crate) conflicting_coordinate: TypeAttributeCoordinate,
297 pub(crate) conflicting_type: Type,
298}
299
300#[derive(thiserror::Error, Debug, Clone)]
301#[error("operation must not provide conflicting field arguments for the same name `{alias}`")]
302pub(crate) struct ConflictingFieldArgument {
303 pub(crate) alias: Name,
305 pub(crate) original_location: Option<SourceSpan>,
306 pub(crate) original_coordinate: FieldArgumentCoordinate,
307 pub(crate) original_value: Option<Value>,
308 pub(crate) conflicting_location: Option<SourceSpan>,
309 pub(crate) conflicting_coordinate: FieldArgumentCoordinate,
310 pub(crate) conflicting_value: Option<Value>,
311}
312
313#[derive(thiserror::Error, Debug, Clone)]
314#[error("cannot select different fields into the same alias `{alias}`")]
315pub(crate) struct ConflictingFieldName {
316 pub(crate) alias: Name,
318 pub(crate) original_location: Option<SourceSpan>,
319 pub(crate) original_selection: TypeAttributeCoordinate,
320 pub(crate) conflicting_location: Option<SourceSpan>,
321 pub(crate) conflicting_selection: TypeAttributeCoordinate,
322}
323
324fn subscription_name_or_anonymous(name: &Option<Name>) -> impl std::fmt::Display + '_ {
325 crate::validation::diagnostics::NameOrAnon {
326 name: name.as_ref(),
327 if_some_prefix: "subscription",
328 if_none: "anonymous subscription",
329 }
330}
331
332#[derive(Debug, Clone, PartialEq, Eq)]
333pub(crate) struct SelectionPath {
334 pub(crate) root: ExecutableDefinitionName,
335 pub(crate) nested_fields: Vec<Name>,
336}
337
338#[derive(Debug, Clone, PartialEq, Eq)]
340pub(crate) enum ExecutableDefinitionName {
341 AnonymousOperation(ast::OperationType),
342 NamedOperation(ast::OperationType, Name),
343 Fragment(Name),
344}
345
346impl ExecutableDocument {
347 pub fn new() -> Self {
349 Self::default()
350 }
351
352 pub fn builder<'schema, 'errors>(
375 schema: Option<&'schema Valid<Schema>>,
376 errors: &'errors mut DiagnosticList,
377 ) -> from_ast::ExecutableDocumentBuilder<'schema, 'errors> {
378 from_ast::ExecutableDocumentBuilder::new(schema.map(|s| s.as_ref()), errors)
379 }
380
381 #[allow(clippy::result_large_err)] pub fn parse(
389 schema: &Valid<Schema>,
390 source_text: impl Into<String>,
391 path: impl AsRef<Path>,
392 ) -> Result<Self, WithErrors<Self>> {
393 Parser::new().parse_executable(schema, source_text, path)
394 }
395
396 #[allow(clippy::result_large_err)] pub fn parse_and_validate(
400 schema: &Valid<Schema>,
401 source_text: impl Into<String>,
402 path: impl AsRef<Path>,
403 ) -> Result<Valid<Self>, WithErrors<Self>> {
404 let (doc, mut errors) = Parser::new().parse_executable_inner(schema, source_text, path);
405 Arc::make_mut(&mut errors.sources)
406 .extend(schema.sources.iter().map(|(k, v)| (*k, v.clone())));
407 validation::validate_executable_document(&mut errors, schema, &doc);
408 errors.into_valid_result(doc)
409 }
410
411 #[allow(clippy::result_large_err)] pub fn validate(self, schema: &Valid<Schema>) -> Result<Valid<Self>, WithErrors<Self>> {
413 let mut sources = IndexMap::clone(&schema.sources);
414 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
415 let mut errors = DiagnosticList::new(Arc::new(sources));
416 validation::validate_executable_document(&mut errors, schema, &self);
417 errors.into_valid_result(self)
418 }
419
420 serialize_method!();
421}
422
423impl Eq for ExecutableDocument {}
424
425impl PartialEq for ExecutableDocument {
427 fn eq(&self, other: &Self) -> bool {
428 let Self {
429 sources: _,
430 operations,
431 fragments,
432 } = self;
433 *operations == other.operations && *fragments == other.fragments
434 }
435}
436
437impl OperationMap {
438 pub fn from_one(operation: impl Into<Node<Operation>>) -> Self {
440 let mut map = Self::default();
441 map.insert(operation);
442 map
443 }
444
445 pub fn is_empty(&self) -> bool {
446 self.anonymous.is_none() && self.named.is_empty()
447 }
448
449 pub fn len(&self) -> usize {
450 self.anonymous.is_some() as usize + self.named.len()
451 }
452
453 pub fn iter(&self) -> impl Iterator<Item = &'_ Node<Operation>> {
455 self.anonymous
456 .as_ref()
457 .into_iter()
458 .chain(self.named.values())
459 }
460
461 pub fn get(&self, name_request: Option<&str>) -> Result<&Node<Operation>, RequestError> {
472 if let Some(name) = name_request {
473 self.named
475 .get(name)
476 .ok_or_else(|| format!("No operation named '{name}'"))
477 } else {
478 if let Some(op) = &self.anonymous {
480 self.named.is_empty().then_some(op)
482 } else {
483 self.named
485 .values()
486 .next()
487 .and_then(|op| (self.named.len() == 1).then_some(op))
488 }
489 .ok_or_else(|| {
490 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
491 })
492 }
493 .map_err(|message| RequestError {
494 message,
495 location: None,
496 is_suspected_validation_bug: false,
497 })
498 }
499
500 pub fn get_mut(&mut self, name_request: Option<&str>) -> Result<&mut Operation, RequestError> {
502 if let Some(name) = name_request {
503 self.named
505 .get_mut(name)
506 .ok_or_else(|| format!("No operation named '{name}'"))
507 } else {
508 if let Some(op) = &mut self.anonymous {
510 self.named.is_empty().then_some(op)
512 } else {
513 let len = self.named.len();
515 self.named
516 .values_mut()
517 .next()
518 .and_then(|op| (len == 1).then_some(op))
519 }
520 .ok_or_else(|| {
521 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
522 })
523 }
524 .map(Node::make_mut)
525 .map_err(|message| RequestError {
526 message,
527 location: None,
528 is_suspected_validation_bug: false,
529 })
530 }
531
532 pub fn insert(&mut self, operation: impl Into<Node<Operation>>) -> Option<Node<Operation>> {
535 let operation = operation.into();
536 if let Some(name) = &operation.name {
537 self.named.insert(name.clone(), operation)
538 } else {
539 self.anonymous.replace(operation)
540 }
541 }
542}
543
544impl Operation {
545 pub fn object_type(&self) -> &NamedType {
547 &self.selection_set.ty
548 }
549
550 pub fn is_query(&self) -> bool {
552 self.operation_type == OperationType::Query
553 }
554
555 pub fn is_mutation(&self) -> bool {
557 self.operation_type == OperationType::Mutation
558 }
559
560 pub fn is_subscription(&self) -> bool {
562 self.operation_type == OperationType::Subscription
563 }
564
565 pub fn is_introspection(&self, document: &ExecutableDocument) -> bool {
568 self.is_query()
569 && self
570 .root_fields(document)
571 .all(|field| matches!(field.name.as_str(), "__type" | "__schema" | "__typename"))
572 }
573
574 pub fn root_fields<'doc>(
589 &'doc self,
590 document: &'doc ExecutableDocument,
591 ) -> impl Iterator<Item = &'doc Node<Field>> {
592 self.selection_set.root_fields(document)
593 }
594
595 pub fn all_fields<'doc>(
608 &'doc self,
609 document: &'doc ExecutableDocument,
610 ) -> impl Iterator<Item = &'doc Node<Field>> {
611 self.selection_set.all_fields(document)
612 }
613
614 serialize_method!();
615}
616
617impl Fragment {
618 pub fn type_condition(&self) -> &NamedType {
619 &self.selection_set.ty
620 }
621
622 serialize_method!();
623}
624
625impl SelectionSet {
626 pub fn new(ty: NamedType) -> Self {
628 Self {
629 ty,
630 selections: Vec::new(),
631 }
632 }
633
634 pub fn is_empty(&self) -> bool {
635 self.selections.is_empty()
636 }
637
638 pub fn push(&mut self, selection: impl Into<Selection>) {
639 self.selections.push(selection.into())
640 }
641
642 pub fn extend(&mut self, selections: impl IntoIterator<Item = impl Into<Selection>>) {
643 self.selections
644 .extend(selections.into_iter().map(|sel| sel.into()))
645 }
646
647 pub fn new_field<'schema>(
652 &self,
653 schema: &'schema Schema,
654 name: Name,
655 ) -> Result<Field, schema::FieldLookupError<'schema>> {
656 let definition = schema.type_field(&self.ty, &name)?.node.clone();
657 Ok(Field::new(name, definition))
658 }
659
660 pub fn new_inline_fragment(&self, opt_type_condition: Option<NamedType>) -> InlineFragment {
662 if let Some(type_condition) = opt_type_condition {
663 InlineFragment::with_type_condition(type_condition)
664 } else {
665 InlineFragment::without_type_condition(self.ty.clone())
666 }
667 }
668
669 pub fn new_fragment_spread(&self, fragment_name: Name) -> FragmentSpread {
671 FragmentSpread::new(fragment_name)
672 }
673
674 pub fn fields(&self) -> impl Iterator<Item = &Node<Field>> {
678 self.selections.iter().filter_map(|sel| sel.as_field())
679 }
680
681 pub fn root_fields<'doc>(
696 &'doc self,
697 document: &'doc ExecutableDocument,
698 ) -> impl Iterator<Item = &'doc Node<Field>> {
699 let mut stack = vec![self.selections.iter()];
700 let mut fragments_seen = HashSet::default();
701 std::iter::from_fn(move || {
702 while let Some(selection_set_iter) = stack.last_mut() {
703 match selection_set_iter.next() {
704 Some(Selection::Field(field)) => {
705 return Some(field);
708 }
709 Some(Selection::InlineFragment(inline)) => {
710 stack.push(inline.selection_set.selections.iter())
711 }
712 Some(Selection::FragmentSpread(spread)) => {
713 if let Some(def) = document.fragments.get(&spread.fragment_name) {
714 let new = fragments_seen.insert(&spread.fragment_name);
715 if new {
716 stack.push(def.selection_set.selections.iter())
717 }
718 } else {
719 }
722 }
723 None => {
724 stack.pop();
727 }
728 }
729 }
730 None
731 })
732 }
733
734 pub fn all_fields<'doc>(
747 &'doc self,
748 document: &'doc ExecutableDocument,
749 ) -> impl Iterator<Item = &'doc Node<Field>> {
750 let mut stack = vec![self.selections.iter()];
751 let mut fragments_seen = HashSet::default();
752 std::iter::from_fn(move || {
753 while let Some(selection_set_iter) = stack.last_mut() {
754 match selection_set_iter.next() {
755 Some(Selection::Field(field)) => {
756 if !field.selection_set.is_empty() {
757 stack.push(field.selection_set.selections.iter())
759 }
760 return Some(field);
762 }
763 Some(Selection::InlineFragment(inline)) => {
764 stack.push(inline.selection_set.selections.iter())
765 }
766 Some(Selection::FragmentSpread(spread)) => {
767 if let Some(def) = document.fragments.get(&spread.fragment_name) {
768 let new = fragments_seen.insert(&spread.fragment_name);
769 if new {
770 stack.push(def.selection_set.selections.iter())
771 }
772 } else {
773 }
776 }
777 None => {
778 stack.pop();
781 }
782 }
783 }
784 None
785 })
786 }
787
788 serialize_method!();
789}
790
791impl Selection {
792 pub fn directives(&self) -> &DirectiveList {
793 match self {
794 Self::Field(sel) => &sel.directives,
795 Self::FragmentSpread(sel) => &sel.directives,
796 Self::InlineFragment(sel) => &sel.directives,
797 }
798 }
799
800 pub fn as_field(&self) -> Option<&Node<Field>> {
801 if let Self::Field(field) = self {
802 Some(field)
803 } else {
804 None
805 }
806 }
807
808 pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
809 if let Self::InlineFragment(inline) = self {
810 Some(inline)
811 } else {
812 None
813 }
814 }
815
816 pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
817 if let Self::FragmentSpread(spread) = self {
818 Some(spread)
819 } else {
820 None
821 }
822 }
823
824 serialize_method!();
825}
826
827impl From<Node<Field>> for Selection {
828 fn from(node: Node<Field>) -> Self {
829 Self::Field(node)
830 }
831}
832
833impl From<Node<InlineFragment>> for Selection {
834 fn from(node: Node<InlineFragment>) -> Self {
835 Self::InlineFragment(node)
836 }
837}
838
839impl From<Node<FragmentSpread>> for Selection {
840 fn from(node: Node<FragmentSpread>) -> Self {
841 Self::FragmentSpread(node)
842 }
843}
844
845impl From<Field> for Selection {
846 fn from(value: Field) -> Self {
847 Self::Field(Node::new(value))
848 }
849}
850
851impl From<InlineFragment> for Selection {
852 fn from(value: InlineFragment) -> Self {
853 Self::InlineFragment(Node::new(value))
854 }
855}
856
857impl From<FragmentSpread> for Selection {
858 fn from(value: FragmentSpread) -> Self {
859 Self::FragmentSpread(Node::new(value))
860 }
861}
862
863impl Field {
864 pub fn new(name: Name, definition: Node<schema::FieldDefinition>) -> Self {
868 let selection_set = SelectionSet::new(definition.ty.inner_named_type().clone());
869 Field {
870 definition,
871 alias: None,
872 name,
873 arguments: Vec::new(),
874 directives: DirectiveList::new(),
875 selection_set,
876 }
877 }
878
879 pub fn with_alias(mut self, alias: Name) -> Self {
880 self.alias = Some(alias);
881 self
882 }
883
884 pub fn with_opt_alias(mut self, alias: Option<Name>) -> Self {
885 self.alias = alias;
886 self
887 }
888
889 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
890 self.directives.push(directive.into());
891 self
892 }
893
894 pub fn with_directives(
895 mut self,
896 directives: impl IntoIterator<Item = Node<Directive>>,
897 ) -> Self {
898 self.directives.extend(directives);
899 self
900 }
901
902 pub fn with_argument(mut self, name: Name, value: impl Into<Node<Value>>) -> Self {
903 self.arguments.push((name, value).into());
904 self
905 }
906
907 pub fn with_arguments(mut self, arguments: impl IntoIterator<Item = Node<Argument>>) -> Self {
908 self.arguments.extend(arguments);
909 self
910 }
911
912 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
913 self.selection_set.push(selection);
914 self
915 }
916
917 pub fn with_selections(
918 mut self,
919 selections: impl IntoIterator<Item = impl Into<Selection>>,
920 ) -> Self {
921 self.selection_set.extend(selections);
922 self
923 }
924
925 pub fn response_key(&self) -> &Name {
927 self.alias.as_ref().unwrap_or(&self.name)
928 }
929
930 pub fn ty(&self) -> &Type {
932 &self.definition.ty
933 }
934
935 pub fn inner_type_def<'a>(&self, schema: &'a Schema) -> Option<&'a schema::ExtendedType> {
939 schema.types.get(self.ty().inner_named_type())
940 }
941
942 pub fn argument_by_name(&self, name: &str) -> Result<&Node<Value>, ArgumentByNameError> {
945 Argument::argument_by_name(&self.arguments, name, || {
946 self.definition
947 .argument_by_name(name)
948 .ok_or(ArgumentByNameError::NoSuchArgument)
949 })
950 }
951
952 pub fn specified_argument_by_name(&self, name: &str) -> Option<&Node<Value>> {
959 Argument::specified_argument_by_name(&self.arguments, name)
960 }
961
962 serialize_method!();
963}
964
965impl InlineFragment {
966 pub fn with_type_condition(type_condition: NamedType) -> Self {
967 let selection_set = SelectionSet::new(type_condition.clone());
968 Self {
969 type_condition: Some(type_condition),
970 directives: DirectiveList::new(),
971 selection_set,
972 }
973 }
974
975 pub fn without_type_condition(parent_selection_set_type: NamedType) -> Self {
976 Self {
977 type_condition: None,
978 directives: DirectiveList::new(),
979 selection_set: SelectionSet::new(parent_selection_set_type),
980 }
981 }
982
983 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
984 self.directives.push(directive.into());
985 self
986 }
987
988 pub fn with_directives(
989 mut self,
990 directives: impl IntoIterator<Item = Node<Directive>>,
991 ) -> Self {
992 self.directives.extend(directives);
993 self
994 }
995
996 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
997 self.selection_set.push(selection);
998 self
999 }
1000
1001 pub fn with_selections(
1002 mut self,
1003 selections: impl IntoIterator<Item = impl Into<Selection>>,
1004 ) -> Self {
1005 self.selection_set.extend(selections);
1006 self
1007 }
1008
1009 serialize_method!();
1010}
1011
1012impl FragmentSpread {
1013 pub fn new(fragment_name: Name) -> Self {
1014 Self {
1015 fragment_name,
1016 directives: DirectiveList::new(),
1017 }
1018 }
1019
1020 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
1021 self.directives.push(directive.into());
1022 self
1023 }
1024
1025 pub fn with_directives(
1026 mut self,
1027 directives: impl IntoIterator<Item = Node<Directive>>,
1028 ) -> Self {
1029 self.directives.extend(directives);
1030 self
1031 }
1032
1033 pub fn fragment_def<'a>(&self, document: &'a ExecutableDocument) -> Option<&'a Node<Fragment>> {
1034 document.fragments.get(&self.fragment_name)
1035 }
1036
1037 serialize_method!();
1038}
1039
1040impl FieldSet {
1041 pub fn parse(
1048 schema: &Valid<Schema>,
1049 type_name: NamedType,
1050 source_text: impl Into<String>,
1051 path: impl AsRef<Path>,
1052 ) -> Result<FieldSet, WithErrors<FieldSet>> {
1053 Parser::new().parse_field_set(schema, type_name, source_text, path)
1054 }
1055
1056 pub fn parse_and_validate(
1059 schema: &Valid<Schema>,
1060 type_name: NamedType,
1061 source_text: impl Into<String>,
1062 path: impl AsRef<Path>,
1063 ) -> Result<Valid<Self>, WithErrors<Self>> {
1064 let (field_set, mut errors) =
1065 Parser::new().parse_field_set_inner(schema, type_name, source_text, path);
1066 validation::validate_field_set(&mut errors, schema, &field_set);
1067 errors.into_valid_result(field_set)
1068 }
1069
1070 pub fn validate(&self, schema: &Valid<Schema>) -> Result<(), DiagnosticList> {
1071 let mut sources = IndexMap::clone(&schema.sources);
1072 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
1073 let mut errors = DiagnosticList::new(Arc::new(sources));
1074 validation::validate_field_set(&mut errors, schema, self);
1075 errors.into_result()
1076 }
1077
1078 serialize_method!();
1079}
1080
1081impl fmt::Display for SelectionPath {
1082 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1083 match &self.root {
1084 ExecutableDefinitionName::AnonymousOperation(operation_type) => {
1085 write!(f, "{operation_type}")?
1086 }
1087 ExecutableDefinitionName::NamedOperation(operation_type, name) => {
1088 write!(f, "{operation_type} {name}")?
1089 }
1090 ExecutableDefinitionName::Fragment(name) => write!(f, "fragment {name}")?,
1091 }
1092 for name in &self.nested_fields {
1093 write!(f, " → {name}")?
1094 }
1095 Ok(())
1096 }
1097}