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 let _ = crate::compat::coerce_and_validate_schema_values(&mut supergraph);
269 let supergraph = Valid::assume_valid(supergraph);
270 Ok(MergeSuccess {
271 schema: supergraph,
272 composition_hints: self.composition_hints.to_owned(),
273 })
274 } else {
275 Err(MergeFailure {
276 schema: Some(Box::new(supergraph)),
277 composition_hints: self.composition_hints.to_owned(),
278 errors: self.errors.to_owned(),
279 })
280 }
281 }
282
283 fn add_interface_object_fields(
284 &mut self,
285 types: &mut IndexMap<NamedType, ExtendedType>,
286 implementers_map: HashMap<Name, Implementers>,
287 ) -> Result<(), MergeFailure> {
288 for interface_object_name in self.interface_objects.iter() {
289 let Some(ExtendedType::Interface(intf_def)) = types.get(interface_object_name) else {
290 return Err(MergeFailure {
291 schema: None,
292 composition_hints: self.composition_hints.to_owned(),
293 errors: vec![format!("Interface {} not found", interface_object_name)],
294 });
295 };
296 let fields = intf_def.fields.clone();
297
298 if let Some(implementers) = implementers_map.get(interface_object_name) {
299 for implementer in implementers.iter() {
300 types.entry(implementer.clone()).and_modify(|f| {
301 if let ExtendedType::Object(obj) = f {
302 let obj = obj.make_mut();
303 for (field_name, field_def) in fields.iter() {
304 let mut field_def = field_def.clone();
305 let field_def = field_def.make_mut();
306 field_def.directives = field_def
307 .directives
308 .iter()
309 .filter(|d| d.name != name!("join__field"))
310 .cloned()
311 .collect();
312 field_def.directives.push(Node::new(Directive {
313 name: name!("join__field"),
314 arguments: vec![],
315 }));
316
317 obj.fields
318 .entry(field_name.clone())
319 .or_insert(field_def.clone().into());
320 }
321 }
322 });
323 }
324 };
325 }
326
327 Ok(())
328 }
329
330 fn merge_descriptions<T: Eq + Clone>(&mut self, merged: &mut Option<T>, new: &Option<T>) {
331 match (&mut *merged, new) {
332 (_, None) => {}
333 (None, Some(_)) => merged.clone_from(new),
334 (Some(a), Some(b)) => {
335 if a != b {
336 self.composition_hints
338 .push(String::from("conflicting descriptions"));
339 }
340 }
341 }
342 }
343
344 fn merge_schema(&mut self, supergraph_schema: &mut Schema, subgraph: &ValidFederationSubgraph) {
345 let supergraph_def = &mut supergraph_schema.schema_definition.make_mut();
346 let subgraph_def = &subgraph.schema.schema().schema_definition;
347 self.merge_descriptions(&mut supergraph_def.description, &subgraph_def.description);
348
349 if subgraph_def.query.is_some() {
350 supergraph_def.query.clone_from(&subgraph_def.query);
351 }
353 if subgraph_def.mutation.is_some() {
354 supergraph_def.mutation.clone_from(&subgraph_def.mutation);
355 }
357 if subgraph_def.subscription.is_some() {
358 supergraph_def
359 .subscription
360 .clone_from(&subgraph_def.subscription);
361 }
363 }
364
365 fn merge_enum_type(
366 &mut self,
367 types: &mut IndexMap<NamedType, ExtendedType>,
368 metadata: &DirectiveNames,
369 subgraph_name: &EnumValue,
370 enum_name: NamedType,
371 enum_type: &Node<EnumType>,
372 ) {
373 let existing_type = types
374 .entry(enum_name.clone())
375 .or_insert(copy_enum_type(enum_name, enum_type));
376
377 if let ExtendedType::Enum(e) = existing_type {
378 let join_type_directives =
379 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
380 e.make_mut().directives.extend(join_type_directives);
381
382 self.add_inaccessible(
383 metadata,
384 &mut e.make_mut().directives,
385 &enum_type.directives,
386 );
387
388 self.merge_descriptions(&mut e.make_mut().description, &enum_type.description);
389
390 for (enum_value_name, enum_value) in enum_type.values.iter() {
393 let ev = e
394 .make_mut()
395 .values
396 .entry(enum_value_name.clone())
397 .or_insert(Component::new(EnumValueDefinition {
398 value: enum_value.value.clone(),
399 description: None,
400 directives: Default::default(),
401 }));
402 self.merge_descriptions(&mut ev.make_mut().description, &enum_value.description);
403
404 self.add_inaccessible(
405 metadata,
406 &mut ev.make_mut().directives,
407 &enum_value.directives,
408 );
409
410 ev.make_mut().directives.push(Node::new(Directive {
411 name: name!("join__enumValue"),
412 arguments: vec![
413 (Node::new(Argument {
414 name: name!("graph"),
415 value: Node::new(Value::Enum(subgraph_name.to_name())),
416 })),
417 ],
418 }));
419 }
420 } else {
421 }
423 }
424
425 fn merge_input_object_type(
426 &mut self,
427 types: &mut IndexMap<NamedType, ExtendedType>,
428 directive_names: &DirectiveNames,
429 subgraph_name: &EnumValue,
430 input_object_name: NamedType,
431 input_object: &Node<InputObjectType>,
432 ) {
433 let existing_type = types
434 .entry(input_object_name.clone())
435 .or_insert(copy_input_object_type(input_object_name, input_object));
436
437 if let ExtendedType::InputObject(obj) = existing_type {
438 let join_type_directives =
439 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
440 let mutable_object = obj.make_mut();
441 mutable_object.directives.extend(join_type_directives);
442
443 self.add_inaccessible(
444 directive_names,
445 &mut mutable_object.directives,
446 &input_object.directives,
447 );
448
449 for (field_name, field) in input_object.fields.iter() {
450 let existing_field = mutable_object.fields.entry(field_name.clone());
451
452 let supergraph_field = match existing_field {
453 Vacant(i) => i.insert(Component::new(InputValueDefinition {
454 name: field.name.clone(),
455 description: field.description.clone(),
456 ty: field.ty.clone(),
457 default_value: field.default_value.clone(),
458 directives: Default::default(),
459 })),
460 Occupied(i) => {
461 i.into_mut()
462 }
468 };
469
470 self.add_inaccessible(
471 directive_names,
472 &mut supergraph_field.make_mut().directives,
473 &field.directives,
474 );
475
476 let join_field_directive = join_field_applied_directive(
477 subgraph_name,
478 None,
479 None,
480 false,
481 None,
482 Some(&field.ty),
483 );
484 supergraph_field
485 .make_mut()
486 .directives
487 .push(Node::new(join_field_directive));
488 }
489 } else {
490 }
492 }
493
494 fn merge_interface_type(
495 &mut self,
496 types: &mut IndexMap<NamedType, ExtendedType>,
497 directive_names: &DirectiveNames,
498 subgraph_name: &EnumValue,
499 interface_name: NamedType,
500 interface: &Node<InterfaceType>,
501 ) {
502 let existing_type = types
503 .entry(interface_name.clone())
504 .or_insert(copy_interface_type(interface_name, interface));
505
506 if let ExtendedType::Interface(intf) = existing_type {
507 let key_directives = interface.directives.get_all(&directive_names.key);
508 let join_type_directives =
509 join_type_applied_directive(subgraph_name.clone(), key_directives, false);
510 let mutable_intf = intf.make_mut();
511 mutable_intf.directives.extend(join_type_directives);
512
513 self.add_inaccessible(
514 directive_names,
515 &mut mutable_intf.directives,
516 &interface.directives,
517 );
518
519 interface
520 .implements_interfaces
521 .iter()
522 .for_each(|intf_name| {
523 mutable_intf.implements_interfaces.insert(intf_name.clone());
525 let join_implements_directive =
526 join_implements_applied_directive(subgraph_name.clone(), intf_name);
527 mutable_intf.directives.push(join_implements_directive);
528 });
529
530 for (field_name, field) in interface.fields.iter() {
531 let existing_field = mutable_intf.fields.entry(field_name.clone());
532 let supergraph_field = match existing_field {
533 Occupied(f) => {
534 f.into_mut()
535 }
540 Vacant(f) => {
541 f.insert(Component::new(FieldDefinition {
543 name: field.name.clone(),
544 description: field.description.clone(),
545 arguments: vec![],
546 ty: field.ty.clone(),
547 directives: Default::default(),
548 }))
549 }
550 };
551
552 fields::merge_arguments(
553 field.arguments.iter(),
554 &mut supergraph_field.make_mut().arguments,
555 self,
556 directive_names,
557 );
558 self.merge_descriptions(
559 &mut supergraph_field.make_mut().description,
560 &field.description,
561 );
562
563 self.add_inaccessible(
564 directive_names,
565 &mut supergraph_field.make_mut().directives,
566 &field.directives,
567 );
568
569 let join_field_directive = join_field_applied_directive(
570 subgraph_name,
571 None,
572 None,
573 false,
574 None,
575 Some(&field.ty),
576 );
577
578 supergraph_field
579 .make_mut()
580 .directives
581 .push(Node::new(join_field_directive));
582 }
583 } else {
584 }
586 }
587
588 fn merge_object_type(
589 &mut self,
590 types: &mut IndexMap<NamedType, ExtendedType>,
591 directive_names: &DirectiveNames,
592 subgraph_name: &EnumValue,
593 object_name: NamedType,
594 object: &Node<ObjectType>,
595 ) {
596 let is_interface_object = object.directives.has(&directive_names.interface_object);
597 let existing_type = types
598 .entry(object_name.clone())
599 .or_insert(copy_object_type_stub(
600 object_name,
601 object,
602 is_interface_object,
603 ));
604
605 if let ExtendedType::Object(obj) = existing_type {
606 let key_directives = object.directives.get_all(&directive_names.key);
607 let join_type_directives =
608 join_type_applied_directive(subgraph_name.clone(), key_directives, false);
609 let mutable_object = obj.make_mut();
610 mutable_object.directives.extend(join_type_directives);
611 self.merge_descriptions(&mut mutable_object.description, &object.description);
612 self.add_inaccessible(
613 directive_names,
614 &mut mutable_object.directives,
615 &object.directives,
616 );
617 object.implements_interfaces.iter().for_each(|intf_name| {
618 mutable_object
620 .implements_interfaces
621 .insert(intf_name.clone());
622 let join_implements_directive =
623 join_implements_applied_directive(subgraph_name.clone(), intf_name);
624 mutable_object.directives.push(join_implements_directive);
625 });
626
627 for (field_name, field) in object.fields.iter() {
628 if field_name == "_service" || field_name == "_entities" {
630 continue;
631 }
632
633 let existing_field = mutable_object.fields.entry(field_name.clone());
634 let supergraph_field = match existing_field {
635 Occupied(f) => {
636 f.into_mut()
640 }
641 Vacant(f) => f.insert(Component::new(FieldDefinition {
642 name: field.name.clone(),
643 description: field.description.clone(),
644 arguments: vec![],
645 directives: Default::default(),
646 ty: field.ty.clone(),
647 })),
648 };
649 self.merge_descriptions(
650 &mut supergraph_field.make_mut().description,
651 &field.description,
652 );
653
654 self.add_inaccessible(
655 directive_names,
656 &mut supergraph_field.make_mut().directives,
657 &field.directives,
658 );
659
660 fields::merge_arguments(
661 field.arguments.iter(),
662 &mut supergraph_field.make_mut().arguments,
663 self,
664 directive_names,
665 );
666
667 let requires_directive_option = field
668 .directives
669 .get_all(&directive_names.requires)
670 .next()
671 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
672
673 let provides_directive_option = field
674 .directives
675 .get_all(&directive_names.provides)
676 .next()
677 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
678
679 let overrides_directive_option = field
680 .directives
681 .get_all(&directive_names.r#override)
682 .next()
683 .and_then(|p| {
684 let overrides_from =
685 directive_string_arg_value(p, &FEDERATION_FROM_ARGUMENT_NAME);
686 let overrides_label =
687 directive_string_arg_value(p, &FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME);
688 overrides_from.map(|from| (from, overrides_label))
689 });
690
691 let external_field = field
692 .directives
693 .get_all(&directive_names.external)
694 .next()
695 .is_some();
696
697 let join_field_directive = join_field_applied_directive(
698 subgraph_name,
699 requires_directive_option,
700 provides_directive_option,
701 external_field,
702 overrides_directive_option,
703 Some(&field.ty),
704 );
705
706 supergraph_field
707 .make_mut()
708 .directives
709 .push(Node::new(join_field_directive));
710
711 }
714 } else if let ExtendedType::Interface(intf) = existing_type {
715 self.interface_objects.insert(intf.name.clone());
716
717 let key_directives = object.directives.get_all(&directive_names.key);
718 let join_type_directives =
719 join_type_applied_directive(subgraph_name.clone(), key_directives, true);
720 let mutable_object = intf.make_mut();
721 mutable_object.directives.extend(join_type_directives);
722 self.merge_descriptions(&mut mutable_object.description, &object.description);
723 self.add_inaccessible(
724 directive_names,
725 &mut mutable_object.directives,
726 &object.directives,
727 );
728
729 for (field_name, field) in object.fields.iter() {
730 if field_name == "_service" || field_name == "_entities" {
732 continue;
733 }
734
735 let existing_field = mutable_object.fields.entry(field_name.clone());
736 let supergraph_field = match existing_field {
737 Occupied(f) => {
738 f.into_mut()
742 }
743 Vacant(f) => f.insert(Component::new(FieldDefinition {
744 name: field.name.clone(),
745 description: field.description.clone(),
746 arguments: vec![],
747 directives: Default::default(),
748 ty: field.ty.clone(),
749 })),
750 };
751 self.merge_descriptions(
752 &mut supergraph_field.make_mut().description,
753 &field.description,
754 );
755
756 self.add_inaccessible(
757 directive_names,
758 &mut supergraph_field.make_mut().directives,
759 &field.directives,
760 );
761
762 fields::merge_arguments(
763 field.arguments.iter(),
764 &mut supergraph_field.make_mut().arguments,
765 self,
766 directive_names,
767 );
768 let requires_directive_option = field
769 .directives
770 .get_all(&directive_names.requires)
771 .next()
772 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
773
774 let provides_directive_option = field
775 .directives
776 .get_all(&directive_names.provides)
777 .next()
778 .and_then(|p| directive_string_arg_value(p, &FEDERATION_FIELDS_ARGUMENT_NAME));
779
780 let overrides_directive_option = field
781 .directives
782 .get_all(&directive_names.r#override)
783 .next()
784 .and_then(|p| {
785 let overrides_from =
786 directive_string_arg_value(p, &FEDERATION_FROM_ARGUMENT_NAME);
787 let overrides_label =
788 directive_string_arg_value(p, &FEDERATION_OVERRIDE_LABEL_ARGUMENT_NAME);
789 overrides_from.map(|from| (from, overrides_label))
790 });
791
792 let external_field = field
793 .directives
794 .get_all(&directive_names.external)
795 .next()
796 .is_some();
797
798 let join_field_directive = join_field_applied_directive(
799 subgraph_name,
800 requires_directive_option,
801 provides_directive_option,
802 external_field,
803 overrides_directive_option,
804 Some(&field.ty),
805 );
806
807 supergraph_field
808 .make_mut()
809 .directives
810 .push(Node::new(join_field_directive));
811
812 }
815 };
816 }
818
819 fn merge_union_type(
820 &mut self,
821 types: &mut IndexMap<NamedType, ExtendedType>,
822 directive_names: &DirectiveNames,
823 subgraph_name: &EnumValue,
824 union_name: NamedType,
825 union: &Node<UnionType>,
826 ) {
827 let existing_type = types
828 .entry(union_name.clone())
829 .or_insert(copy_union_type(union_name, union.description.clone()));
830
831 if let ExtendedType::Union(u) = existing_type {
832 let join_type_directives =
833 join_type_applied_directive(subgraph_name.clone(), iter::empty(), false);
834 u.make_mut().directives.extend(join_type_directives);
835 self.add_inaccessible(
836 directive_names,
837 &mut u.make_mut().directives,
838 &union.directives,
839 );
840
841 for union_member in union.members.iter() {
842 u.make_mut().members.insert(union_member.clone());
844 u.make_mut().directives.push(Component::new(Directive {
845 name: name!("join__unionMember"),
846 arguments: vec![
847 Node::new(Argument {
848 name: name!("graph"),
849 value: Node::new(Value::Enum(subgraph_name.to_name())),
850 }),
851 Node::new(Argument {
852 name: name!("member"),
853 value: union_member.as_str().into(),
854 }),
855 ],
856 }));
857 }
858 }
859 }
860
861 fn merge_scalar_type(
862 &mut self,
863 types: &mut IndexMap<Name, ExtendedType>,
864 directive_names: &DirectiveNames,
865 subgraph_name: EnumValue,
866 scalar_name: NamedType,
867 ty: &Node<ScalarType>,
868 ) {
869 let existing_type = types
870 .entry(scalar_name.clone())
871 .or_insert(copy_scalar_type(scalar_name, ty));
872
873 if let ExtendedType::Scalar(s) = existing_type {
874 let join_type_directives =
875 join_type_applied_directive(subgraph_name, iter::empty(), false);
876 s.make_mut().directives.extend(join_type_directives);
877 self.add_inaccessible(
878 directive_names,
879 &mut s.make_mut().directives,
880 &ty.directives,
881 );
882 } else {
883 }
885 }
886
887 fn add_inaccessible<I>(
889 &mut self,
890 directive_names: &DirectiveNames,
891 new_directives: &mut Vec<I>,
892 original_directives: &[I],
893 ) where
894 I: AsRef<Directive> + From<Directive> + Clone,
895 {
896 if original_directives
897 .iter()
898 .any(|d| d.as_ref().name == directive_names.inaccessible)
899 && !new_directives
900 .iter()
901 .any(|d| d.as_ref().name == INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC)
902 {
903 self.needs_inaccessible = true;
904
905 new_directives.push(
906 Directive {
907 name: INACCESSIBLE_DIRECTIVE_NAME_IN_SPEC,
908 arguments: vec![],
909 }
910 .into(),
911 );
912 }
913 }
914}
915
916struct DirectiveNames {
917 key: Name,
918 requires: Name,
919 provides: Name,
920 external: Name,
921 interface_object: Name,
922 r#override: Name,
923 inaccessible: Name,
924}
925
926impl DirectiveNames {
927 fn for_metadata(metadata: &Option<&LinksMetadata>) -> Self {
928 let federation_identity =
929 metadata.and_then(|m| m.for_identity(&Identity::federation_identity()));
930 let federation_identity = federation_identity.as_ref();
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;