1use crate::ast;
52use crate::collections::eq_unique_by_name;
53use crate::collections::hash_unordered;
54use crate::collections::IndexMap;
55use crate::coordinate::FieldArgumentCoordinate;
56use crate::coordinate::TypeAttributeCoordinate;
57use crate::parser::Parser;
58use crate::parser::SourceMap;
59use crate::parser::SourceSpan;
60use crate::schema;
61use crate::validation::DiagnosticList;
62use crate::validation::Valid;
63use crate::validation::WithErrors;
64use crate::Node;
65use crate::Schema;
66use indexmap::map::Entry;
67use std::fmt;
68use std::path::Path;
69use std::sync::Arc;
70
71pub(crate) mod from_ast;
72mod serialize;
73pub(crate) mod validation;
74
75pub use self::from_ast::ExecutableDocumentBuilder;
76pub use crate::ast::Argument;
77use crate::ast::ArgumentByNameError;
78pub use crate::ast::Directive;
79pub use crate::ast::DirectiveList;
80pub use crate::ast::NamedType;
81pub use crate::ast::OperationType;
82pub use crate::ast::Type;
83pub use crate::ast::Value;
84pub use crate::ast::VariableDefinition;
85use crate::collections::HashSet;
86use crate::request::RequestError;
87pub use crate::Name;
88
89#[derive(Debug, Clone, Default)]
91pub struct ExecutableDocument {
92 pub sources: SourceMap,
97
98 pub operations: OperationMap,
99 pub fragments: FragmentMap,
100}
101
102#[derive(Debug, Clone, Default, PartialEq)]
104pub struct OperationMap {
105 pub anonymous: Option<Node<Operation>>,
106 pub named: IndexMap<Name, Node<Operation>>,
107}
108
109pub type FragmentMap = IndexMap<Name, Node<Fragment>>;
111
112#[derive(Debug, Clone)]
115pub struct FieldSet {
116 pub sources: SourceMap,
121
122 pub selection_set: SelectionSet,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
128pub struct Operation {
129 pub description: Option<Node<str>>,
130 pub operation_type: OperationType,
131 pub name: Option<Name>,
132 pub variables: Vec<Node<VariableDefinition>>,
133 pub directives: DirectiveList,
134 pub selection_set: SelectionSet,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct Fragment {
141 pub description: Option<Node<str>>,
142 pub name: Name,
143 pub directives: DirectiveList,
144 pub selection_set: SelectionSet,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Hash)]
150pub struct SelectionSet {
151 pub ty: NamedType,
152 pub selections: Vec<Selection>,
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
158pub enum Selection {
159 Field(Node<Field>),
160 FragmentSpread(Node<FragmentSpread>),
161 InlineFragment(Node<InlineFragment>),
162}
163
164#[derive(Debug, Clone, Eq)]
167pub struct Field {
168 pub definition: Node<schema::FieldDefinition>,
170 pub alias: Option<Name>,
171 pub name: Name,
172 pub arguments: Vec<Node<Argument>>,
173 pub directives: DirectiveList,
174 pub selection_set: SelectionSet,
175}
176
177impl PartialEq for Field {
178 fn eq(&self, other: &Self) -> bool {
179 self.definition == other.definition
180 && self.alias == other.alias
181 && self.name == other.name
182 && eq_unique_by_name(&self.arguments, &other.arguments, |a| &a.name)
183 && self.directives == other.directives
184 && self.selection_set == other.selection_set
185 }
186}
187
188impl std::hash::Hash for Field {
189 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
190 self.definition.hash(state);
191 self.alias.hash(state);
192 self.name.hash(state);
193 hash_unordered(self.arguments.iter(), state, self.arguments.len());
194 self.directives.hash(state);
195 self.selection_set.hash(state);
196 }
197}
198
199#[derive(Debug, Clone, PartialEq, Eq, Hash)]
202pub struct FragmentSpread {
203 pub fragment_name: Name,
204 pub directives: DirectiveList,
205}
206
207#[derive(Debug, Clone, PartialEq, Eq, Hash)]
210pub struct InlineFragment {
211 pub type_condition: Option<NamedType>,
212 pub directives: DirectiveList,
213 pub selection_set: SelectionSet,
214}
215
216#[derive(thiserror::Error, Debug, Clone)]
219pub(crate) enum BuildError {
220 #[error("an executable document must not contain {describe}")]
221 TypeSystemDefinition {
222 name: Option<Name>,
223 describe: &'static str,
224 },
225
226 #[error("anonymous operation cannot be selected when the document contains other operations")]
227 AmbiguousAnonymousOperation,
228
229 #[error(
230 "the operation `{name_at_previous_location}` is defined multiple times in the document"
231 )]
232 OperationNameCollision { name_at_previous_location: Name },
233
234 #[error(
235 "the fragment `{name_at_previous_location}` is defined multiple times in the document"
236 )]
237 FragmentNameCollision { name_at_previous_location: Name },
238
239 #[error("`{operation_type}` root operation type is not defined")]
240 UndefinedRootOperation { operation_type: &'static str },
241
242 #[error(
243 "type condition `{type_name}` of fragment `{fragment_name}` \
244 is not a type defined in the schema"
245 )]
246 UndefinedTypeInNamedFragmentTypeCondition {
247 type_name: NamedType,
248 fragment_name: Name,
249 },
250
251 #[error("type condition `{type_name}` of inline fragment is not a type defined in the schema")]
252 UndefinedTypeInInlineFragmentTypeCondition {
253 type_name: NamedType,
254 path: SelectionPath,
255 },
256
257 #[error("field selection of scalar type `{type_name}` must not have subselections")]
258 SubselectionOnScalarType {
259 type_name: NamedType,
260 path: SelectionPath,
261 },
262
263 #[error("field selection of enum type `{type_name}` must not have subselections")]
264 SubselectionOnEnumType {
265 type_name: NamedType,
266 path: SelectionPath,
267 },
268
269 #[error("type `{type_name}` does not have a field `{field_name}`")]
270 UndefinedField {
271 type_name: NamedType,
272 field_name: Name,
273 path: SelectionPath,
274 },
275
276 #[error(
278 "{} can only have one root field",
279 subscription_name_or_anonymous(name)
280 )]
281 SubscriptionUsesMultipleFields {
282 name: Option<Name>,
283 fields: Vec<Name>,
284 },
285
286 #[error(
287 "{} can not have an introspection field as a root field",
288 subscription_name_or_anonymous(name)
289 )]
290 SubscriptionUsesIntrospection {
291 name: Option<Name>,
293 field: Name,
295 },
296 #[error(
297 "{} can not specify @skip or @include on root fields",
298 subscription_name_or_anonymous(name)
299 )]
300 SubscriptionUsesConditionalSelection {
301 name: Option<Name>,
303 },
304
305 #[error("`@defer` label `{label}` is not unique within the document")]
306 DuplicateDeferLabel {
307 label: String,
308 original_location: Option<SourceSpan>,
309 },
310
311 #[error("`@defer` label argument must be a static String, not a variable")]
312 DeferLabelMustNotBeVariable,
313
314 #[error(
315 "`@defer` is not allowed on root selections of {} operations",
316 operation_type.name()
317 )]
318 DeferOnRootMutationOrSubscriptionField { operation_type: OperationType },
319
320 #[error("`@defer` in a subscription operation must be disabled with an `if` argument")]
321 DeferInSubscriptionMustBeConditional,
322
323 #[error("{0}")]
324 ConflictingFieldType(Box<ConflictingFieldType>),
325 #[error("{0}")]
326 ConflictingFieldArgument(Box<ConflictingFieldArgument>),
327 #[error("{0}")]
328 ConflictingFieldName(Box<ConflictingFieldName>),
329}
330
331#[derive(thiserror::Error, Debug, Clone)]
332#[error("operation must not select different types using the same name `{alias}`")]
333pub(crate) struct ConflictingFieldType {
334 pub(crate) alias: Name,
336 pub(crate) original_location: Option<SourceSpan>,
337 pub(crate) original_coordinate: TypeAttributeCoordinate,
338 pub(crate) original_type: Type,
339 pub(crate) conflicting_location: Option<SourceSpan>,
340 pub(crate) conflicting_coordinate: TypeAttributeCoordinate,
341 pub(crate) conflicting_type: Type,
342}
343
344#[derive(thiserror::Error, Debug, Clone)]
345#[error("operation must not provide conflicting field arguments for the same name `{alias}`")]
346pub(crate) struct ConflictingFieldArgument {
347 pub(crate) alias: Name,
349 pub(crate) original_location: Option<SourceSpan>,
350 pub(crate) original_coordinate: FieldArgumentCoordinate,
351 pub(crate) original_value: Option<Value>,
352 pub(crate) conflicting_location: Option<SourceSpan>,
353 pub(crate) conflicting_coordinate: FieldArgumentCoordinate,
354 pub(crate) conflicting_value: Option<Value>,
355}
356
357#[derive(thiserror::Error, Debug, Clone)]
358#[error("cannot select different fields into the same alias `{alias}`")]
359pub(crate) struct ConflictingFieldName {
360 pub(crate) alias: Name,
362 pub(crate) original_location: Option<SourceSpan>,
363 pub(crate) original_selection: TypeAttributeCoordinate,
364 pub(crate) conflicting_location: Option<SourceSpan>,
365 pub(crate) conflicting_selection: TypeAttributeCoordinate,
366}
367
368fn subscription_name_or_anonymous(name: &Option<Name>) -> impl std::fmt::Display + '_ {
369 crate::validation::diagnostics::NameOrAnon {
370 name: name.as_ref(),
371 if_some_prefix: "subscription",
372 if_none: "anonymous subscription",
373 }
374}
375
376#[derive(Debug, Clone, PartialEq, Eq)]
377pub(crate) struct SelectionPath {
378 pub(crate) root: ExecutableDefinitionName,
379 pub(crate) nested_fields: Vec<Name>,
380}
381
382#[derive(Debug, Clone, PartialEq, Eq)]
384pub(crate) enum ExecutableDefinitionName {
385 AnonymousOperation(ast::OperationType),
386 NamedOperation(ast::OperationType, Name),
387 Fragment(Name),
388}
389
390impl ExecutableDocument {
391 pub fn new() -> Self {
393 Self::default()
394 }
395
396 pub fn builder<'schema, 'errors>(
419 schema: Option<&'schema Valid<Schema>>,
420 errors: &'errors mut DiagnosticList,
421 ) -> from_ast::ExecutableDocumentBuilder<'schema, 'errors> {
422 from_ast::ExecutableDocumentBuilder::new(schema.map(|s| s.as_ref()), errors)
423 }
424
425 #[allow(clippy::result_large_err)] pub fn parse(
433 schema: &Valid<Schema>,
434 source_text: impl Into<String>,
435 path: impl AsRef<Path>,
436 ) -> Result<Self, WithErrors<Self>> {
437 Parser::new().parse_executable(schema, source_text, path)
438 }
439
440 #[allow(clippy::result_large_err)] pub fn parse_and_validate(
444 schema: &Valid<Schema>,
445 source_text: impl Into<String>,
446 path: impl AsRef<Path>,
447 ) -> Result<Valid<Self>, WithErrors<Self>> {
448 let (doc, mut errors) = Parser::new().parse_executable_inner(schema, source_text, path);
449 Arc::make_mut(&mut errors.sources)
450 .extend(schema.sources.iter().map(|(k, v)| (*k, v.clone())));
451 validation::validate_executable_document(&mut errors, schema, &doc);
452 errors.into_valid_result(doc)
453 }
454
455 #[allow(clippy::result_large_err)] pub fn validate(self, schema: &Valid<Schema>) -> Result<Valid<Self>, WithErrors<Self>> {
457 let mut sources = IndexMap::clone(&schema.sources);
458 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
459 let mut errors = DiagnosticList::new(Arc::new(sources));
460 validation::validate_executable_document(&mut errors, schema, &self);
461 errors.into_valid_result(self)
462 }
463
464 serialize_method!();
465}
466
467impl Eq for ExecutableDocument {}
468
469impl PartialEq for ExecutableDocument {
471 fn eq(&self, other: &Self) -> bool {
472 let Self {
473 sources: _,
474 operations,
475 fragments,
476 } = self;
477 *operations == other.operations && *fragments == other.fragments
478 }
479}
480
481impl OperationMap {
482 pub fn from_one(operation: impl Into<Node<Operation>>) -> Self {
484 let mut map = Self::default();
485 map.insert(operation);
486 map
487 }
488
489 pub fn is_empty(&self) -> bool {
490 self.anonymous.is_none() && self.named.is_empty()
491 }
492
493 pub fn len(&self) -> usize {
494 self.anonymous.is_some() as usize + self.named.len()
495 }
496
497 pub fn iter(&self) -> impl Iterator<Item = &'_ Node<Operation>> {
499 self.anonymous
500 .as_ref()
501 .into_iter()
502 .chain(self.named.values())
503 }
504
505 pub fn get(&self, name_request: Option<&str>) -> Result<&Node<Operation>, RequestError> {
516 if let Some(name) = name_request {
517 self.named
519 .get(name)
520 .ok_or_else(|| format!("No operation named '{name}'"))
521 } else {
522 if let Some(op) = &self.anonymous {
524 self.named.is_empty().then_some(op)
526 } else {
527 self.named
529 .values()
530 .next()
531 .and_then(|op| (self.named.len() == 1).then_some(op))
532 }
533 .ok_or_else(|| {
534 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
535 })
536 }
537 .map_err(|message| RequestError {
538 message,
539 location: None,
540 is_suspected_validation_bug: false,
541 })
542 }
543
544 pub fn get_mut(&mut self, name_request: Option<&str>) -> Result<&mut Operation, RequestError> {
546 if let Some(name) = name_request {
547 self.named
549 .get_mut(name)
550 .ok_or_else(|| format!("No operation named '{name}'"))
551 } else {
552 if let Some(op) = &mut self.anonymous {
554 self.named.is_empty().then_some(op)
556 } else {
557 let len = self.named.len();
559 self.named
560 .values_mut()
561 .next()
562 .and_then(|op| (len == 1).then_some(op))
563 }
564 .ok_or_else(|| {
565 "Ambiguous request: multiple operations but no specified `operationName`".to_owned()
566 })
567 }
568 .map(Node::make_mut)
569 .map_err(|message| RequestError {
570 message,
571 location: None,
572 is_suspected_validation_bug: false,
573 })
574 }
575
576 pub fn insert(&mut self, operation: impl Into<Node<Operation>>) -> Option<Node<Operation>> {
579 let operation = operation.into();
580 if let Some(name) = &operation.name {
581 self.named.insert(name.clone(), operation)
582 } else {
583 self.anonymous.replace(operation)
584 }
585 }
586}
587
588impl Operation {
589 pub fn object_type(&self) -> &NamedType {
591 &self.selection_set.ty
592 }
593
594 pub fn is_query(&self) -> bool {
596 self.operation_type == OperationType::Query
597 }
598
599 pub fn is_mutation(&self) -> bool {
601 self.operation_type == OperationType::Mutation
602 }
603
604 pub fn is_subscription(&self) -> bool {
606 self.operation_type == OperationType::Subscription
607 }
608
609 pub fn is_introspection(&self, document: &ExecutableDocument) -> bool {
612 self.is_query()
613 && self
614 .root_fields(document)
615 .all(|field| matches!(field.name.as_str(), "__type" | "__schema" | "__typename"))
616 }
617
618 pub fn root_fields<'doc>(
633 &'doc self,
634 document: &'doc ExecutableDocument,
635 ) -> impl Iterator<Item = &'doc Node<Field>> {
636 self.selection_set.root_fields(document)
637 }
638
639 pub fn all_fields<'doc>(
652 &'doc self,
653 document: &'doc ExecutableDocument,
654 ) -> impl Iterator<Item = &'doc Node<Field>> {
655 self.selection_set.all_fields(document)
656 }
657
658 serialize_method!();
659}
660
661impl Fragment {
662 pub fn type_condition(&self) -> &NamedType {
663 &self.selection_set.ty
664 }
665
666 serialize_method!();
667}
668
669impl SelectionSet {
670 pub fn new(ty: NamedType) -> Self {
672 Self {
673 ty,
674 selections: Vec::new(),
675 }
676 }
677
678 pub fn is_empty(&self) -> bool {
679 self.selections.is_empty()
680 }
681
682 pub fn push(&mut self, selection: impl Into<Selection>) {
683 self.selections.push(selection.into())
684 }
685
686 pub fn extend(&mut self, selections: impl IntoIterator<Item = impl Into<Selection>>) {
687 self.selections
688 .extend(selections.into_iter().map(|sel| sel.into()))
689 }
690
691 pub fn new_field<'schema>(
696 &self,
697 schema: &'schema Schema,
698 name: Name,
699 ) -> Result<Field, schema::FieldLookupError<'schema>> {
700 let definition = schema.type_field(&self.ty, &name)?.clone();
701 Ok(Field::new(name, definition))
702 }
703
704 pub fn new_inline_fragment(&self, opt_type_condition: Option<NamedType>) -> InlineFragment {
706 if let Some(type_condition) = opt_type_condition {
707 InlineFragment::with_type_condition(type_condition)
708 } else {
709 InlineFragment::without_type_condition(self.ty.clone())
710 }
711 }
712
713 pub fn new_fragment_spread(&self, fragment_name: Name) -> FragmentSpread {
715 FragmentSpread::new(fragment_name)
716 }
717
718 pub fn fields(&self) -> impl Iterator<Item = &Node<Field>> {
722 self.selections.iter().filter_map(|sel| sel.as_field())
723 }
724
725 pub fn root_fields<'doc>(
740 &'doc self,
741 document: &'doc ExecutableDocument,
742 ) -> impl Iterator<Item = &'doc Node<Field>> {
743 let mut stack = vec![self.selections.iter()];
744 let mut fragments_seen = HashSet::default();
745 std::iter::from_fn(move || {
746 while let Some(selection_set_iter) = stack.last_mut() {
747 match selection_set_iter.next() {
748 Some(Selection::Field(field)) => {
749 return Some(field);
752 }
753 Some(Selection::InlineFragment(inline)) => {
754 stack.push(inline.selection_set.selections.iter())
755 }
756 Some(Selection::FragmentSpread(spread)) => {
757 if let Some(def) = document.fragments.get(&spread.fragment_name) {
758 let new = fragments_seen.insert(&spread.fragment_name);
759 if new {
760 stack.push(def.selection_set.selections.iter())
761 }
762 } else {
763 }
766 }
767 None => {
768 stack.pop();
771 }
772 }
773 }
774 None
775 })
776 }
777
778 pub fn all_fields<'doc>(
791 &'doc self,
792 document: &'doc ExecutableDocument,
793 ) -> impl Iterator<Item = &'doc Node<Field>> {
794 let mut stack = vec![self.selections.iter()];
795 let mut fragments_seen = HashSet::default();
796 std::iter::from_fn(move || {
797 while let Some(selection_set_iter) = stack.last_mut() {
798 match selection_set_iter.next() {
799 Some(Selection::Field(field)) => {
800 if !field.selection_set.is_empty() {
801 stack.push(field.selection_set.selections.iter())
803 }
804 return Some(field);
806 }
807 Some(Selection::InlineFragment(inline)) => {
808 stack.push(inline.selection_set.selections.iter())
809 }
810 Some(Selection::FragmentSpread(spread)) => {
811 if let Some(def) = document.fragments.get(&spread.fragment_name) {
812 let new = fragments_seen.insert(&spread.fragment_name);
813 if new {
814 stack.push(def.selection_set.selections.iter())
815 }
816 } else {
817 }
820 }
821 None => {
822 stack.pop();
825 }
826 }
827 }
828 None
829 })
830 }
831
832 serialize_method!();
833}
834
835impl Selection {
836 pub fn directives(&self) -> &DirectiveList {
837 match self {
838 Self::Field(sel) => &sel.directives,
839 Self::FragmentSpread(sel) => &sel.directives,
840 Self::InlineFragment(sel) => &sel.directives,
841 }
842 }
843
844 pub fn as_field(&self) -> Option<&Node<Field>> {
845 if let Self::Field(field) = self {
846 Some(field)
847 } else {
848 None
849 }
850 }
851
852 pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
853 if let Self::InlineFragment(inline) = self {
854 Some(inline)
855 } else {
856 None
857 }
858 }
859
860 pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
861 if let Self::FragmentSpread(spread) = self {
862 Some(spread)
863 } else {
864 None
865 }
866 }
867
868 serialize_method!();
869}
870
871impl From<Node<Field>> for Selection {
872 fn from(node: Node<Field>) -> Self {
873 Self::Field(node)
874 }
875}
876
877impl From<Node<InlineFragment>> for Selection {
878 fn from(node: Node<InlineFragment>) -> Self {
879 Self::InlineFragment(node)
880 }
881}
882
883impl From<Node<FragmentSpread>> for Selection {
884 fn from(node: Node<FragmentSpread>) -> Self {
885 Self::FragmentSpread(node)
886 }
887}
888
889impl From<Field> for Selection {
890 fn from(value: Field) -> Self {
891 Self::Field(Node::new(value))
892 }
893}
894
895impl From<InlineFragment> for Selection {
896 fn from(value: InlineFragment) -> Self {
897 Self::InlineFragment(Node::new(value))
898 }
899}
900
901impl From<FragmentSpread> for Selection {
902 fn from(value: FragmentSpread) -> Self {
903 Self::FragmentSpread(Node::new(value))
904 }
905}
906
907impl Field {
908 pub fn new(name: Name, definition: Node<schema::FieldDefinition>) -> Self {
912 let selection_set = SelectionSet::new(definition.ty.inner_named_type().clone());
913 Field {
914 definition,
915 alias: None,
916 name,
917 arguments: Vec::new(),
918 directives: DirectiveList::new(),
919 selection_set,
920 }
921 }
922
923 pub fn with_alias(mut self, alias: Name) -> Self {
924 self.alias = Some(alias);
925 self
926 }
927
928 pub fn with_opt_alias(mut self, alias: Option<Name>) -> Self {
929 self.alias = alias;
930 self
931 }
932
933 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
934 self.directives.push(directive.into());
935 self
936 }
937
938 pub fn with_directives(
939 mut self,
940 directives: impl IntoIterator<Item = Node<Directive>>,
941 ) -> Self {
942 self.directives.extend(directives);
943 self
944 }
945
946 pub fn with_argument(mut self, name: Name, value: impl Into<Node<Value>>) -> Self {
947 self.arguments.push((name, value).into());
948 self
949 }
950
951 pub fn with_arguments(mut self, arguments: impl IntoIterator<Item = Node<Argument>>) -> Self {
952 self.arguments.extend(arguments);
953 self
954 }
955
956 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
957 self.selection_set.push(selection);
958 self
959 }
960
961 pub fn with_selections(
962 mut self,
963 selections: impl IntoIterator<Item = impl Into<Selection>>,
964 ) -> Self {
965 self.selection_set.extend(selections);
966 self
967 }
968
969 pub fn response_name(&self) -> &Name {
971 self.alias.as_ref().unwrap_or(&self.name)
972 }
973
974 pub fn ty(&self) -> &Type {
976 &self.definition.ty
977 }
978
979 pub fn inner_type_def<'a>(&self, schema: &'a Schema) -> Option<&'a schema::ExtendedType> {
983 schema.types.get(self.ty().inner_named_type())
984 }
985
986 pub fn argument_by_name(&self, name: &str) -> Result<&Node<Value>, ArgumentByNameError> {
989 Argument::argument_by_name(&self.arguments, name, || {
990 self.definition
991 .argument_by_name(name)
992 .ok_or(ArgumentByNameError::NoSuchArgument)
993 })
994 }
995
996 pub fn specified_argument_by_name(&self, name: &str) -> Option<&Node<Value>> {
1003 Argument::specified_argument_by_name(&self.arguments, name)
1004 }
1005
1006 serialize_method!();
1007}
1008
1009impl InlineFragment {
1010 pub fn with_type_condition(type_condition: NamedType) -> Self {
1011 let selection_set = SelectionSet::new(type_condition.clone());
1012 Self {
1013 type_condition: Some(type_condition),
1014 directives: DirectiveList::new(),
1015 selection_set,
1016 }
1017 }
1018
1019 pub fn without_type_condition(parent_selection_set_type: NamedType) -> Self {
1020 Self {
1021 type_condition: None,
1022 directives: DirectiveList::new(),
1023 selection_set: SelectionSet::new(parent_selection_set_type),
1024 }
1025 }
1026
1027 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
1028 self.directives.push(directive.into());
1029 self
1030 }
1031
1032 pub fn with_directives(
1033 mut self,
1034 directives: impl IntoIterator<Item = Node<Directive>>,
1035 ) -> Self {
1036 self.directives.extend(directives);
1037 self
1038 }
1039
1040 pub fn with_selection(mut self, selection: impl Into<Selection>) -> Self {
1041 self.selection_set.push(selection);
1042 self
1043 }
1044
1045 pub fn with_selections(
1046 mut self,
1047 selections: impl IntoIterator<Item = impl Into<Selection>>,
1048 ) -> Self {
1049 self.selection_set.extend(selections);
1050 self
1051 }
1052
1053 serialize_method!();
1054}
1055
1056impl FragmentSpread {
1057 pub fn new(fragment_name: Name) -> Self {
1058 Self {
1059 fragment_name,
1060 directives: DirectiveList::new(),
1061 }
1062 }
1063
1064 pub fn with_directive(mut self, directive: impl Into<Node<Directive>>) -> Self {
1065 self.directives.push(directive.into());
1066 self
1067 }
1068
1069 pub fn with_directives(
1070 mut self,
1071 directives: impl IntoIterator<Item = Node<Directive>>,
1072 ) -> Self {
1073 self.directives.extend(directives);
1074 self
1075 }
1076
1077 pub fn fragment_def<'a>(&self, document: &'a ExecutableDocument) -> Option<&'a Node<Fragment>> {
1078 document.fragments.get(&self.fragment_name)
1079 }
1080
1081 serialize_method!();
1082}
1083
1084impl FieldSet {
1085 pub fn parse(
1092 schema: &Valid<Schema>,
1093 type_name: NamedType,
1094 source_text: impl Into<String>,
1095 path: impl AsRef<Path>,
1096 ) -> Result<FieldSet, WithErrors<FieldSet>> {
1097 Parser::new().parse_field_set(schema, type_name, source_text, path)
1098 }
1099
1100 pub fn parse_and_validate(
1103 schema: &Valid<Schema>,
1104 type_name: NamedType,
1105 source_text: impl Into<String>,
1106 path: impl AsRef<Path>,
1107 ) -> Result<Valid<Self>, WithErrors<Self>> {
1108 let (field_set, mut errors) =
1109 Parser::new().parse_field_set_inner(schema, type_name, source_text, path);
1110 validation::validate_field_set(&mut errors, schema, &field_set);
1111 errors.into_valid_result(field_set)
1112 }
1113
1114 pub fn validate(&self, schema: &Valid<Schema>) -> Result<(), DiagnosticList> {
1115 let mut sources = IndexMap::clone(&schema.sources);
1116 sources.extend(self.sources.iter().map(|(k, v)| (*k, v.clone())));
1117 let mut errors = DiagnosticList::new(Arc::new(sources));
1118 validation::validate_field_set(&mut errors, schema, self);
1119 errors.into_result()
1120 }
1121
1122 serialize_method!();
1123}
1124
1125impl fmt::Display for SelectionPath {
1126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1127 match &self.root {
1128 ExecutableDefinitionName::AnonymousOperation(operation_type) => {
1129 write!(f, "{operation_type}")?
1130 }
1131 ExecutableDefinitionName::NamedOperation(operation_type, name) => {
1132 write!(f, "{operation_type} {name}")?
1133 }
1134 ExecutableDefinitionName::Fragment(name) => write!(f, "fragment {name}")?,
1135 }
1136 for name in &self.nested_fields {
1137 write!(f, " → {name}")?
1138 }
1139 Ok(())
1140 }
1141}