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::LinksMetadata;
46use crate::link::federation_spec_definition::FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC;
47use crate::link::federation_spec_definition::FEDERATION_FIELDS_ARGUMENT_NAME;
48use crate::link::federation_spec_definition::FEDERATION_FROM_ARGUMENT_NAME;
49use crate::link::federation_spec_definition::FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC;
50use crate::link::federation_spec_definition::FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC;
51use crate::link::federation_spec_definition::FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC;
52use crate::link::federation_spec_definition::FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME;
53use crate::link::federation_spec_definition::FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC;
54use crate::link::federation_spec_definition::FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC;
55use crate::link::inaccessible_spec_definition::INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC;
56use crate::link::inaccessible_spec_definition::InaccessibleSpecDefinition;
57use crate::link::join_spec_definition::EnumValue;
58use crate::link::join_spec_definition::JOIN_OVERRIDE_LABEL_ARGUMENT_NAME;
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_default_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.by_identity.get(&Identity::federation_identity()));
931
932 let key = federation_identity
933 .map(|link| link.directive_name_in_schema(&FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC))
934 .unwrap_or(FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC);
935
936 let requires = federation_identity
937 .map(|link| link.directive_name_in_schema(&FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC))
938 .unwrap_or(FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC);
939
940 let provides = federation_identity
941 .map(|link| link.directive_name_in_schema(&FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC))
942 .unwrap_or(FEDERATION_PROVIDES_DIRECTIVE_NAME_IN_SPEC);
943
944 let external = federation_identity
945 .map(|link| link.directive_name_in_schema(&FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC))
946 .unwrap_or(FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC);
947
948 let interface_object = federation_identity
949 .map(|link| {
950 link.directive_name_in_schema(&FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC)
951 })
952 .unwrap_or(FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC);
953
954 let r#override = federation_identity
955 .map(|link| link.directive_name_in_schema(&FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC))
956 .unwrap_or(FEDERATION_OVERRIDE_DIRECTIVE_NAME_IN_SPEC);
957
958 let inaccessible = federation_identity
959 .map(|link| link.directive_name_in_schema(&INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC))
960 .unwrap_or(INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC);
961
962 Self {
963 key,
964 requires,
965 provides,
966 external,
967 interface_object,
968 r#override,
969 inaccessible,
970 }
971 }
972}
973
974const EXECUTABLE_DIRECTIVE_LOCATIONS: [DirectiveLocation; 8] = [
975 DirectiveLocation::Query,
976 DirectiveLocation::Mutation,
977 DirectiveLocation::Subscription,
978 DirectiveLocation::Field,
979 DirectiveLocation::FragmentDefinition,
980 DirectiveLocation::FragmentSpread,
981 DirectiveLocation::InlineFragment,
982 DirectiveLocation::VariableDefinition,
983];
984fn is_executable_directive(directive: &Node<DirectiveDefinition>) -> bool {
985 directive
986 .locations
987 .iter()
988 .any(|loc| EXECUTABLE_DIRECTIVE_LOCATIONS.contains(loc))
989}
990
991const FEDERATION_TYPES: [&str; 4] = ["_Any", "_Entity", "_Service", "@key"];
994fn is_mergeable_type(type_name: &str) -> bool {
995 if type_name.starts_with("federation__") || type_name.starts_with("link__") {
996 return false;
997 }
998 !FEDERATION_TYPES.contains(&type_name)
999}
1000
1001fn copy_scalar_type(scalar_name: Name, scalar_type: &Node<ScalarType>) -> ExtendedType {
1002 ExtendedType::Scalar(Node::new(ScalarType {
1003 description: scalar_type.description.clone(),
1004 name: scalar_name,
1005 directives: Default::default(),
1006 }))
1007}
1008
1009fn copy_enum_type(enum_name: Name, enum_type: &Node<EnumType>) -> ExtendedType {
1010 ExtendedType::Enum(Node::new(EnumType {
1011 description: enum_type.description.clone(),
1012 name: enum_name,
1013 directives: Default::default(),
1014 values: IndexMap::default(),
1015 }))
1016}
1017
1018fn copy_input_object_type(
1019 input_object_name: Name,
1020 input_object: &Node<InputObjectType>,
1021) -> ExtendedType {
1022 let mut new_input_object = InputObjectType {
1023 description: input_object.description.clone(),
1024 name: input_object_name,
1025 directives: Default::default(),
1026 fields: IndexMap::default(),
1027 };
1028
1029 for (field_name, input_field) in input_object.fields.iter() {
1030 new_input_object.fields.insert(
1031 field_name.clone(),
1032 Component::new(InputValueDefinition {
1033 name: input_field.name.clone(),
1034 description: input_field.description.clone(),
1035 directives: Default::default(),
1036 ty: input_field.ty.clone(),
1037 default_value: input_field.default_value.clone(),
1038 }),
1039 );
1040 }
1041
1042 ExtendedType::InputObject(Node::new(new_input_object))
1043}
1044
1045fn copy_interface_type(interface_name: Name, interface: &Node<InterfaceType>) -> ExtendedType {
1046 let new_interface = InterfaceType {
1047 description: interface.description.clone(),
1048 name: interface_name,
1049 directives: Default::default(),
1050 fields: copy_fields(interface.fields.iter()),
1051 implements_interfaces: interface.implements_interfaces.clone(),
1052 };
1053 ExtendedType::Interface(Node::new(new_interface))
1054}
1055
1056fn copy_object_type_stub(
1057 object_name: Name,
1058 object: &Node<ObjectType>,
1059 is_interface_object: bool,
1060) -> ExtendedType {
1061 if is_interface_object {
1062 let new_interface = InterfaceType {
1063 description: object.description.clone(),
1064 name: object_name,
1065 directives: Default::default(),
1066 fields: copy_fields(object.fields.iter()),
1067 implements_interfaces: object.implements_interfaces.clone(),
1068 };
1069 ExtendedType::Interface(Node::new(new_interface))
1070 } else {
1071 let new_object = ObjectType {
1072 description: object.description.clone(),
1073 name: object_name,
1074 directives: Default::default(),
1075 fields: copy_fields(object.fields.iter()),
1076 implements_interfaces: object.implements_interfaces.clone(),
1077 };
1078 ExtendedType::Object(Node::new(new_object))
1079 }
1080}
1081
1082fn copy_fields(
1083 fields_to_copy: Iter<Name, Component<FieldDefinition>>,
1084) -> IndexMap<Name, Component<FieldDefinition>> {
1085 let mut new_fields: IndexMap<Name, Component<FieldDefinition>> = IndexMap::default();
1086 for (field_name, field) in fields_to_copy {
1087 if field_name == "_service" || field_name == "_entities" {
1089 continue;
1090 }
1091 let args: Vec<Node<InputValueDefinition>> = field
1092 .arguments
1093 .iter()
1094 .map(|a| {
1095 Node::new(InputValueDefinition {
1096 name: a.name.clone(),
1097 description: a.description.clone(),
1098 directives: Default::default(),
1099 ty: a.ty.clone(),
1100 default_value: a.default_value.clone(),
1101 })
1102 })
1103 .collect();
1104 let new_field = Component::new(FieldDefinition {
1105 name: field.name.clone(),
1106 description: field.description.clone(),
1107 directives: Default::default(),
1108 arguments: args,
1109 ty: field.ty.clone(),
1110 });
1111
1112 new_fields.insert(field_name.clone(), new_field);
1113 }
1114 new_fields
1115}
1116
1117fn copy_union_type(union_name: Name, description: Option<Node<str>>) -> ExtendedType {
1118 ExtendedType::Union(Node::new(UnionType {
1119 description,
1120 name: union_name,
1121 directives: Default::default(),
1122 members: IndexSet::default(),
1123 }))
1124}
1125
1126fn join_type_applied_directive<'a>(
1127 subgraph_name: EnumValue,
1128 key_directives: impl Iterator<Item = &'a Component<Directive>> + Sized,
1129 is_interface_object: bool,
1130) -> Vec<Component<Directive>> {
1131 let mut join_type_directive = Directive {
1132 name: name!("join__type"),
1133 arguments: vec![Node::new(Argument {
1134 name: name!("graph"),
1135 value: Node::new(Value::Enum(subgraph_name.into())),
1136 })],
1137 };
1138 if is_interface_object {
1139 join_type_directive.arguments.push(Node::new(Argument {
1140 name: name!("isInterfaceObject"),
1141 value: Node::new(Value::Boolean(is_interface_object)),
1142 }));
1143 }
1144
1145 let mut result = vec![];
1146 for key_directive in key_directives {
1147 let mut join_type_directive_with_key = join_type_directive.clone();
1148 let field_set = directive_string_arg_value(key_directive, &name!("fields")).unwrap();
1149 join_type_directive_with_key
1150 .arguments
1151 .push(Node::new(Argument {
1152 name: name!("key"),
1153 value: field_set.into(),
1154 }));
1155
1156 let resolvable =
1157 directive_bool_arg_value(key_directive, &name!("resolvable")).unwrap_or(&true);
1158 if !resolvable {
1159 join_type_directive_with_key
1160 .arguments
1161 .push(Node::new(Argument {
1162 name: name!("resolvable"),
1163 value: Node::new(Value::Boolean(false)),
1164 }));
1165 }
1166 result.push(join_type_directive_with_key)
1167 }
1168 if result.is_empty() {
1169 result.push(join_type_directive)
1170 }
1171 result
1172 .into_iter()
1173 .map(Component::new)
1174 .collect::<Vec<Component<Directive>>>()
1175}
1176
1177fn join_implements_applied_directive(
1178 subgraph_name: EnumValue,
1179 intf_name: &Name,
1180) -> Component<Directive> {
1181 Component::new(Directive {
1182 name: name!("join__implements"),
1183 arguments: vec![
1184 Node::new(Argument {
1185 name: name!("graph"),
1186 value: Node::new(Value::Enum(subgraph_name.into())),
1187 }),
1188 Node::new(Argument {
1189 name: name!("interface"),
1190 value: intf_name.as_str().into(),
1191 }),
1192 ],
1193 })
1194}
1195
1196fn directive_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a Value> {
1197 directive
1198 .arguments
1199 .iter()
1200 .find(|arg| arg.name == *arg_name)
1201 .map(|arg| arg.value.as_ref())
1202}
1203
1204fn directive_string_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a str> {
1205 match directive_arg_value(directive, arg_name) {
1206 Some(Value::String(value)) => Some(value),
1207 _ => None,
1208 }
1209}
1210
1211fn directive_bool_arg_value<'a>(directive: &'a Directive, arg_name: &Name) -> Option<&'a bool> {
1212 match directive_arg_value(directive, arg_name) {
1213 Some(Value::Boolean(value)) => Some(value),
1214 _ => None,
1215 }
1216}
1217
1218fn add_core_feature_link(supergraph: &mut Schema) {
1220 supergraph
1222 .schema_definition
1223 .make_mut()
1224 .directives
1225 .push(Component::new(Directive {
1226 name: name!("link"),
1227 arguments: vec![Node::new(Argument {
1228 name: name!("url"),
1229 value: Node::new("https://specs.apollo.dev/link/v1.0".into()),
1230 })],
1231 }));
1232
1233 let (name, link_purpose_enum) = link_purpose_enum_type();
1234 supergraph.types.insert(name, link_purpose_enum.into());
1235
1236 let link_import_name = name!("link__Import");
1238 let link_import_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1239 directives: Default::default(),
1240 name: link_import_name.clone(),
1241 description: None,
1242 }));
1243 supergraph
1244 .types
1245 .insert(link_import_name, link_import_scalar);
1246
1247 let link_directive_definition = link_directive_definition();
1248 supergraph
1249 .directive_definitions
1250 .insert(name!("link"), Node::new(link_directive_definition));
1251}
1252
1253fn link_directive_definition() -> DirectiveDefinition {
1255 DirectiveDefinition {
1256 name: name!("link"),
1257 description: None,
1258 arguments: vec![
1259 Node::new(InputValueDefinition {
1260 name: name!("url"),
1261 description: None,
1262 directives: Default::default(),
1263 ty: ty!(String).into(),
1264 default_value: None,
1265 }),
1266 Node::new(InputValueDefinition {
1267 name: name!("as"),
1268 description: None,
1269 directives: Default::default(),
1270 ty: ty!(String).into(),
1271 default_value: None,
1272 }),
1273 Node::new(InputValueDefinition {
1274 name: name!("for"),
1275 description: None,
1276 directives: Default::default(),
1277 ty: ty!(link__Purpose).into(),
1278 default_value: None,
1279 }),
1280 Node::new(InputValueDefinition {
1281 name: name!("import"),
1282 description: None,
1283 directives: Default::default(),
1284 ty: ty!([link__Import]).into(),
1285 default_value: None,
1286 }),
1287 ],
1288 locations: vec![DirectiveLocation::Schema],
1289 repeatable: true,
1290 }
1291}
1292
1293fn link_purpose_enum_type() -> (Name, EnumType) {
1305 let link_purpose_name = name!("link__Purpose");
1306 let mut link_purpose_enum = EnumType {
1307 description: None,
1308 name: link_purpose_name.clone(),
1309 directives: Default::default(),
1310 values: IndexMap::default(),
1311 };
1312 let link_purpose_security_value = EnumValueDefinition {
1313 description: Some(
1314 r"SECURITY features provide metadata necessary to securely resolve fields.".into(),
1315 ),
1316 directives: Default::default(),
1317 value: name!("SECURITY"),
1318 };
1319 let link_purpose_execution_value = EnumValueDefinition {
1320 description: Some(
1321 r"EXECUTION features provide metadata necessary for operation execution.".into(),
1322 ),
1323 directives: Default::default(),
1324 value: name!("EXECUTION"),
1325 };
1326 link_purpose_enum.values.insert(
1327 link_purpose_security_value.value.clone(),
1328 Component::new(link_purpose_security_value),
1329 );
1330 link_purpose_enum.values.insert(
1331 link_purpose_execution_value.value.clone(),
1332 Component::new(link_purpose_execution_value),
1333 );
1334 (link_purpose_name, link_purpose_enum)
1335}
1336
1337fn add_core_feature_join(
1339 supergraph: &mut Schema,
1340 subgraphs_and_enum_values: &Vec<(&ValidFederationSubgraph, EnumValue)>,
1341) {
1342 supergraph
1344 .schema_definition
1345 .make_mut()
1346 .directives
1347 .push(Component::new(Directive {
1348 name: name!("link"),
1349 arguments: vec![
1350 Node::new(Argument {
1351 name: name!("url"),
1352 value: "https://specs.apollo.dev/join/v0.5".into(),
1353 }),
1354 Node::new(Argument {
1355 name: name!("for"),
1356 value: Node::new(Value::Enum(name!("EXECUTION"))),
1357 }),
1358 ],
1359 }));
1360
1361 let join_field_set_name = name!("join__FieldSet");
1363 let join_field_set_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1364 directives: Default::default(),
1365 name: join_field_set_name.clone(),
1366 description: None,
1367 }));
1368 supergraph
1369 .types
1370 .insert(join_field_set_name, join_field_set_scalar);
1371
1372 let join_field_value_name = name!("join__FieldValue");
1374 let join_field_value_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1375 directives: Default::default(),
1376 name: join_field_value_name.clone(),
1377 description: None,
1378 }));
1379 supergraph
1380 .types
1381 .insert(join_field_value_name, join_field_value_scalar);
1382
1383 let join_context_argument_name = name!("join__ContextArgument");
1390 let join_context_argument_input = ExtendedType::InputObject(Node::new(InputObjectType {
1391 description: None,
1392 name: join_context_argument_name.clone(),
1393 directives: Default::default(),
1394 fields: vec![
1395 (
1396 name!("name"),
1397 Component::new(InputValueDefinition {
1398 name: name!("name"),
1399 description: None,
1400 directives: Default::default(),
1401 ty: ty!(String!).into(),
1402 default_value: None,
1403 }),
1404 ),
1405 (
1406 name!("type"),
1407 Component::new(InputValueDefinition {
1408 name: name!("type"),
1409 description: None,
1410 directives: Default::default(),
1411 ty: ty!(String!).into(),
1412 default_value: None,
1413 }),
1414 ),
1415 (
1416 name!("context"),
1417 Component::new(InputValueDefinition {
1418 name: name!("context"),
1419 description: None,
1420 directives: Default::default(),
1421 ty: ty!(String!).into(),
1422 default_value: None,
1423 }),
1424 ),
1425 (
1426 name!("selection"),
1427 Component::new(InputValueDefinition {
1428 name: name!("selection"),
1429 description: None,
1430 directives: Default::default(),
1431 ty: ty!(join__FieldValue!).into(),
1432 default_value: None,
1433 }),
1434 ),
1435 ]
1436 .into_iter()
1437 .collect(),
1438 }));
1439 supergraph
1440 .types
1441 .insert(join_context_argument_name, join_context_argument_input);
1442
1443 let join_graph_directive_definition = join_graph_directive_definition();
1444 supergraph.directive_definitions.insert(
1445 join_graph_directive_definition.name.clone(),
1446 Node::new(join_graph_directive_definition),
1447 );
1448
1449 let join_type_directive_definition = join_type_directive_definition();
1450 supergraph.directive_definitions.insert(
1451 join_type_directive_definition.name.clone(),
1452 Node::new(join_type_directive_definition),
1453 );
1454
1455 let join_field_directive_definition = join_field_directive_definition();
1456 supergraph.directive_definitions.insert(
1457 join_field_directive_definition.name.clone(),
1458 Node::new(join_field_directive_definition),
1459 );
1460
1461 let join_implements_directive_definition = join_implements_directive_definition();
1462 supergraph.directive_definitions.insert(
1463 join_implements_directive_definition.name.clone(),
1464 Node::new(join_implements_directive_definition),
1465 );
1466
1467 let join_union_member_directive_definition = join_union_member_directive_definition();
1468 supergraph.directive_definitions.insert(
1469 join_union_member_directive_definition.name.clone(),
1470 Node::new(join_union_member_directive_definition),
1471 );
1472
1473 let join_enum_value_directive_definition = join_enum_value_directive_definition();
1474 supergraph.directive_definitions.insert(
1475 join_enum_value_directive_definition.name.clone(),
1476 Node::new(join_enum_value_directive_definition),
1477 );
1478
1479 let join_directive_arguments_name = name!("join__DirectiveArguments");
1481 let join_directive_arguments_scalar = ExtendedType::Scalar(Node::new(ScalarType {
1482 directives: Default::default(),
1483 name: join_directive_arguments_name.clone(),
1484 description: None,
1485 }));
1486 supergraph.types.insert(
1487 join_directive_arguments_name,
1488 join_directive_arguments_scalar,
1489 );
1490
1491 let join_directive_directive_definition = join_directive_directive_definition();
1492 supergraph.directive_definitions.insert(
1493 join_directive_directive_definition.name.clone(),
1494 Node::new(join_directive_directive_definition),
1495 );
1496
1497 let (name, join_graph_enum_type) = join_graph_enum_type(subgraphs_and_enum_values);
1498 supergraph.types.insert(name, join_graph_enum_type.into());
1499}
1500
1501fn join_enum_value_directive_definition() -> DirectiveDefinition {
1503 DirectiveDefinition {
1504 name: name!("join__enumValue"),
1505 description: None,
1506 arguments: vec![Node::new(InputValueDefinition {
1507 name: name!("graph"),
1508 description: None,
1509 directives: Default::default(),
1510 ty: ty!(join__Graph!).into(),
1511 default_value: None,
1512 })],
1513 locations: vec![DirectiveLocation::EnumValue],
1514 repeatable: true,
1515 }
1516}
1517
1518fn join_directive_directive_definition() -> DirectiveDefinition {
1520 DirectiveDefinition {
1521 name: name!("join__directive"),
1522 description: None,
1523 arguments: vec![
1524 Node::new(InputValueDefinition {
1525 name: name!("graphs"),
1526 description: None,
1527 directives: Default::default(),
1528 ty: ty!([join__Graph!]).into(),
1529 default_value: None,
1530 }),
1531 Node::new(InputValueDefinition {
1532 name: name!("name"),
1533 description: None,
1534 directives: Default::default(),
1535 ty: ty!(String!).into(),
1536 default_value: None,
1537 }),
1538 Node::new(InputValueDefinition {
1539 name: name!("args"),
1540 description: None,
1541 directives: Default::default(),
1542 ty: ty!(join__DirectiveArguments!).into(),
1543 default_value: None,
1544 }),
1545 ],
1546 locations: vec![
1547 DirectiveLocation::Schema,
1548 DirectiveLocation::Object,
1549 DirectiveLocation::Interface,
1550 DirectiveLocation::FieldDefinition,
1551 ],
1552 repeatable: true,
1553 }
1554}
1555
1556fn join_field_directive_definition() -> DirectiveDefinition {
1566 DirectiveDefinition {
1567 name: name!("join__field"),
1568 description: None,
1569 arguments: vec![
1570 Node::new(InputValueDefinition {
1571 name: name!("graph"),
1572 description: None,
1573 directives: Default::default(),
1574 ty: ty!(join__Graph).into(),
1575 default_value: None,
1576 }),
1577 Node::new(InputValueDefinition {
1578 name: name!("requires"),
1579 description: None,
1580 directives: Default::default(),
1581 ty: ty!(join__FieldSet).into(),
1582 default_value: None,
1583 }),
1584 Node::new(InputValueDefinition {
1585 name: name!("provides"),
1586 description: None,
1587 directives: Default::default(),
1588 ty: ty!(join__FieldSet).into(),
1589 default_value: None,
1590 }),
1591 Node::new(InputValueDefinition {
1592 name: name!("type"),
1593 description: None,
1594 directives: Default::default(),
1595 ty: ty!(String).into(),
1596 default_value: None,
1597 }),
1598 Node::new(InputValueDefinition {
1599 name: name!("external"),
1600 description: None,
1601 directives: Default::default(),
1602 ty: ty!(Boolean).into(),
1603 default_value: None,
1604 }),
1605 Node::new(InputValueDefinition {
1606 name: name!("override"),
1607 description: None,
1608 directives: Default::default(),
1609 ty: ty!(String).into(),
1610 default_value: None,
1611 }),
1612 Node::new(InputValueDefinition {
1613 name: JOIN_OVERRIDE_LABEL_ARGUMENT_NAME,
1614 description: None,
1615 directives: Default::default(),
1616 ty: ty!(String).into(),
1617 default_value: None,
1618 }),
1619 Node::new(InputValueDefinition {
1620 name: name!("usedOverridden"),
1621 description: None,
1622 directives: Default::default(),
1623 ty: ty!(Boolean).into(),
1624 default_value: None,
1625 }),
1626 Node::new(InputValueDefinition {
1627 name: name!("contextArguments"),
1628 description: None,
1629 directives: Default::default(),
1630 ty: ty!([join__ContextArgument!]).into(),
1631 default_value: None,
1632 }),
1633 ],
1634 locations: vec![
1635 DirectiveLocation::FieldDefinition,
1636 DirectiveLocation::InputFieldDefinition,
1637 ],
1638 repeatable: true,
1639 }
1640}
1641
1642fn join_field_applied_directive(
1646 subgraph_name: &EnumValue,
1647 requires: Option<&str>,
1648 provides: Option<&str>,
1649 external: bool,
1650 overrides: Option<(&str, Option<&str>)>, r#type: Option<&Type>,
1652) -> Directive {
1653 let mut join_field_directive = Directive {
1654 name: name!("join__field"),
1655 arguments: vec![Node::new(Argument {
1656 name: name!("graph"),
1657 value: Node::new(Value::Enum(subgraph_name.to_name())),
1658 })],
1659 };
1660 if let Some(required_fields) = requires {
1661 join_field_directive.arguments.push(Node::new(Argument {
1662 name: name!("requires"),
1663 value: required_fields.into(),
1664 }));
1665 }
1666 if let Some(provided_fields) = provides {
1667 join_field_directive.arguments.push(Node::new(Argument {
1668 name: name!("provides"),
1669 value: provided_fields.into(),
1670 }));
1671 }
1672 if external {
1673 join_field_directive.arguments.push(Node::new(Argument {
1674 name: name!("external"),
1675 value: external.into(),
1676 }));
1677 }
1678 if let Some((from, label)) = overrides {
1679 join_field_directive.arguments.push(Node::new(Argument {
1680 name: name!("override"),
1681 value: Node::new(Value::String(from.to_string())),
1682 }));
1683 if let Some(label) = label {
1684 join_field_directive.arguments.push(Node::new(Argument {
1685 name: name!("overrideLabel"),
1686 value: Node::new(Value::String(label.to_string())),
1687 }));
1688 }
1689 }
1690 if let Some(r#type) = r#type {
1691 join_field_directive.arguments.push(Node::new(Argument {
1692 name: name!("type"),
1693 value: r#type.to_string().into(),
1694 }));
1695 }
1696 join_field_directive
1697}
1698
1699fn join_graph_directive_definition() -> DirectiveDefinition {
1701 DirectiveDefinition {
1702 name: name!("join__graph"),
1703 description: None,
1704 arguments: vec![
1705 Node::new(InputValueDefinition {
1706 name: name!("name"),
1707 description: None,
1708 directives: Default::default(),
1709 ty: ty!(String!).into(),
1710 default_value: None,
1711 }),
1712 Node::new(InputValueDefinition {
1713 name: name!("url"),
1714 description: None,
1715 directives: Default::default(),
1716 ty: ty!(String!).into(),
1717 default_value: None,
1718 }),
1719 ],
1720 locations: vec![DirectiveLocation::EnumValue],
1721 repeatable: false,
1722 }
1723}
1724
1725fn join_implements_directive_definition() -> DirectiveDefinition {
1730 DirectiveDefinition {
1731 name: name!("join__implements"),
1732 description: None,
1733 arguments: vec![
1734 Node::new(InputValueDefinition {
1735 name: name!("graph"),
1736 description: None,
1737 directives: Default::default(),
1738 ty: ty!(join__Graph!).into(),
1739 default_value: None,
1740 }),
1741 Node::new(InputValueDefinition {
1742 name: name!("interface"),
1743 description: None,
1744 directives: Default::default(),
1745 ty: ty!(String!).into(),
1746 default_value: None,
1747 }),
1748 ],
1749 locations: vec![DirectiveLocation::Interface, DirectiveLocation::Object],
1750 repeatable: true,
1751 }
1752}
1753
1754fn join_type_directive_definition() -> DirectiveDefinition {
1762 DirectiveDefinition {
1763 name: name!("join__type"),
1764 description: None,
1765 arguments: vec![
1766 Node::new(InputValueDefinition {
1767 name: name!("graph"),
1768 description: None,
1769 directives: Default::default(),
1770 ty: ty!(join__Graph!).into(),
1771 default_value: None,
1772 }),
1773 Node::new(InputValueDefinition {
1774 name: name!("key"),
1775 description: None,
1776 directives: Default::default(),
1777 ty: ty!(join__FieldSet).into(),
1778 default_value: None,
1779 }),
1780 Node::new(InputValueDefinition {
1781 name: name!("extension"),
1782 description: None,
1783 directives: Default::default(),
1784 ty: ty!(Boolean!).into(),
1785 default_value: Some(Node::new(Value::Boolean(false))),
1786 }),
1787 Node::new(InputValueDefinition {
1788 name: name!("resolvable"),
1789 description: None,
1790 directives: Default::default(),
1791 ty: ty!(Boolean!).into(),
1792 default_value: Some(Node::new(Value::Boolean(true))),
1793 }),
1794 Node::new(InputValueDefinition {
1795 name: name!("isInterfaceObject"),
1796 description: None,
1797 directives: Default::default(),
1798 ty: ty!(Boolean!).into(),
1799 default_value: Some(Node::new(Value::Boolean(false))),
1800 }),
1801 ],
1802 locations: vec![
1803 DirectiveLocation::Enum,
1804 DirectiveLocation::InputObject,
1805 DirectiveLocation::Interface,
1806 DirectiveLocation::Object,
1807 DirectiveLocation::Scalar,
1808 DirectiveLocation::Union,
1809 ],
1810 repeatable: true,
1811 }
1812}
1813
1814fn join_union_member_directive_definition() -> DirectiveDefinition {
1816 DirectiveDefinition {
1817 name: name!("join__unionMember"),
1818 description: None,
1819 arguments: vec![
1820 Node::new(InputValueDefinition {
1821 name: name!("graph"),
1822 description: None,
1823 directives: Default::default(),
1824 ty: ty!(join__Graph!).into(),
1825 default_value: None,
1826 }),
1827 Node::new(InputValueDefinition {
1828 name: name!("member"),
1829 description: None,
1830 directives: Default::default(),
1831 ty: ty!(String!).into(),
1832 default_value: None,
1833 }),
1834 ],
1835 locations: vec![DirectiveLocation::Union],
1836 repeatable: true,
1837 }
1838}
1839
1840fn join_graph_enum_type(
1842 subgraphs_and_enum_values: &Vec<(&ValidFederationSubgraph, EnumValue)>,
1843) -> (Name, EnumType) {
1844 let join_graph_enum_name = name!("join__Graph");
1845 let mut join_graph_enum_type = EnumType {
1846 description: None,
1847 name: join_graph_enum_name.clone(),
1848 directives: Default::default(),
1849 values: IndexMap::default(),
1850 };
1851 for (s, subgraph_name) in subgraphs_and_enum_values {
1852 let join_graph_applied_directive = Directive {
1853 name: name!("join__graph"),
1854 arguments: vec![
1855 (Node::new(Argument {
1856 name: name!("name"),
1857 value: s.name.as_str().into(),
1858 })),
1859 (Node::new(Argument {
1860 name: name!("url"),
1861 value: s.url.as_str().into(),
1862 })),
1863 ],
1864 };
1865 let graph = EnumValueDefinition {
1866 description: None,
1867 directives: DirectiveList(vec![Node::new(join_graph_applied_directive)]),
1868 value: subgraph_name.to_name(),
1869 };
1870 join_graph_enum_type
1871 .values
1872 .insert(graph.value.clone(), Component::new(graph));
1873 }
1874 (join_graph_enum_name, join_graph_enum_type)
1875}
1876
1877fn add_core_feature_inaccessible(supergraph: &mut Schema) {
1878 let spec = InaccessibleSpecDefinition::new(
1880 Version { major: 0, minor: 2 },
1881 Version { major: 2, minor: 0 },
1882 );
1883
1884 supergraph
1885 .schema_definition
1886 .make_mut()
1887 .directives
1888 .push(Component::new(Directive {
1889 name: name!("link"),
1890 arguments: vec![
1891 Node::new(Argument {
1892 name: name!("url"),
1893 value: spec.to_string().into(),
1894 }),
1895 Node::new(Argument {
1896 name: name!("for"),
1897 value: Node::new(Value::Enum(name!("SECURITY"))),
1898 }),
1899 ],
1900 }));
1901
1902 supergraph.directive_definitions.insert(
1903 INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
1904 Node::new(DirectiveDefinition {
1905 name: INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
1906 description: None,
1907 arguments: vec![],
1908 locations: vec![
1909 DirectiveLocation::FieldDefinition,
1910 DirectiveLocation::Object,
1911 DirectiveLocation::Interface,
1912 DirectiveLocation::Union,
1913 DirectiveLocation::ArgumentDefinition,
1914 DirectiveLocation::Scalar,
1915 DirectiveLocation::Enum,
1916 DirectiveLocation::EnumValue,
1917 DirectiveLocation::InputObject,
1918 DirectiveLocation::InputFieldDefinition,
1919 ],
1920 repeatable: false,
1921 }),
1922 );
1923}
1924
1925fn merge_directive(
1926 supergraph_directives: &mut IndexMap<Name, Node<DirectiveDefinition>>,
1927 directive: &Node<DirectiveDefinition>,
1928) {
1929 if !supergraph_directives.contains_key(&directive.name.clone()) {
1930 supergraph_directives.insert(directive.name.clone(), directive.clone());
1931 }
1932}
1933
1934#[cfg(test)]
1935mod tests;