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