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