use super::*;
#[derive(Default)]
pub(crate) struct LinkedSchemas {
pub(super) schemas: Vec<LinkedSchemaRecord>,
namespaces: HashMap<(SubgraphId, StringId), LinkedSchemaId>,
pub(super) definitions: Vec<LinkedDefinitionRecord>,
imported_definitions_by_name: HashMap<(SubgraphId, StringId), LinkedDefinitionId>,
}
pub(crate) struct LinkedSchemaRecord {
pub(crate) subgraph_id: SubgraphId,
pub(crate) linked_schema_type: LinkedSchemaType,
pub(crate) url: StringId,
pub(crate) name_from_url: Option<StringId>,
pub(crate) r#as: Option<StringId>,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum LinkedSchemaType {
FederationSpec(FederationSpec),
Other,
}
impl LinkedSchemaRecord {
pub(crate) fn namespace(&self) -> Option<StringId> {
self.r#as.or(self.name_from_url)
}
}
pub(crate) struct LinkedDefinitionRecord {
pub(crate) linked_schema_id: LinkedSchemaId,
pub(crate) original_name: StringId,
pub(crate) imported_as: Option<StringId>,
}
impl LinkedDefinitionRecord {
pub(crate) fn final_name(&self) -> StringId {
self.imported_as.unwrap_or(self.original_name)
}
}
pub(crate) type LinkedSchema<'a> = View<'a, LinkedSchemaId, LinkedSchemaRecord>;
impl Subgraphs {
pub(crate) fn iter_linked_schemas(&self) -> impl ExactSizeIterator<Item = LinkedSchema<'_>> {
self.linked_schemas
.schemas
.iter()
.enumerate()
.map(|(idx, record)| View { id: idx.into(), record })
}
pub(crate) fn get_linked_schema(&self, subgraph_id: SubgraphId, namespace: StringId) -> Option<LinkedSchemaId> {
self.linked_schemas.namespaces.get(&(subgraph_id, namespace)).copied()
}
pub(crate) fn get_imported_definition(
&self,
subgraph_id: SubgraphId,
name: StringId,
) -> Option<LinkedDefinitionId> {
self.linked_schemas
.imported_definitions_by_name
.get(&(subgraph_id, name))
.copied()
}
pub(crate) fn push_linked_definition(
&mut self,
subgraph_id: SubgraphId,
linked_definition: LinkedDefinitionRecord,
) -> LinkedDefinitionId {
let id = LinkedDefinitionId::from(self.linked_schemas.definitions.len());
self.linked_schemas
.imported_definitions_by_name
.insert((subgraph_id, linked_definition.final_name()), id);
self.linked_schemas.definitions.push(linked_definition);
id
}
pub(crate) fn push_linked_schema(&mut self, linked_schema: LinkedSchemaRecord) -> LinkedSchemaId {
let id = LinkedSchemaId::from(self.linked_schemas.schemas.len());
if let Some(namespace) = linked_schema.namespace() {
let previous = self
.linked_schemas
.namespaces
.insert((linked_schema.subgraph_id, namespace), id);
if previous.is_some() {
self.ingestion_diagnostics.push_warning(format!(
"Linked schema namespace collision for subgraph {}: the \"{}\" namespace is defined at least twice",
self[self[linked_schema.subgraph_id].name], self[namespace],
));
}
}
let url = self.strings.resolve(linked_schema.url);
if let Some(federation_spec) = FederationSpec::from_url(url) {
let existing = &mut self[linked_schema.subgraph_id].federation_spec;
*existing = (*existing).max(federation_spec);
}
self.linked_schemas.schemas.push(linked_schema);
id
}
}