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