pub(crate) mod prune_inacessible;
pub(crate) mod strip_schema_internals;
use std::{
hash::{Hash as _, Hasher},
sync::Arc,
};
use graphql_tools::static_graphql::schema::{Definition, Document, TypeDefinition};
use prune_inacessible::PruneInaccessible;
use strip_schema_internals::StripSchemaInternals;
#[derive(Debug)]
pub struct ConsumerSchema {
pub document: Arc<Document>,
pub hash: u64,
}
impl From<Arc<Document>> for ConsumerSchema {
fn from(document: Arc<Document>) -> Self {
let hash = {
let mut hasher = xxhash_rust::xxh3::Xxh3::new();
document.hash(&mut hasher);
hasher.finish()
};
Self { document, hash }
}
}
impl ConsumerSchema {
pub fn new_from_supergraph(supergraph: &Document) -> Self {
let document: Arc<Document> = Self::create_consumer_schema(supergraph).into();
document.into()
}
fn create_consumer_schema(supergraph: &Document) -> Document {
let mut result = PruneInaccessible::prune(supergraph);
result = StripSchemaInternals::strip_schema_internals(&result);
let introspection_schema = include_str!("introspection_schema.graphql");
let mut parsed_introspection_schema =
graphql_tools::parser::schema::parse_schema(introspection_schema).unwrap();
let query_type_name = result
.query_type_name()
.map(|name| name.to_string())
.expect("Query type not found in schema");
parsed_introspection_schema
.definitions
.iter_mut()
.for_each(|def| {
match def {
Definition::TypeDefinition(TypeDefinition::Object(
type_def_in_introspection,
)) => {
if type_def_in_introspection.name == "Query" {
match result.definitions.iter_mut().find(|d| {
if let Definition::TypeDefinition(TypeDefinition::Object(
query_def,
)) = d
{
query_def.name == query_type_name
} else {
false
}
}) {
Some(Definition::TypeDefinition(TypeDefinition::Object(
query_def,
))) => {
query_def
.fields
.extend(type_def_in_introspection.fields.clone());
}
_ => {
result.definitions.push(def.clone());
}
}
} else {
result.definitions.push(def.clone());
}
}
_ => result.definitions.push(def.clone()),
}
});
result
}
}