graphql_composition/
lib.rs1#![deny(unsafe_code, missing_docs, rust_2018_idioms)]
2#![doc = include_str!("../README.md")]
3
4pub mod diagnostics;
5
6mod compose;
7mod composition_ir;
8mod emit_federated_graph;
9mod federated_graph;
10mod grafbase_extensions;
11mod ingest_subgraph;
12mod result;
13mod subgraphs;
14mod validate;
15
16pub use self::{
17 diagnostics::Diagnostics,
18 federated_graph::{DomainError, FederatedGraph, render_api_sdl, render_federated_sdl},
19 grafbase_extensions::LoadedExtension,
20 result::CompositionResult,
21 subgraphs::{IngestError, Subgraphs},
22};
23
24use self::{
25 compose::{ComposeContext, compose_subgraphs},
26 emit_federated_graph::emit_federated_graph,
27 ingest_subgraph::ast_value_to_subgraph_value,
28};
29
30pub fn compose(subgraphs: &mut Subgraphs) -> CompositionResult {
32 subgraphs.sort_pre_composition();
33
34 let mut diagnostics = Diagnostics::default();
35
36 if subgraphs.iter_subgraphs().len() == 0 {
37 let error = "No subgraphs to compose. You must pass at least one subgraph.";
38 diagnostics.push_fatal(error.to_owned());
39
40 return CompositionResult {
41 federated_graph: None,
42 diagnostics,
43 };
44 }
45
46 let mut context = ComposeContext::new(subgraphs, &mut diagnostics);
47
48 validate::validate_pre_merge(&mut context);
49
50 if context.diagnostics.any_fatal() {
51 return CompositionResult {
52 federated_graph: None,
53 diagnostics,
54 };
55 }
56
57 compose_subgraphs(&mut context);
58
59 if context.diagnostics.any_fatal() {
60 CompositionResult {
61 federated_graph: None,
62 diagnostics,
63 }
64 } else {
65 let federated_graph = emit_federated_graph(context.into_ir(), subgraphs);
66
67 CompositionResult {
68 federated_graph: Some(federated_graph),
69 diagnostics,
70 }
71 }
72}
73
74trait VecExt<T> {
75 fn push_return_idx(&mut self, elem: T) -> usize;
76}
77
78impl<T> VecExt<T> for Vec<T> {
79 fn push_return_idx(&mut self, elem: T) -> usize {
80 let idx = self.len();
81 self.push(elem);
82 idx
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn grafbase_schema_can_be_composed() {
92 use std::{fs, path::Path};
93 let schema_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../cli/src/api/graphql/api.graphql");
94 let schema = fs::read_to_string(schema_path).unwrap();
95
96 let mut subgraphs = Subgraphs::default();
97 subgraphs
98 .ingest_str(&schema, "grafbase-api", Some("https://api.grafbase.com"))
99 .unwrap();
100 let result = compose(&mut subgraphs);
101 assert!(result.diagnostics().is_empty());
102 }
103}