1mod fields;
2
3use std::fmt::Debug;
4use std::fmt::Formatter;
5use std::iter;
6use std::sync::Arc;
7
8use apollo_compiler::Name;
9use apollo_compiler::Node;
10use apollo_compiler::Schema;
11use apollo_compiler::ast::Argument;
12use apollo_compiler::ast::Directive;
13use apollo_compiler::ast::DirectiveDefinition;
14use apollo_compiler::ast::DirectiveList;
15use apollo_compiler::ast::DirectiveLocation;
16use apollo_compiler::ast::EnumValueDefinition;
17use apollo_compiler::ast::FieldDefinition;
18use apollo_compiler::ast::NamedType;
19use apollo_compiler::ast::Type;
20use apollo_compiler::ast::Value;
21use apollo_compiler::collections::HashMap;
22use apollo_compiler::collections::IndexMap;
23use apollo_compiler::collections::IndexSet;
24use apollo_compiler::name;
25use apollo_compiler::schema::Component;
26use apollo_compiler::schema::EnumType;
27use apollo_compiler::schema::ExtendedType;
28use apollo_compiler::schema::Implementers;
29use apollo_compiler::schema::InputObjectType;
30use apollo_compiler::schema::InputValueDefinition;
31use apollo_compiler::schema::InterfaceType;
32use apollo_compiler::schema::ObjectType;
33use apollo_compiler::schema::ScalarType;
34use apollo_compiler::schema::UnionType;
35use apollo_compiler::ty;
36use apollo_compiler::validation::Valid;
37use indexmap::map::Entry::Occupied;
38use indexmap::map::Entry::Vacant;
39use indexmap::map::Iter;
40use itertools::Itertools;
41
42use crate::ValidFederationSubgraph;
43use crate::ValidFederationSubgraphs;
44use crate::error::FederationError;
45use crate::link::federation_spec_definition::FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC;
46use crate::link::federation_spec_definition::FEDERATION_FIELDS_ARGUMENT_NAME;
47use crate::link::federation_spec_definition::FEDERATION_FROM_ARGUMENT_NAME;
48use crate::link::federation_spec_definition::FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC;
49use crate::link::federation_spec_definition::FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC;
50use crate::link::federation_spec_definition::FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC;
51use crate::link::federation_spec_definition::FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME;
52use crate::link::federation_spec_definition::FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC;
53use crate::link::federation_spec_definition::FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC;
54use crate::link::inaccessible_spec_definition::INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC;
55use crate::link::inaccessible_spec_definition::InaccessibleSpecDefinition;
56use crate::link::join_spec_definition::EnumValue;
57use crate::link::join_spec_definition::JOIN_OVERRIDE_LABEL_ARGUMENT_NAME;
58use crate::link::metadata::LinksMetadata;
59use crate::link::spec::Identity;
60use crate::link::spec::Version;
61use crate::link::spec_definition::SpecDefinition;
62use crate::schema::ValidFederationSchema;
63use crate::subgraph::ValidSubgraph;
64
65type MergeWarning = String;
66type MergeError = String;
67
68struct Merger {
69 errors: Vec<MergeError>,
70 composition_hints: Vec<MergeWarning>,
71 needs_inaccessible: bool,
72 interface_objects: IndexSet<Name>,
73}
74
75pub struct MergeSuccess {
76 pub schema: Valid<Schema>,
77 pub composition_hints: Vec<MergeWarning>,
78}
79
80impl From<FederationError> for MergeFailure {
81 fn from(err: FederationError) -> Self {
82 MergeFailure {
87 schema: None,
88 errors: vec![err.to_string()],
89 composition_hints: vec![],
90 }
91 }
92}
93
94pub struct MergeFailure {
95 pub schema: Option<Box<Schema>>,
96 pub errors: Vec<MergeError>,
97 pub composition_hints: Vec<MergeWarning>,
98}
99
100impl Debug for MergeFailure {
101 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
102 f.debug_struct("MergeFailure")
103 .field("errors", &self.errors)
104 .field("composition_hints", &self.composition_hints)
105 .finish()
106 }
107}
108
109pub fn merge_subgraphs(subgraphs: Vec<&ValidSubgraph>) -> Result<MergeSuccess, MergeFailure> {
110 let mut merger = Merger::new();
111 let mut federation_subgraphs = ValidFederationSubgraphs::new();
112 for subgraph in subgraphs {
113 federation_subgraphs.add(ValidFederationSubgraph {
114 name: subgraph.name.clone(),
115 url: subgraph.url.clone(),
116 schema: ValidFederationSchema::new(subgraph.schema.clone())?,
117 })?;
118 }
119 merger.merge(federation_subgraphs)
120}
121
122pub fn merge_federation_subgraphs(
123 subgraphs: ValidFederationSubgraphs,
124) -> Result<MergeSuccess, MergeFailure> {
125 let mut merger = Merger::new();
126 merger.merge(subgraphs)
127}
128
129impl Merger {
130 fn new() -> Self {
131 Merger {
132 composition_hints: Vec::new(),
133 errors: Vec::new(),
134 needs_inaccessible: false,
135 interface_objects: IndexSet::default(),
136 }
137 }
138
139 fn merge(&mut self, subgraphs: ValidFederationSubgraphs) -> Result<MergeSuccess, MergeFailure> {
140 let mut subgraphs = subgraphs
141 .into_iter()
142 .map(|(_, subgraph)| subgraph)
143 .collect_vec();
144 subgraphs.sort_by(|s1, s2| s1.name.cmp(&s2.name));
145 let mut subgraphs_and_enum_values = Vec::new();
146 let mut enum_values = IndexSet::default();
147 for subgraph in &subgraphs {
148 let enum_value = match EnumValue::new(&subgraph.name) {
149 Ok(enum_value) => enum_value,
150 Err(err) => {
151 self.errors.push(err);
152 continue;
153 }
154 };
155
156 let enum_value = if enum_values.contains(&enum_value.to_string()) {
158 EnumValue::new(&format!("{}_{}", subgraph.name, enum_values.len()))
159 .expect("adding a suffix always works")
160 } else {
161 enum_value
162 };
163 enum_values.insert(enum_value.to_string());
164 subgraphs_and_enum_values.push((subgraph, enum_value))
165 }
166 if !self.errors.is_empty() {
167 return Err(MergeFailure {
168 schema: None,
169 composition_hints: self.composition_hints.to_owned(),
170 errors: self.errors.to_owned(),
171 });
172 }
173
174 let mut supergraph = Schema::new();
175 add_core_feature_link(&mut supergraph);
180 add_core_feature_join(&mut supergraph, &subgraphs_and_enum_values);
181
182 for (subgraph, subgraph_name) in &subgraphs_and_enum_values {
184 let sources = Arc::make_mut(&mut supergraph.sources);
185 for (key, source) in subgraph.schema.schema().sources.iter() {
186 sources.entry(*key).or_insert_with(|| source.clone());
187 }
188
189 self.merge_schema(&mut supergraph, subgraph);
190 let metadata = subgraph.schema.metadata();
193 let relevant_directives = DirectiveNames::for_metadata(&metadata);
194
195 for (type_name, ty) in &subgraph.schema.schema().types {
196 if ty.is_built_in() || !is_mergeable_type(type_name) {
197 continue;
199 }
200
201 match ty {
202 ExtendedType::Enum(value) => self.merge_enum_type(
203 &mut supergraph.types,
204 &relevant_directives,
205 subgraph_name,
206 type_name.clone(),
207 value,
208 ),
209 ExtendedType::InputObject(value) => self.merge_input_object_type(
210 &mut supergraph.types,
211 &relevant_directives,
212 subgraph_name,
213 type_name.clone(),
214 value,
215 ),
216 ExtendedType::Interface(value) => self.merge_interface_type(
217 &mut supergraph.types,
218 &relevant_directives,
219 subgraph_name,
220 type_name.clone(),
221 value,
222 ),
223 ExtendedType::Object(value) => self.merge_object_type(
224 &mut supergraph.types,
225 &relevant_directives,
226 subgraph_name,
227 type_name.clone(),
228 value,
229 ),
230 ExtendedType::Union(value) => self.merge_union_type(
231 &mut supergraph.types,
232 &relevant_directives,
233 subgraph_name,
234 type_name.clone(),
235 value,
236 ),
237 ExtendedType::Scalar(value) => {
238 if !value.is_built_in() {
239 self.merge_scalar_type(
240 &mut supergraph.types,
241 &relevant_directives,
242 subgraph_name.clone(),
243 type_name.clone(),
244 value,
245 );
246 }
247 }
248 }
249 }
250
251 for (_, directive) in subgraph.schema.schema().directive_definitions.iter() {
253 if is_executable_directive(directive) {
254 merge_directive(&mut supergraph.directive_definitions, directive);
255 }
256 }
257 }
258
259 let implementers_map = supergraph.implementers_map();
260 self.add_interface_object_fields(&mut supergraph.types, implementers_map)?;
261
262 if self.needs_inaccessible {
263 add_core_feature_inaccessible(&mut supergraph);
264 }
265
266 if self.errors.is_empty() {
267 crate::compat::coerce_schema_values(&mut supergraph);
268
269 let supergraph = Valid::assume_valid(supergraph);
271 Ok(MergeSuccess {
272 schema: supergraph,
273 composition_hints: self.composition_hints.to_owned(),
274 })
275 } else {
276 Err(MergeFailure {
277 schema: Some(Box::new(supergraph)),
278 composition_hints: self.composition_hints.to_owned(),
279 errors: self.errors.to_owned(),
280 })
281 }
282 }
283
284 fn add_interface_object_fields(
285 &mut self,
286 types: &mut IndexMap<NamedType, ExtendedType>,
287 implementers_map: HashMap<Name, Implementers>,
288 ) -> Result<(), MergeFailure> {
289 for interface_object_name in self.interface_objects.iter() {
290 let Some(ExtendedType::Interface(intf_def)) = types.get(interface_object_name) else {
291 return Err(MergeFailure {
292 schema: None,
293 composition_hints: self.composition_hints.to_owned(),
294 errors: vec![format!("Interface {} not found", interface_object_name)],
295 });
296 };
297 let fields = intf_def.fields.clone();
298
299 if let Some(implementers) = implementers_map.get(interface_object_name) {
300 for implementer in implementers.iter() {
301 types.entry(implementer.clone()).and_modify(|f| {
302 if let ExtendedType::Object(obj) = f {
303 let obj = obj.make_mut();
304 for (field_name, field_def) in fields.iter() {
305 let mut field_def = field_def.clone();
306 let field_def = field_def.make_mut();
307 field_def.directives = field_def
308 .directives
309 .iter()
310 .filter(|d| d.name != name!("join__field"))
311 .cloned()
312 .collect();
313 field_def.directives.push(Node::new(Directive {
314 name: name!("join__field"),
315 arguments: vec![],
316 }));
317
318 obj.fields
319 .entry(field_name.clone())
320 .or_insert(field_def.clone().into());
321 }
322 }
323 });
324 }
325 };
326 }
327
328 Ok(())
329 }
330
331 fn merge_descriptions<T: Eq + Clone>(&mut self, merged: &mut Option<T>, new: &Option<T>) {
332 match (&mut *merged, new) {
333 (_, None) => {}
334 (None, Some(_)) => merged.clone_from(new),
335 (Some(a), Some(b)) => {
336 if a != b {
337 self.composition_hints
339 .push(String::from("conflicting descriptions"));
340 }
341 }
342 }
343 }
344
345 fn merge_schema(&mut self, supergraph_schema: &mut Schema, subgraph: &ValidFederationSubgraph) {
346 let supergraph_def = &mut supergraph_schema.schema_definition.make_mut();
347 let subgraph_def = &subgraph.schema.schema().schema_definition;
348 self.merge_descriptions(&mut supergraph_def.description, &subgraph_def.description);
349
350 if subgraph_def.query.is_some() {
351 supergraph_def.query.clone_from(&subgraph_def.query);
352 }
354 if subgraph_def.mutation.is_some() {
355 supergraph_def.mutation.clone_from(&subgraph_def.mutation);
356 }
358 if subgraph_def.subscription.is_some() {
359 supergraph_def
360 .subscription
361 .clone_from(&subgraph_def.subscription);
362 }
364 }
365
366 fn merge_enum_type(
367 &mut self,
368 types: &mut IndexMap<NamedType, ExtendedType>,
369 metadata: &DirectiveNames,
370 subgraph_name: &EnumValue,
371 enum_name: NamedType,
372 enum_type: &Node<EnumType>,
373 ) {
374 let existing_type = types
375 .entry(enum_name.clone())
376 .or_insert(copy_enum_type(enum_name, enum_type));
377
378 if let ExtendedType::Enum(e) = existing_type {
379 let join_type_directives =
380 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
381 e.make_mut().directives.extend(join_type_directives);
382
383 self.add_inaccessible(
384 metadata,
385 &mut e.make_mut().directives,
386 &enum_type.directives,
387 );
388
389 self.merge_descriptions(&mut e.make_mut().description, &enum_type.description);
390
391 for (enum_value_name, enum_value) in enum_type.values.iter() {
394 let ev = e
395 .make_mut()
396 .values
397 .entry(enum_value_name.clone())
398 .or_insert(Component::new(EnumValueDefinition {
399 value: enum_value.value.clone(),
400 description: None,
401 directives: Default::default(),
402 }));
403 self.merge_descriptions(&mut ev.make_mut().description, &enum_value.description);
404
405 self.add_inaccessible(
406 metadata,
407 &mut ev.make_mut().directives,
408 &enum_value.directives,
409 );
410
411 ev.make_mut().directives.push(Node::new(Directive {
412 name: name!("join__enumValue"),
413 arguments: vec![
414 (Node::new(Argument {
415 name: name!("graph"),
416 value: Node::new(Value::Enum(subgraph_name.to_name())),
417 })),
418 ],
419 }));
420 }
421 } else {
422 }
424 }
425
426 fn merge_input_object_type(
427 &mut self,
428 types: &mut IndexMap<NamedType, ExtendedType>,
429 directive_names: &DirectiveNames,
430 subgraph_name: &EnumValue,
431 input_object_name: NamedType,
432 input_object: &Node<InputObjectType>,
433 ) {
434 let existing_type = types
435 .entry(input_object_name.clone())
436 .or_insert(copy_input_object_type(input_object_name, input_object));
437
438 if let ExtendedType::InputObject(obj) = existing_type {
439 let join_type_directives =
440 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
441 let mutable_object = obj.make_mut();
442 mutable_object.directives.extend(join_type_directives);
443
444 self.add_inaccessible(
445 directive_names,
446 &mut mutable_object.directives,
447 &input_object.directives,
448 );
449
450 for (field_name, field) in input_object.fields.iter() {
451 let existing_field = mutable_object.fields.entry(field_name.clone());
452
453 let supergraph_field = match existing_field {
454 Vacant(i) => i.insert(Component::new(InputValueDefinition {
455 name: field.name.clone(),
456 description: field.description.clone(),
457 ty: field.ty.clone(),
458 default_value: field.default_value.clone(),
459 directives: Default::default(),
460 })),
461 Occupied(i) => {
462 i.into_mut()
463 }
469 };
470
471 self.add_inaccessible(
472 directive_names,
473 &mut supergraph_field.make_mut().directives,
474 &field.directives,
475 );
476
477 let join_field_directive = join_field_applied_directive(
478 subgraph_name,
479 None,
480 None,
481 false,
482 None,
483 Some(&field.ty),
484 );
485 supergraph_field
486 .make_mut()
487 .directives
488 .push(Node::new(join_field_directive));
489 }
490 } else {
491 }
493 }
494
495 fn merge_interface_type(
496 &mut self,
497 types: &mut IndexMap<NamedType, ExtendedType>,
498 directive_names: &DirectiveNames,
499 subgraph_name: &EnumValue,
500 interface_name: NamedType,
501 interface: &Node<InterfaceType>,
502 ) {
503 let existing_type = types
504 .entry(interface_name.clone())
505 .or_insert(copy_interface_type(interface_name, interface));
506
507 if let ExtendedType::Interface(intf) = existing_type {
508 let key_directives = interface.directives.get_all(&directive_names.key);
509 let join_type_directives =
510 join_type_applied_directive(subgraph_name.clone(), key_directives, false);
511 let mutable_intf = intf.make_mut();
512 mutable_intf.directives.extend(join_type_directives);
513
514 self.add_inaccessible(
515 directive_names,
516 &mut mutable_intf.directives,
517 &interface.directives,
518 );
519
520 interface
521 .implements_interfaces
522 .iter()
523 .for_each(|intf_name| {
524 mutable_intf.implements_interfaces.insert(intf_name.clone());
526 let join_implements_directive =
527 join_implements_applied_directive(subgraph_name.clone(), intf_name);
528 mutable_intf.directives.push(join_implements_directive);
529 });
530
531 for (field_name, field) in interface.fields.iter() {
532 let existing_field = mutable_intf.fields.entry(field_name.clone());
533 let supergraph_field = match existing_field {
534 Occupied(f) => {
535 f.into_mut()
536 }
541 Vacant(f) => {
542 f.insert(Component::new(FieldDefinition {
544 name: field.name.clone(),
545 description: field.description.clone(),
546 arguments: vec![],
547 ty: field.ty.clone(),
548 directives: Default::default(),
549 }))
550 }
551 };
552
553 fields::merge_arguments(
554 field.arguments.iter(),
555 &mut supergraph_field.make_mut().arguments,
556 self,
557 directive_names,
558 );
559 self.merge_descriptions(
560 &mut supergraph_field.make_mut().description,
561 &field.description,
562 );
563
564 self.add_inaccessible(
565 directive_names,
566 &mut supergraph_field.make_mut().directives,
567 &field.directives,
568 );
569
570 let join_field_directive = join_field_applied_directive(
571 subgraph_name,
572 None,
573 None,
574 false,
575 None,
576 Some(&field.ty),
577 );
578
579 supergraph_field
580 .make_mut()
581 .directives
582 .push(Node::new(join_field_directive));
583 }
584 } else {
585 }
587 }
588
589 fn merge_object_type(
590 &mut self,
591 types: &mut IndexMap<NamedType, ExtendedType>,
592 directive_names: &DirectiveNames,
593 subgraph_name: &EnumValue,
594 object_name: NamedType,
595 object: &Node<ObjectType>,
596 ) {
597 let is_interface_object = object.directives.has(&directive_names.interface_object);
598 let existing_type = types
599 .entry(object_name.clone())
600 .or_insert(copy_object_type_stub(
601 object_name,
602 object,
603 is_interface_object,
604 ));
605
606 if let ExtendedType::Object(obj) = existing_type {
607 let key_directives = object.directives.get_all(&directive_names.key);
608 let join_type_directives =
609 join_type_applied_directive(subgraph_name.clone(), key_directives, false);
610 let mutable_object = obj.make_mut();
611 mutable_object.directives.extend(join_type_directives);
612 self.merge_descriptions(&mut mutable_object.description, &object.description);
613 self.add_inaccessible(
614 directive_names,
615 &mut mutable_object.directives,
616 &object.directives,
617 );
618 object.implements_interfaces.iter().for_each(|intf_name| {
619 mutable_object
621 .implements_interfaces
622 .insert(intf_name.clone());
623 let join_implements_directive =
624 join_implements_applied_directive(subgraph_name.clone(), intf_name);
625 mutable_object.directives.push(join_implements_directive);
626 });
627
628 for (field_name, field) in object.fields.iter() {
629 if field_name == "_service" || field_name == "_entities" {
631 continue;
632 }
633
634 let existing_field = mutable_object.fields.entry(field_name.clone());
635 let supergraph_field = match existing_field {
636 Occupied(f) => {
637 f.into_mut()
641 }
642 Vacant(f) => f.insert(Component::new(FieldDefinition {
643 name: field.name.clone(),
644 description: field.description.clone(),
645 arguments: vec![],
646 directives: Default::default(),
647 ty: field.ty.clone(),
648 })),
649 };
650 self.merge_descriptions(
651 &mut supergraph_field.make_mut().description,
652 &field.description,
653 );
654
655 self.add_inaccessible(
656 directive_names,
657 &mut supergraph_field.make_mut().directives,
658 &field.directives,
659 );
660
661 fields::merge_arguments(
662 field.arguments.iter(),
663 &mut supergraph_field.make_mut().arguments,
664 self,
665 directive_names,
666 );
667
668 let requires_directive_option = field
669 .directives
670 .get_all(&directive_names.requires)
671 .next()
672 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
673
674 let provides_directive_option = field
675 .directives
676 .get_all(&directive_names.provides)
677 .next()
678 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
679
680 let overrides_directive_option = field
681 .directives
682 .get_all(&directive_names.r#override)
683 .next()
684 .and_then(|p| {
685 let overrides_from =
686 directive_string_arg_value(p, &FEDERATION_FROM_ARGUMENT_NAME);
687 let overrides_label =
688 directive_string_arg_value(p, &FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME);
689 overrides_from.map(|from| (from, overrides_label))
690 });
691
692 let external_field = field
693 .directives
694 .get_all(&directive_names.external)
695 .next()
696 .is_some();
697
698 let join_field_directive = join_field_applied_directive(
699 subgraph_name,
700 requires_directive_option,
701 provides_directive_option,
702 external_field,
703 overrides_directive_option,
704 Some(&field.ty),
705 );
706
707 supergraph_field
708 .make_mut()
709 .directives
710 .push(Node::new(join_field_directive));
711
712 }
715 } else if let ExtendedType::Interface(intf) = existing_type {
716 self.interface_objects.insert(intf.name.clone());
717
718 let key_directives = object.directives.get_all(&directive_names.key);
719 let join_type_directives =
720 join_type_applied_directive(subgraph_name.clone(), key_directives, true);
721 let mutable_object = intf.make_mut();
722 mutable_object.directives.extend(join_type_directives);
723 self.merge_descriptions(&mut mutable_object.description, &object.description);
724 self.add_inaccessible(
725 directive_names,
726 &mut mutable_object.directives,
727 &object.directives,
728 );
729
730 for (field_name, field) in object.fields.iter() {
731 if field_name == "_service" || field_name == "_entities" {
733 continue;
734 }
735
736 let existing_field = mutable_object.fields.entry(field_name.clone());
737 let supergraph_field = match existing_field {
738 Occupied(f) => {
739 f.into_mut()
743 }
744 Vacant(f) => f.insert(Component::new(FieldDefinition {
745 name: field.name.clone(),
746 description: field.description.clone(),
747 arguments: vec![],
748 directives: Default::default(),
749 ty: field.ty.clone(),
750 })),
751 };
752 self.merge_descriptions(
753 &mut supergraph_field.make_mut().description,
754 &field.description,
755 );
756
757 self.add_inaccessible(
758 directive_names,
759 &mut supergraph_field.make_mut().directives,
760 &field.directives,
761 );
762
763 fields::merge_arguments(
764 field.arguments.iter(),
765 &mut supergraph_field.make_mut().arguments,
766 self,
767 directive_names,
768 );
769 let requires_directive_option = field
770 .directives
771 .get_all(&directive_names.requires)
772 .next()
773 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
774
775 let provides_directive_option = field
776 .directives
777 .get_all(&directive_names.provides)
778 .next()
779 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
780
781 let overrides_directive_option = field
782 .directives
783 .get_all(&directive_names.r#override)
784 .next()
785 .and_then(|p| {
786 let overrides_from =
787 directive_string_arg_value(p, &FEDERATION_FROM_ARGUMENT_NAME);
788 let overrides_label =
789 directive_string_arg_value(p, &FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME);
790 overrides_from.map(|from| (from, overrides_label))
791 });
792
793 let external_field = field
794 .directives
795 .get_all(&directive_names.external)
796 .next()
797 .is_some();
798
799 let join_field_directive = join_field_applied_directive(
800 subgraph_name,
801 requires_directive_option,
802 provides_directive_option,
803 external_field,
804 overrides_directive_option,
805 Some(&field.ty),
806 );
807
808 supergraph_field
809 .make_mut()
810 .directives
811 .push(Node::new(join_field_directive));
812
813 }
816 };
817 }
819
820 fn merge_union_type(
821 &mut self,
822 types: &mut IndexMap<NamedType, ExtendedType>,
823 directive_names: &DirectiveNames,
824 subgraph_name: &EnumValue,
825 union_name: NamedType,
826 union: &Node<UnionType>,
827 ) {
828 let existing_type = types
829 .entry(union_name.clone())
830 .or_insert(copy_union_type(union_name, union.description.clone()));
831
832 if let ExtendedType::Union(u) = existing_type {
833 let join_type_directives =
834 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
835 u.make_mut().directives.extend(join_type_directives);
836 self.add_inaccessible(
837 directive_names,
838 &mut u.make_mut().directives,
839 &union.directives,
840 );
841
842 for union_member in union.members.iter() {
843 u.make_mut().members.insert(union_member.clone());
845 u.make_mut().directives.push(Component::new(Directive {
846 name: name!("join__unionMember"),
847 arguments: vec![
848 Node::new(Argument {
849 name: name!("graph"),
850 value: Node::new(Value::Enum(subgraph_name.to_name())),
851 }),
852 Node::new(Argument {
853 name: name!("member"),
854 value: union_member.as_str().into(),
855 }),
856 ],
857 }));
858 }
859 }
860 }
861
862 fn merge_scalar_type(
863 &mut self,
864 types: &mut IndexMap<Name, ExtendedType>,
865 directive_names: &DirectiveNames,
866 subgraph_name: EnumValue,
867 scalar_name: NamedType,
868 ty: &Node<ScalarType>,
869 ) {
870 let existing_type = types
871 .entry(scalar_name.clone())
872 .or_insert(copy_scalar_type(scalar_name, ty));
873
874 if let ExtendedType::Scalar(s) = existing_type {
875 let join_type_directives =
876 join_type_applied_directive(subgraph_name, iter::empty(), false);
877 s.make_mut().directives.extend(join_type_directives);
878 self.add_inaccessible(
879 directive_names,
880 &mut s.make_mut().directives,
881 &ty.directives,
882 );
883 } else {
884 }
886 }
887
888 fn add_inaccessible<I>(
890 &mut self,
891 directive_names: &DirectiveNames,
892 new_directives: &mut Vec<I>,
893 original_directives: &[I],
894 ) where
895 I: AsRef<Directive> + From<Directive> + Clone,
896 {
897 if original_directives
898 .iter()
899 .any(|d| d.as_ref().name == directive_names.inaccessible)
900 && !new_directives
901 .iter()
902 .any(|d| d.as_ref().name == INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC)
903 {
904 self.needs_inaccessible = true;
905
906 new_directives.push(
907 Directive {
908 name: INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
909 arguments: vec![],
910 }
911 .into(),
912 );
913 }
914 }
915}
916
917struct DirectiveNames {
918 key: Name,
919 requires: Name,
920 provides: Name,
921 external: Name,
922 interface_object: Name,
923 r#override: Name,
924 inaccessible: Name,
925}
926
927impl DirectiveNames {
928 fn for_metadata(metadata: &Option<&LinksMetadata>) -> Self {
929 let federation_identity =
930 metadata.and_then(|m| m.for_identity(&Identity::federation_identity()));
931 let federation_identity = federation_identity.as_ref();
932
933 let key = federation_identity
934 .map(|link| link.directive_name_in_schema(&FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC))
935 .unwrap_or(FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC);
936
937 let requires = federation_identity
938 .map(|link| link.directive_name_in_schema(&FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC))
939 .unwrap_or(FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC);
940
941 let provides = federation_identity
942 .map(|link| link.directive_name_in_schema(&FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC))
943 .unwrap_or(FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC);
944
945 let external = federation_identity
946 .map(|link| link.directive_name_in_schema(&FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC))
947 .unwrap_or(FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC);
948
949 let interface_object = federation_identity
950 .map(|link| {
951 link.directive_name_in_schema(&FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC)
952 })
953 .unwrap_or(FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC);
954
955 let r#override = federation_identity
956 .map(|link| link.directive_name_in_schema(&FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC))
957 .unwrap_or(FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC);
958
959 let inaccessible = federation_identity
960 .map(|link| link.directive_name_in_schema(&INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC))
961 .unwrap_or(INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC);
962
963 Self {
964 key,
965 requires,
966 provides,
967 external,
968 interface_object,
969 r#override,
970 inaccessible,
971 }
972 }
973}
974
975const EXECUTABLE_DIRECTIVE_LOCATIONS: [DirectiveLocation; 8] = [
976 DirectiveLocation::Query,
977 DirectiveLocation::Mutation,
978 DirectiveLocation::Subscription,
979 DirectiveLocation::Field,
980 DirectiveLocation::FragmentDefinition,
981 DirectiveLocation::FragmentSpread,
982 DirectiveLocation::InlineFragment,
983 DirectiveLocation::VariableDefinition,
984];
985fn is_executable_directive(directive: &Node<DirectiveDefinition>) -> bool {
986 directive
987 .locations
988 .iter()
989 .any(|loc| EXECUTABLE_DIRECTIVE_LOCATIONS.contains(loc))
990}
991
992const FEDERATION_TYPES: [&str; 4] = ["_Any", "_Entity", "_Service", "@key"];
995fn is_mergeable_type(type_name: &str) -> bool {
996 if type_name.starts_with("federation__") || type_name.starts_with("link__") {
997 return false;
998 }
999 !FEDERATION_TYPES.contains(&type_name)
1000}
1001
1002fn copy_scalar_type(scalar_name: Name, scalar_type: &Node<ScalarType>) -> ExtendedType {
1003 ExtendedType::Scalar(Node::new(ScalarType {
1004 description: scalar_type.description.clone(),
1005 name: scalar_name,
1006 directives: Default::default(),
1007 }))
1008}
1009
1010fn copy_enum_type(enum_name: Name, enum_type: &Node<EnumType>) -> ExtendedType {
1011 ExtendedType::Enum(Node::new(EnumType {
1012 description: enum_type.description.clone(),
1013 name: enum_name,
1014 directives: Default::default(),
1015 values: IndexMap::default(),
1016 }))
1017}
1018
1019fn copy_input_object_type(
1020 input_object_name: Name,
1021 input_object: &Node<InputObjectType>,
1022) -> ExtendedType {
1023 let mut new_input_object = InputObjectType {
1024 description: input_object.description.clone(),
1025 name: input_object_name,
1026 directives: Default::default(),
1027 fields: IndexMap::default(),
1028 };
1029
1030 for (field_name, input_field) in input_object.fields.iter() {
1031 new_input_object.fields.insert(
1032 field_name.clone(),
1033 Component::new(InputValueDefinition {
1034 name: input_field.name.clone(),
1035 description: input_field.description.clone(),
1036 directives: Default::default(),
1037 ty: input_field.ty.clone(),
1038 default_value: input_field.default_value.clone(),
1039 }),
1040 );
1041 }
1042
1043 ExtendedType::InputObject(Node::new(new_input_object))
1044}
1045
1046fn copy_interface_type(interface_name: Name, interface: &Node<InterfaceType>) -> ExtendedType {
1047 let new_interface = InterfaceType {
1048 description: interface.description.clone(),
1049 name: interface_name,
1050 directives: Default::default(),
1051 fields: copy_fields(interface.fields.iter()),
1052 implements_interfaces: interface.implements_interfaces.clone(),
1053 };
1054 ExtendedType::Interface(Node::new(new_interface))
1055}
1056
1057fn copy_object_type_stub(
1058 object_name: Name,
1059 object: &Node<ObjectType>,
1060 is_interface_object: bool,
1061) -> ExtendedType {
1062 if is_interface_object {
1063 let new_interface = InterfaceType {
1064 description: object.description.clone(),
1065 name: object_name,
1066 directives: Default::default(),
1067 fields: copy_fields(object.fields.iter()),
1068 implements_interfaces: object.implements_interfaces.clone(),
1069 };
1070 ExtendedType::Interface(Node::new(new_interface))
1071 } else {
1072 let new_object = ObjectType {
1073 description: object.description.clone(),
1074 name: object_name,
1075 directives: Default::default(),
1076 fields: copy_fields(object.fields.iter()),
1077 implements_interfaces: object.implements_interfaces.clone(),
1078 };
1079 ExtendedType::Object(Node::new(new_object))
1080 }
1081}
1082
1083fn copy_fields(
1084 fields_to_copy: Iter<Name, Component<FieldDefinition>>,
1085) -> IndexMap<Name, Component<FieldDefinition>> {
1086 let mut new_fields: IndexMap<Name, Component<FieldDefinition>> = IndexMap::default();
1087 for (field_name, field) in fields_to_copy {
1088 if field_name == "_service" || field_name == "_entities" {
1090 continue;
1091 }
1092 let args: Vec<Node<InputValueDefinition>> = field
1093 .arguments
1094 .iter()
1095 .map(|a| {
1096 Node::new(InputValueDefinition {
1097 name: a.name.clone(),
1098 description: a.description.clone(),
1099 directives: Default::default(),
1100 ty: a.ty.clone(),
1101 default_value: a.default_value.clone(),
1102 })
1103 })
1104 .collect();
1105 let new_field = Component::new(FieldDefinition {
1106 name: field.name.clone(),
1107 description: field.description.clone(),
1108 directives: Default::default(),
1109 arguments: args,
1110 ty: field.ty.clone(),
1111 });
1112
1113 new_fields.insert(field_name.clone(), new_field);
1114 }
1115 new_fields
1116}
1117
1118fn copy_union_type(union_name: Name, description: Option<Node<str>>) -> ExtendedType {
1119 ExtendedType::Union(Node::new(UnionType {
1120 description,
1121 name: union_name,
1122 directives: Default::default(),
1123 members: IndexSet::default(),
1124 }))
1125}
1126
1127fn join_type_applied_directive<'a>(
1128 subgraph_name: EnumValue,
1129 key_directives: impl Iterator<Item = &'a Component<Directive>> + Sized,
1130 is_interface_object: bool,
1131) -> Vec<Component<Directive>> {
1132 let mut join_type_directive = Directive {
1133 name: name!("join__type"),
1134 arguments: vec![Node::new(Argument {
1135 name: name!("graph"),
1136 value: Node::new(Value::Enum(subgraph_name.into())),
1137 })],
1138 };
1139 if is_interface_object {
1140 join_type_directive.arguments.push(Node::new(Argument {
1141 name: name!("isInterfaceObject"),
1142 value: Node::new(Value::Boolean(is_interface_object)),
1143 }));
1144 }
1145
1146 let mut result = vec![];
1147 for key_directive in key_directives {
1148 let mut join_type_directive_with_key = join_type_directive.clone();
1149 let field_set = directive_string_arg_value(key_directive, &name!("fields")).unwrap();
1150 join_type_directive_with_key
1151 .arguments
1152 .push(Node::new(Argument {
1153 name: name!("key"),
1154 value: field_set.into(),
1155 }));
1156
1157 let resolvable =
1158 directive_bool_arg_value(key_directive, &name!("resolvable")).unwrap_or(&true);
1159 if !resolvable {
1160 join_type_directive_with_key
1161 .arguments
1162 .push(Node::new(Argument {
1163 name: name!("resolvable"),
1164 value: Node::new(Value::Boolean(false)),
1165 }));
1166 }
1167 result.push(join_type_directive_with_key)
1168 }
1169 if result.is_empty() {
1170 result.push(join_type_directive)
1171 }
1172 result
1173 .into_iter()
1174 .map(Component::new)
1175 .collect::<Vec<Component<Directive>>>()
1176}
1177
1178fn join_implements_applied_directive(
1179 subgraph_name: EnumValue,
1180 intf_name: &Name,
1181) -> Component<Directive> {
1182 Component::new(Directive {
1183 name: name!("join__implements"),
1184 arguments: vec![
1185 Node::new(Argument {
1186 name: name!("graph"),
1187 value: Node::new(Value::Enum(subgraph_name.into())),
1188 }),
1189 Node::new(Argument {
1190 name: name!("interface"),
1191 value: intf_name.as_str().into(),
1192 }),
1193 ],
1194 })
1195}
1196
1197fn directive_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a Value> {
1198 directive
1199 .arguments
1200 .iter()
1201 .find(|arg| arg.name == *arg_name)
1202 .map(|arg| arg.value.as_ref())
1203}
1204
1205fn directive_string_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a str> {
1206 match directive_arg_value(directive, arg_name) {
1207 Some(Value::String(value)) => Some(value),
1208 _ => None,
1209 }
1210}
1211
1212fn directive_bool_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a bool> {
1213 match directive_arg_value(directive, arg_name) {
1214 Some(Value::Boolean(value)) => Some(value),
1215 _ => None,
1216 }
1217}
1218
1219fn add_core_feature_link(supergraph: &mut Schema) {
1221 supergraph
1223 .schema_definition
1224 .make_mut()
1225 .directives
1226 .push(Component::new(Directive {
1227 name: name!("link"),
1228 arguments: vec![Node::new(Argument {
1229 name: name!("url"),
1230 value: Node::new("https://specs.apollo.dev/link/v1.0".into()),
1231 })],
1232 }));
1233
1234 let (name, link_purpose_enum) = link_purpose_enum_type();
1235 supergraph.types.insert(name, link_purpose_enum.into());
1236
1237 let link_import_name = name!("link__Import");
1239 let link_import_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1240 directives: Default::default(),
1241 name: link_import_name.clone(),
1242 description: None,
1243 }));
1244 supergraph
1245 .types
1246 .insert(link_import_name, link_import_scalar);
1247
1248 let link_directive_definition = link_directive_definition();
1249 supergraph
1250 .directive_definitions
1251 .insert(name!("link"), Node::new(link_directive_definition));
1252}
1253
1254fn link_directive_definition() -> DirectiveDefinition {
1256 DirectiveDefinition {
1257 name: name!("link"),
1258 description: None,
1259 arguments: vec![
1260 Node::new(InputValueDefinition {
1261 name: name!("url"),
1262 description: None,
1263 directives: Default::default(),
1264 ty: ty!(String).into(),
1265 default_value: None,
1266 }),
1267 Node::new(InputValueDefinition {
1268 name: name!("as"),
1269 description: None,
1270 directives: Default::default(),
1271 ty: ty!(String).into(),
1272 default_value: None,
1273 }),
1274 Node::new(InputValueDefinition {
1275 name: name!("for"),
1276 description: None,
1277 directives: Default::default(),
1278 ty: ty!(link__Purpose).into(),
1279 default_value: None,
1280 }),
1281 Node::new(InputValueDefinition {
1282 name: name!("import"),
1283 description: None,
1284 directives: Default::default(),
1285 ty: ty!([link__Import]).into(),
1286 default_value: None,
1287 }),
1288 ],
1289 locations: vec![DirectiveLocation::Schema],
1290 repeatable: true,
1291 }
1292}
1293
1294fn link_purpose_enum_type() -> (Name, EnumType) {
1306 let link_purpose_name = name!("link__Purpose");
1307 let mut link_purpose_enum = EnumType {
1308 description: None,
1309 name: link_purpose_name.clone(),
1310 directives: Default::default(),
1311 values: IndexMap::default(),
1312 };
1313 let link_purpose_security_value = EnumValueDefinition {
1314 description: Some(
1315 r"SECURITY features provide metadata necessary to securely resolve fields.".into(),
1316 ),
1317 directives: Default::default(),
1318 value: name!("SECURITY"),
1319 };
1320 let link_purpose_execution_value = EnumValueDefinition {
1321 description: Some(
1322 r"EXECUTION features provide metadata necessary for operation execution.".into(),
1323 ),
1324 directives: Default::default(),
1325 value: name!("EXECUTION"),
1326 };
1327 link_purpose_enum.values.insert(
1328 link_purpose_security_value.value.clone(),
1329 Component::new(link_purpose_security_value),
1330 );
1331 link_purpose_enum.values.insert(
1332 link_purpose_execution_value.value.clone(),
1333 Component::new(link_purpose_execution_value),
1334 );
1335 (link_purpose_name, link_purpose_enum)
1336}
1337
1338fn add_core_feature_join(
1340 supergraph: &mut Schema,
1341 subgraphs_and_enum_values: &Vec<(&ValidFederationSubgraph, EnumValue)>,
1342) {
1343 supergraph
1345 .schema_definition
1346 .make_mut()
1347 .directives
1348 .push(Component::new(Directive {
1349 name: name!("link"),
1350 arguments: vec![
1351 Node::new(Argument {
1352 name: name!("url"),
1353 value: "https://specs.apollo.dev/join/v0.5".into(),
1354 }),
1355 Node::new(Argument {
1356 name: name!("for"),
1357 value: Node::new(Value::Enum(name!("EXECUTION"))),
1358 }),
1359 ],
1360 }));
1361
1362 let join_field_set_name = name!("join__FieldSet");
1364 let join_field_set_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1365 directives: Default::default(),
1366 name: join_field_set_name.clone(),
1367 description: None,
1368 }));
1369 supergraph
1370 .types
1371 .insert(join_field_set_name, join_field_set_scalar);
1372
1373 let join_field_value_name = name!("join__FieldValue");
1375 let join_field_value_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1376 directives: Default::default(),
1377 name: join_field_value_name.clone(),
1378 description: None,
1379 }));
1380 supergraph
1381 .types
1382 .insert(join_field_value_name, join_field_value_scalar);
1383
1384 let join_context_argument_name = name!("join__ContextArgument");
1391 let join_context_argument_input = ExtendedType::InputObject(Node::new(InputObjectType {
1392 description: None,
1393 name: join_context_argument_name.clone(),
1394 directives: Default::default(),
1395 fields: vec![
1396 (
1397 name!("name"),
1398 Component::new(InputValueDefinition {
1399 name: name!("name"),
1400 description: None,
1401 directives: Default::default(),
1402 ty: ty!(String!).into(),
1403 default_value: None,
1404 }),
1405 ),
1406 (
1407 name!("type"),
1408 Component::new(InputValueDefinition {
1409 name: name!("type"),
1410 description: None,
1411 directives: Default::default(),
1412 ty: ty!(String!).into(),
1413 default_value: None,
1414 }),
1415 ),
1416 (
1417 name!("context"),
1418 Component::new(InputValueDefinition {
1419 name: name!("context"),
1420 description: None,
1421 directives: Default::default(),
1422 ty: ty!(String!).into(),
1423 default_value: None,
1424 }),
1425 ),
1426 (
1427 name!("selection"),
1428 Component::new(InputValueDefinition {
1429 name: name!("selection"),
1430 description: None,
1431 directives: Default::default(),
1432 ty: ty!(join__FieldValue!).into(),
1433 default_value: None,
1434 }),
1435 ),
1436 ]
1437 .into_iter()
1438 .collect(),
1439 }));
1440 supergraph
1441 .types
1442 .insert(join_context_argument_name, join_context_argument_input);
1443
1444 let join_graph_directive_definition = join_graph_directive_definition();
1445 supergraph.directive_definitions.insert(
1446 join_graph_directive_definition.name.clone(),
1447 Node::new(join_graph_directive_definition),
1448 );
1449
1450 let join_type_directive_definition = join_type_directive_definition();
1451 supergraph.directive_definitions.insert(
1452 join_type_directive_definition.name.clone(),
1453 Node::new(join_type_directive_definition),
1454 );
1455
1456 let join_field_directive_definition = join_field_directive_definition();
1457 supergraph.directive_definitions.insert(
1458 join_field_directive_definition.name.clone(),
1459 Node::new(join_field_directive_definition),
1460 );
1461
1462 let join_implements_directive_definition = join_implements_directive_definition();
1463 supergraph.directive_definitions.insert(
1464 join_implements_directive_definition.name.clone(),
1465 Node::new(join_implements_directive_definition),
1466 );
1467
1468 let join_union_member_directive_definition = join_union_member_directive_definition();
1469 supergraph.directive_definitions.insert(
1470 join_union_member_directive_definition.name.clone(),
1471 Node::new(join_union_member_directive_definition),
1472 );
1473
1474 let join_enum_value_directive_definition = join_enum_value_directive_definition();
1475 supergraph.directive_definitions.insert(
1476 join_enum_value_directive_definition.name.clone(),
1477 Node::new(join_enum_value_directive_definition),
1478 );
1479
1480 let join_directive_arguments_name = name!("join__DirectiveArguments");
1482 let join_directive_arguments_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1483 directives: Default::default(),
1484 name: join_directive_arguments_name.clone(),
1485 description: None,
1486 }));
1487 supergraph.types.insert(
1488 join_directive_arguments_name,
1489 join_directive_arguments_scalar,
1490 );
1491
1492 let join_directive_directive_definition = join_directive_directive_definition();
1493 supergraph.directive_definitions.insert(
1494 join_directive_directive_definition.name.clone(),
1495 Node::new(join_directive_directive_definition),
1496 );
1497
1498 let (name, join_graph_enum_type) = join_graph_enum_type(subgraphs_and_enum_values);
1499 supergraph.types.insert(name, join_graph_enum_type.into());
1500}
1501
1502fn join_enum_value_directive_definition() -> DirectiveDefinition {
1504 DirectiveDefinition {
1505 name: name!("join__enumValue"),
1506 description: None,
1507 arguments: vec![Node::new(InputValueDefinition {
1508 name: name!("graph"),
1509 description: None,
1510 directives: Default::default(),
1511 ty: ty!(join__Graph!).into(),
1512 default_value: None,
1513 })],
1514 locations: vec![DirectiveLocation::EnumValue],
1515 repeatable: true,
1516 }
1517}
1518
1519fn join_directive_directive_definition() -> DirectiveDefinition {
1521 DirectiveDefinition {
1522 name: name!("join__directive"),
1523 description: None,
1524 arguments: vec![
1525 Node::new(InputValueDefinition {
1526 name: name!("graphs"),
1527 description: None,
1528 directives: Default::default(),
1529 ty: ty!([join__Graph!]).into(),
1530 default_value: None,
1531 }),
1532 Node::new(InputValueDefinition {
1533 name: name!("name"),
1534 description: None,
1535 directives: Default::default(),
1536 ty: ty!(String!).into(),
1537 default_value: None,
1538 }),
1539 Node::new(InputValueDefinition {
1540 name: name!("args"),
1541 description: None,
1542 directives: Default::default(),
1543 ty: ty!(join__DirectiveArguments!).into(),
1544 default_value: None,
1545 }),
1546 ],
1547 locations: vec![
1548 DirectiveLocation::Schema,
1549 DirectiveLocation::Object,
1550 DirectiveLocation::Interface,
1551 DirectiveLocation::FieldDefinition,
1552 ],
1553 repeatable: true,
1554 }
1555}
1556
1557fn join_field_directive_definition() -> DirectiveDefinition {
1567 DirectiveDefinition {
1568 name: name!("join__field"),
1569 description: None,
1570 arguments: vec![
1571 Node::new(InputValueDefinition {
1572 name: name!("graph"),
1573 description: None,
1574 directives: Default::default(),
1575 ty: ty!(join__Graph).into(),
1576 default_value: None,
1577 }),
1578 Node::new(InputValueDefinition {
1579 name: name!("requires"),
1580 description: None,
1581 directives: Default::default(),
1582 ty: ty!(join__FieldSet).into(),
1583 default_value: None,
1584 }),
1585 Node::new(InputValueDefinition {
1586 name: name!("provides"),
1587 description: None,
1588 directives: Default::default(),
1589 ty: ty!(join__FieldSet).into(),
1590 default_value: None,
1591 }),
1592 Node::new(InputValueDefinition {
1593 name: name!("type"),
1594 description: None,
1595 directives: Default::default(),
1596 ty: ty!(String).into(),
1597 default_value: None,
1598 }),
1599 Node::new(InputValueDefinition {
1600 name: name!("external"),
1601 description: None,
1602 directives: Default::default(),
1603 ty: ty!(Boolean).into(),
1604 default_value: None,
1605 }),
1606 Node::new(InputValueDefinition {
1607 name: name!("override"),
1608 description: None,
1609 directives: Default::default(),
1610 ty: ty!(String).into(),
1611 default_value: None,
1612 }),
1613 Node::new(InputValueDefinition {
1614 name: JOIN_OVERRIDE_LABEL_ARGUMENT_NAME,
1615 description: None,
1616 directives: Default::default(),
1617 ty: ty!(String).into(),
1618 default_value: None,
1619 }),
1620 Node::new(InputValueDefinition {
1621 name: name!("usedOverridden"),
1622 description: None,
1623 directives: Default::default(),
1624 ty: ty!(Boolean).into(),
1625 default_value: None,
1626 }),
1627 Node::new(InputValueDefinition {
1628 name: name!("contextArguments"),
1629 description: None,
1630 directives: Default::default(),
1631 ty: ty!([join__ContextArgument!]).into(),
1632 default_value: None,
1633 }),
1634 ],
1635 locations: vec![
1636 DirectiveLocation::FieldDefinition,
1637 DirectiveLocation::InputFieldDefinition,
1638 ],
1639 repeatable: true,
1640 }
1641}
1642
1643fn join_field_applied_directive(
1647 subgraph_name: &EnumValue,
1648 requires: Option<&str>,
1649 provides: Option<&str>,
1650 external: bool,
1651 overrides: Option<(&str, Option<&str>)>, r#type: Option<&Type>,
1653) -> Directive {
1654 let mut join_field_directive = Directive {
1655 name: name!("join__field"),
1656 arguments: vec![Node::new(Argument {
1657 name: name!("graph"),
1658 value: Node::new(Value::Enum(subgraph_name.to_name())),
1659 })],
1660 };
1661 if let Some(required_fields) = requires {
1662 join_field_directive.arguments.push(Node::new(Argument {
1663 name: name!("requires"),
1664 value: required_fields.into(),
1665 }));
1666 }
1667 if let Some(provided_fields) = provides {
1668 join_field_directive.arguments.push(Node::new(Argument {
1669 name: name!("provides"),
1670 value: provided_fields.into(),
1671 }));
1672 }
1673 if external {
1674 join_field_directive.arguments.push(Node::new(Argument {
1675 name: name!("external"),
1676 value: external.into(),
1677 }));
1678 }
1679 if let Some((from, label)) = overrides {
1680 join_field_directive.arguments.push(Node::new(Argument {
1681 name: name!("override"),
1682 value: Node::new(Value::String(from.to_string())),
1683 }));
1684 if let Some(label) = label {
1685 join_field_directive.arguments.push(Node::new(Argument {
1686 name: name!("overrideLabel"),
1687 value: Node::new(Value::String(label.to_string())),
1688 }));
1689 }
1690 }
1691 if let Some(r#type) = r#type {
1692 join_field_directive.arguments.push(Node::new(Argument {
1693 name: name!("type"),
1694 value: r#type.to_string().into(),
1695 }));
1696 }
1697 join_field_directive
1698}
1699
1700fn join_graph_directive_definition() -> DirectiveDefinition {
1702 DirectiveDefinition {
1703 name: name!("join__graph"),
1704 description: None,
1705 arguments: vec![
1706 Node::new(InputValueDefinition {
1707 name: name!("name"),
1708 description: None,
1709 directives: Default::default(),
1710 ty: ty!(String!).into(),
1711 default_value: None,
1712 }),
1713 Node::new(InputValueDefinition {
1714 name: name!("url"),
1715 description: None,
1716 directives: Default::default(),
1717 ty: ty!(String!).into(),
1718 default_value: None,
1719 }),
1720 ],
1721 locations: vec![DirectiveLocation::EnumValue],
1722 repeatable: false,
1723 }
1724}
1725
1726fn join_implements_directive_definition() -> DirectiveDefinition {
1731 DirectiveDefinition {
1732 name: name!("join__implements"),
1733 description: None,
1734 arguments: vec![
1735 Node::new(InputValueDefinition {
1736 name: name!("graph"),
1737 description: None,
1738 directives: Default::default(),
1739 ty: ty!(join__Graph!).into(),
1740 default_value: None,
1741 }),
1742 Node::new(InputValueDefinition {
1743 name: name!("interface"),
1744 description: None,
1745 directives: Default::default(),
1746 ty: ty!(String!).into(),
1747 default_value: None,
1748 }),
1749 ],
1750 locations: vec![DirectiveLocation::Interface, DirectiveLocation::Object],
1751 repeatable: true,
1752 }
1753}
1754
1755fn join_type_directive_definition() -> DirectiveDefinition {
1763 DirectiveDefinition {
1764 name: name!("join__type"),
1765 description: None,
1766 arguments: vec![
1767 Node::new(InputValueDefinition {
1768 name: name!("graph"),
1769 description: None,
1770 directives: Default::default(),
1771 ty: ty!(join__Graph!).into(),
1772 default_value: None,
1773 }),
1774 Node::new(InputValueDefinition {
1775 name: name!("key"),
1776 description: None,
1777 directives: Default::default(),
1778 ty: ty!(join__FieldSet).into(),
1779 default_value: None,
1780 }),
1781 Node::new(InputValueDefinition {
1782 name: name!("extension"),
1783 description: None,
1784 directives: Default::default(),
1785 ty: ty!(Boolean!).into(),
1786 default_value: Some(Node::new(Value::Boolean(false))),
1787 }),
1788 Node::new(InputValueDefinition {
1789 name: name!("resolvable"),
1790 description: None,
1791 directives: Default::default(),
1792 ty: ty!(Boolean!).into(),
1793 default_value: Some(Node::new(Value::Boolean(true))),
1794 }),
1795 Node::new(InputValueDefinition {
1796 name: name!("isInterfaceObject"),
1797 description: None,
1798 directives: Default::default(),
1799 ty: ty!(Boolean!).into(),
1800 default_value: Some(Node::new(Value::Boolean(false))),
1801 }),
1802 ],
1803 locations: vec![
1804 DirectiveLocation::Enum,
1805 DirectiveLocation::InputObject,
1806 DirectiveLocation::Interface,
1807 DirectiveLocation::Object,
1808 DirectiveLocation::Scalar,
1809 DirectiveLocation::Union,
1810 ],
1811 repeatable: true,
1812 }
1813}
1814
1815fn join_union_member_directive_definition() -> DirectiveDefinition {
1817 DirectiveDefinition {
1818 name: name!("join__unionMember"),
1819 description: None,
1820 arguments: vec![
1821 Node::new(InputValueDefinition {
1822 name: name!("graph"),
1823 description: None,
1824 directives: Default::default(),
1825 ty: ty!(join__Graph!).into(),
1826 default_value: None,
1827 }),
1828 Node::new(InputValueDefinition {
1829 name: name!("member"),
1830 description: None,
1831 directives: Default::default(),
1832 ty: ty!(String!).into(),
1833 default_value: None,
1834 }),
1835 ],
1836 locations: vec![DirectiveLocation::Union],
1837 repeatable: true,
1838 }
1839}
1840
1841fn join_graph_enum_type(
1843 subgraphs_and_enum_values: &Vec<(&ValidFederationSubgraph, EnumValue)>,
1844) -> (Name, EnumType) {
1845 let join_graph_enum_name = name!("join__Graph");
1846 let mut join_graph_enum_type = EnumType {
1847 description: None,
1848 name: join_graph_enum_name.clone(),
1849 directives: Default::default(),
1850 values: IndexMap::default(),
1851 };
1852 for (s, subgraph_name) in subgraphs_and_enum_values {
1853 let join_graph_applied_directive = Directive {
1854 name: name!("join__graph"),
1855 arguments: vec![
1856 (Node::new(Argument {
1857 name: name!("name"),
1858 value: s.name.as_str().into(),
1859 })),
1860 (Node::new(Argument {
1861 name: name!("url"),
1862 value: s.url.as_str().into(),
1863 })),
1864 ],
1865 };
1866 let graph = EnumValueDefinition {
1867 description: None,
1868 directives: DirectiveList(vec![Node::new(join_graph_applied_directive)]),
1869 value: subgraph_name.to_name(),
1870 };
1871 join_graph_enum_type
1872 .values
1873 .insert(graph.value.clone(), Component::new(graph));
1874 }
1875 (join_graph_enum_name, join_graph_enum_type)
1876}
1877
1878fn add_core_feature_inaccessible(supergraph: &mut Schema) {
1879 let spec = InaccessibleSpecDefinition::new(
1881 Version { major: 0, minor: 2 },
1882 Version { major: 2, minor: 0 },
1883 );
1884
1885 supergraph
1886 .schema_definition
1887 .make_mut()
1888 .directives
1889 .push(Component::new(Directive {
1890 name: name!("link"),
1891 arguments: vec![
1892 Node::new(Argument {
1893 name: name!("url"),
1894 value: spec.to_string().into(),
1895 }),
1896 Node::new(Argument {
1897 name: name!("for"),
1898 value: Node::new(Value::Enum(name!("SECURITY"))),
1899 }),
1900 ],
1901 }));
1902
1903 supergraph.directive_definitions.insert(
1904 INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
1905 Node::new(DirectiveDefinition {
1906 name: INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
1907 description: None,
1908 arguments: vec![],
1909 locations: vec![
1910 DirectiveLocation::FieldDefinition,
1911 DirectiveLocation::Object,
1912 DirectiveLocation::Interface,
1913 DirectiveLocation::Union,
1914 DirectiveLocation::ArgumentDefinition,
1915 DirectiveLocation::Scalar,
1916 DirectiveLocation::Enum,
1917 DirectiveLocation::EnumValue,
1918 DirectiveLocation::InputObject,
1919 DirectiveLocation::InputFieldDefinition,
1920 ],
1921 repeatable: false,
1922 }),
1923 );
1924}
1925
1926fn merge_directive(
1927 supergraph_directives: &mut IndexMap<Name, Node<DirectiveDefinition>>,
1928 directive: &Node<DirectiveDefinition>,
1929) {
1930 if !supergraph_directives.contains_key(&directive.name.clone()) {
1931 supergraph_directives.insert(directive.name.clone(), directive.clone());
1932 }
1933}
1934
1935#[cfg(test)]
1936mod tests;