mod satisfiability;
use std::vec;
use tracing::instrument;
pub use crate::composition::satisfiability::validate_satisfiability;
use crate::error::CompositionError;
use crate::merger::merge::Merger;
pub use crate::schema::schema_upgrader::upgrade_subgraphs_if_necessary;
use crate::schema::validators::root_fields::validate_consistent_root_fields;
use crate::subgraph::typestate::Expanded;
use crate::subgraph::typestate::Initial;
use crate::subgraph::typestate::Subgraph;
use crate::subgraph::typestate::Validated;
pub use crate::supergraph::Merged;
pub use crate::supergraph::Satisfiable;
pub use crate::supergraph::Supergraph;
#[instrument(skip(subgraphs))]
pub fn compose(
subgraphs: Vec<Subgraph<Initial>>,
) -> Result<Supergraph<Satisfiable>, Vec<CompositionError>> {
tracing::debug!("Expanding subgraphs...");
let expanded_subgraphs = expand_subgraphs(subgraphs)?;
tracing::debug!("Upgrading subgraphs...");
let validated_subgraphs = upgrade_subgraphs_if_necessary(expanded_subgraphs)?;
tracing::debug!("Pre-merge validations...");
pre_merge_validations(&validated_subgraphs)?;
tracing::debug!("Merging subgraphs...");
let supergraph = merge_subgraphs(validated_subgraphs)?;
tracing::debug!("Post-merge validations...");
post_merge_validations(&supergraph)?;
tracing::debug!("Validating satisfiability...");
validate_satisfiability(supergraph)
}
#[instrument(skip(subgraphs))]
pub fn expand_subgraphs(
subgraphs: Vec<Subgraph<Initial>>,
) -> Result<Vec<Subgraph<Expanded>>, Vec<CompositionError>> {
let mut errors: Vec<CompositionError> = vec![];
let expanded: Vec<Subgraph<Expanded>> = subgraphs
.into_iter()
.map(|s| s.expand_links())
.filter_map(|r| r.map_err(|e| errors.extend(e.to_composition_errors())).ok())
.collect();
if errors.is_empty() {
Ok(expanded)
} else {
Err(errors)
}
}
#[instrument(skip(subgraphs))]
pub fn pre_merge_validations(
subgraphs: &[Subgraph<Validated>],
) -> Result<(), Vec<CompositionError>> {
validate_consistent_root_fields(subgraphs)?;
Ok(())
}
#[instrument(skip(subgraphs))]
pub fn merge_subgraphs(
subgraphs: Vec<Subgraph<Validated>>,
) -> Result<Supergraph<Merged>, Vec<CompositionError>> {
let merger = Merger::new(subgraphs, Default::default()).map_err(|e| {
vec![CompositionError::InternalError {
message: e.to_string(),
}]
})?;
let result = merger.merge().map_err(|e| {
vec![CompositionError::InternalError {
message: e.to_string(),
}]
})?;
tracing::trace!(
"Merge has {} errors and {} hints",
result.errors.len(),
result.hints.len()
);
if result.errors.is_empty() {
let Some(supergraph_schema) = result.supergraph else {
return Err(vec![CompositionError::InternalError {
message: "Merge completed with no supergraph schema".to_string(),
}]);
};
let supergraph = Supergraph::with_hints(supergraph_schema, result.hints);
Ok(supergraph)
} else {
Err(result.errors)
}
}
#[instrument(skip(_supergraph))]
pub fn post_merge_validations(
_supergraph: &Supergraph<Merged>,
) -> Result<(), Vec<CompositionError>> {
Ok(())
}