use crate::subgraphs::{FederationSpec, LinkedSchemaType, StringId};
use super::*;
pub(in crate::ingest_subgraph) fn match_directive_name(
ctx: &mut Context<'_>,
directive_name: &str,
) -> (StringId, DirectiveNameMatch) {
let (namespace, directive_name) = directive_name
.split_once("__")
.map(|(namespace, name)| {
let namespace = ctx.subgraphs.strings.intern(namespace);
(Some(namespace), name)
})
.unwrap_or((None, directive_name));
let linked_schema_id =
namespace.and_then(|namespace_str| ctx.subgraphs.get_linked_schema(ctx.subgraph_id, namespace_str));
let directive_name_id = ctx.subgraphs.strings.intern(directive_name);
let matched = match match_directive_name_inner(ctx, directive_name_id, linked_schema_id, directive_name) {
DirectiveNameMatch::NoMatch => {
if let Some(definition) = ctx
.subgraph_id
.iter_directive_definitions(ctx.subgraphs)
.find(|definition| directive_name_id == definition.name)
{
DirectiveNameMatch::LocallyDefined(definition.id)
} else {
DirectiveNameMatch::NoMatch
}
}
other => other,
};
(directive_name_id, matched)
}
fn match_directive_name_inner(
ctx: &mut Context<'_>,
directive_name_id: StringId,
linked_schema_id: Option<subgraphs::LinkedSchemaId>,
directive_name: &str,
) -> DirectiveNameMatch {
if let Some(linked_schema_id) = linked_schema_id {
return match ctx.subgraphs.at(linked_schema_id).linked_schema_type {
LinkedSchemaType::FederationSpec(FederationSpec::ApolloV2) => {
match_federation_directive_by_original_name(directive_name)
}
LinkedSchemaType::FederationSpec(FederationSpec::CompositeSchemas) => {
match_composite_schemas_directive_by_original_name(directive_name)
}
LinkedSchemaType::FederationSpec(FederationSpec::ApolloV1) => DirectiveNameMatch::Qualified {
linked_schema_id,
directive_unqualified_name: directive_name_id,
},
LinkedSchemaType::Other => DirectiveNameMatch::Qualified {
linked_schema_id,
directive_unqualified_name: directive_name_id,
},
};
}
if let Some(imported_definition_id) = ctx
.subgraphs
.get_imported_definition(ctx.subgraph_id, directive_name_id)
{
let imported_definition = ctx.subgraphs.at(imported_definition_id);
let linked_schema = ctx.subgraphs.at(imported_definition.linked_schema_id);
match linked_schema.linked_schema_type {
LinkedSchemaType::FederationSpec(FederationSpec::ApolloV2 | FederationSpec::ApolloV1) => {
let original_name = &ctx.subgraphs.strings.resolve(imported_definition.original_name);
return match_federation_directive_by_original_name(original_name);
}
LinkedSchemaType::FederationSpec(FederationSpec::CompositeSchemas) => {
let original_name = &ctx.subgraphs.strings.resolve(imported_definition.original_name);
return match_composite_schemas_directive_by_original_name(original_name);
}
LinkedSchemaType::Other => {
return DirectiveNameMatch::Imported {
linked_definition_id: imported_definition_id,
};
}
};
}
match directive_name {
LINK => return DirectiveNameMatch::Link,
"deprecated" => return DirectiveNameMatch::Deprecated,
"specifiedBy" => return DirectiveNameMatch::SpecifiedBy,
"oneOf" => return DirectiveNameMatch::OneOf,
COST => return DirectiveNameMatch::Cost,
LIST_SIZE => return DirectiveNameMatch::ListSize,
_ => (),
}
let federation_schema_has_been_linked = ctx.subgraphs.at(ctx.subgraph_id).federation_spec.is_apollo_v2();
let is_virtual_subgraph = ctx.subgraphs.at(ctx.subgraph_id).is_virtual();
if !federation_schema_has_been_linked && !is_virtual_subgraph {
return match_federation_directive_by_original_name(directive_name);
}
DirectiveNameMatch::NoMatch
}
fn match_composite_schemas_directive_by_original_name(original_name: &str) -> DirectiveNameMatch {
match original_name {
LOOKUP => DirectiveNameMatch::Lookup,
KEY => DirectiveNameMatch::KeyFromCompositeSchemas,
REQUIRE => DirectiveNameMatch::Require,
SHAREABLE => DirectiveNameMatch::Shareable,
IS => DirectiveNameMatch::Is,
DERIVE => DirectiveNameMatch::Derive,
EXTERNAL => DirectiveNameMatch::External,
OVERRIDE => DirectiveNameMatch::Override,
PROVIDES => DirectiveNameMatch::Provides,
INACCESSIBLE => DirectiveNameMatch::Inaccessible,
INTERNAL => DirectiveNameMatch::Internal,
_ => DirectiveNameMatch::NoMatch,
}
}
fn match_federation_directive_by_original_name(original_name: &str) -> DirectiveNameMatch {
match original_name {
AUTHENTICATED => DirectiveNameMatch::Authenticated,
COMPOSE_DIRECTIVE => DirectiveNameMatch::ComposeDirective,
EXTENDS => DirectiveNameMatch::Extends,
EXTERNAL => DirectiveNameMatch::External,
INACCESSIBLE => DirectiveNameMatch::Inaccessible,
INTERFACE_OBJECT => DirectiveNameMatch::InterfaceObject,
KEY => DirectiveNameMatch::Key,
OVERRIDE => DirectiveNameMatch::Override,
POLICY => DirectiveNameMatch::Policy,
PROVIDES => DirectiveNameMatch::Provides,
REQUIRES => DirectiveNameMatch::Requires,
REQUIRES_SCOPES => DirectiveNameMatch::RequiresScopes,
SHAREABLE => DirectiveNameMatch::Shareable,
TAG => DirectiveNameMatch::Tag,
_ => DirectiveNameMatch::NoMatch,
}
}
#[derive(Debug, Clone, Copy)]
pub(in crate::ingest_subgraph) enum DirectiveNameMatch {
NoMatch,
Qualified {
linked_schema_id: subgraphs::LinkedSchemaId,
directive_unqualified_name: StringId,
},
Imported {
linked_definition_id: subgraphs::LinkedDefinitionId,
},
LocallyDefined(#[expect(unused)] subgraphs::DirectiveDefinitionId),
Deprecated,
SpecifiedBy,
Lookup,
Derive,
Require,
Is,
KeyFromCompositeSchemas,
Internal,
Authenticated,
ComposeDirective,
Cost,
Extends,
External,
Inaccessible,
OneOf,
InterfaceObject,
Key,
Link,
ListSize,
Override,
Policy,
Provides,
Requires,
RequiresScopes,
Shareable,
Tag,
}