Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

feat: Intra-subgraph logic of federated query graph creation #84

Merged
merged 2 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ indexmap = "2.0.2"
thiserror = "1.0"
url = "2"
lazy_static = "1.4.0"
petgraph = "0.6.4"
strum = "0.25.0"
strum_macros = "0.25.2"

Expand Down
1 change: 0 additions & 1 deletion src/link/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ pub(crate) fn directive_optional_fieldset_argument(
}
}

#[allow(dead_code)]
pub(crate) fn directive_required_fieldset_argument(
application: &Node<Directive>,
name: &Name,
Expand Down
107 changes: 106 additions & 1 deletion src/link/federation_spec_definition.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use crate::error::{FederationError, SingleFederationError};
use crate::link::argument::{
directive_optional_boolean_argument, directive_required_fieldset_argument,
};
use crate::link::spec::{Identity, Url, Version};
use crate::link::spec_definition::{SpecDefinition, SpecDefinitions};
use crate::schema::FederationSchema;
use apollo_compiler::ast::Argument;
use apollo_compiler::schema::{Directive, DirectiveDefinition, Name, Value};
use apollo_compiler::schema::{
Directive, DirectiveDefinition, ExtendedType, Name, UnionType, Value,
};
use apollo_compiler::{name, Node, NodeStr};
use lazy_static::lazy_static;

pub(crate) const FEDERATION_ENTITY_TYPE_NAME_IN_SPEC: Name = name!("_Entity");
pub(crate) const FEDERATION_KEY_DIRECTIVE_NAME_IN_SPEC: Name = name!("key");
pub(crate) const FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC: Name = name!("interfaceObject");
pub(crate) const FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC: Name = name!("external");
Expand All @@ -20,6 +26,11 @@ pub(crate) const FEDERATION_RESOLVABLE_ARGUMENT_NAME: Name = name!("resolvable")
pub(crate) const FEDERATION_REASON_ARGUMENT_NAME: Name = name!("reason");
pub(crate) const FEDERATION_FROM_ARGUMENT_NAME: Name = name!("from");

pub(crate) struct KeyDirectiveArguments {
pub(crate) fields: NodeStr,
pub(crate) resolvable: bool,
}

pub(crate) struct FederationSpecDefinition {
url: Url,
}
Expand All @@ -34,6 +45,31 @@ impl FederationSpecDefinition {
}
}

pub(crate) fn entity_type_definition<'schema>(
&self,
schema: &'schema FederationSchema,
) -> Result<Option<&'schema Node<UnionType>>, FederationError> {
// Note that the _Entity type is special in that:
// 1. Spec renaming doesn't take place for it (there's no prefixing or importing needed),
// in order to maintain backwards compatibility with Fed 1.
// 2. Its presence is optional; if absent, it means the subgraph has no resolvable keys.
match schema
.schema()
.types
.get(&FEDERATION_ENTITY_TYPE_NAME_IN_SPEC)
{
Some(ExtendedType::Union(type_)) => Ok(Some(type_)),
None => Ok(None),
_ => Err(SingleFederationError::Internal {
message: format!(
"Unexpectedly found non-union for federation spec's \"{}\" type definition",
FEDERATION_ENTITY_TYPE_NAME_IN_SPEC
),
}
.into()),
}
}

pub(crate) fn key_directive_definition<'schema>(
&self,
schema: &'schema FederationSchema,
Expand Down Expand Up @@ -76,6 +112,43 @@ impl FederationSpecDefinition {
})
}

pub(crate) fn key_directive_arguments(
&self,
application: &Node<Directive>,
) -> Result<KeyDirectiveArguments, FederationError> {
Ok(KeyDirectiveArguments {
fields: directive_required_fieldset_argument(
application,
&FEDERATION_FIELDS_ARGUMENT_NAME,
)?,
resolvable: directive_optional_boolean_argument(
application,
&FEDERATION_RESOLVABLE_ARGUMENT_NAME,
)?
.unwrap_or(false),
})
}

pub(crate) fn interface_object_directive_definition<'schema>(
&self,
schema: &'schema FederationSchema,
) -> Result<Option<&'schema Node<DirectiveDefinition>>, FederationError> {
if *self.version() < (Version { major: 2, minor: 3 }) {
return Ok(None);
}
self.directive_definition(schema, &FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC)?
.ok_or_else(|| {
SingleFederationError::Internal {
message: format!(
"Unexpectedly could not find federation spec's \"@{}\" directive definition",
FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC
),
}
.into()
})
.map(Some)
}

pub(crate) fn interface_object_directive(
&self,
schema: &FederationSchema,
Expand All @@ -97,6 +170,22 @@ impl FederationSpecDefinition {
})
}

pub(crate) fn external_directive_definition<'schema>(
&self,
schema: &'schema FederationSchema,
) -> Result<&'schema Node<DirectiveDefinition>, FederationError> {
self.directive_definition(schema, &FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC)?
.ok_or_else(|| {
SingleFederationError::Internal {
message: format!(
"Unexpectedly could not find federation spec's \"@{}\" directive definition",
FEDERATION_EXTERNAL_DIRECTIVE_NAME_IN_SPEC
),
}
.into()
})
}

pub(crate) fn external_directive(
&self,
schema: &FederationSchema,
Expand All @@ -120,6 +209,22 @@ impl FederationSpecDefinition {
})
}

pub(crate) fn requires_directive_definition<'schema>(
&self,
schema: &'schema FederationSchema,
) -> Result<&'schema Node<DirectiveDefinition>, FederationError> {
self.directive_definition(schema, &FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC)?
.ok_or_else(|| {
SingleFederationError::Internal {
message: format!(
"Unexpectedly could not find federation spec's \"@{}\" directive definition",
FEDERATION_REQUIRES_DIRECTIVE_NAME_IN_SPEC
),
}
.into()
})
}

pub(crate) fn requires_directive(
&self,
schema: &FederationSchema,
Expand Down
Loading