#![cfg_attr(
not(test),
deny(
clippy::exit,
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::unimplemented,
clippy::todo
)
)]
#![deny(nonstandard_style)]
#![deny(clippy::redundant_clone)]
#![deny(clippy::manual_while_let_some)]
#![deny(clippy::needless_borrow)]
#![deny(clippy::manual_ok_or)]
#![deny(clippy::needless_collect)]
#![deny(clippy::or_fun_call)]
use std::hash::Hash;
use std::hash::Hasher;
use apollo_compiler::Name;
pub mod expand;
pub mod header;
mod id;
mod json_selection;
mod models;
mod schema_type_ref;
pub use models::ProblemLocation;
pub mod runtime;
pub(crate) mod spec;
mod string_template;
pub mod validation;
pub(crate) mod variable;
use apollo_compiler::name;
use id::ConnectorPosition;
use id::ObjectTypeDefinitionDirectivePosition;
pub use json_selection::ApplyToError;
pub use json_selection::JSONSelection;
pub use json_selection::Key;
pub use json_selection::PathSelection;
pub(crate) use json_selection::SelectionTrie;
pub use json_selection::SubSelection;
pub use models::CustomConfiguration;
pub use models::Header;
use serde::Serialize;
pub use spec::ConnectHTTPArguments;
pub use spec::ConnectSpec;
pub use spec::SourceHTTPArguments;
pub use string_template::Error as StringTemplateError;
pub use string_template::StringTemplate;
pub(crate) use validation::field_set_is_subset;
pub use variable::Namespace;
pub use self::models::Connector;
pub use self::models::ConnectorErrorsSettings;
pub use self::models::EntityResolver;
pub use self::models::HTTPMethod;
pub use self::models::HeaderSource;
pub use self::models::HttpJsonTransport;
pub use self::models::Label;
pub use self::models::MakeUriError;
pub use self::models::OriginatingDirective;
pub use self::models::SourceName;
pub use self::spec::connect::ConnectBatchArguments;
use crate::schema::position::ObjectFieldDefinitionPosition;
use crate::schema::position::ObjectOrInterfaceFieldDefinitionPosition;
use crate::schema::position::ObjectOrInterfaceFieldDirectivePosition;
#[derive(Debug, Clone)]
pub struct ConnectId {
pub subgraph_name: String,
pub source_name: Option<SourceName>,
pub named: Option<Name>,
pub(crate) directive: ConnectorPosition,
}
impl ConnectId {
pub(crate) fn synthetic_name(&self) -> String {
format!("{}_{}", self.subgraph_name, self.directive.synthetic_name())
}
pub fn name(&self) -> String {
self.named
.as_ref()
.map_or_else(|| self.directive.coordinate(), |name| name.to_string())
}
pub fn subgraph_source(&self) -> String {
let source = self
.source_name
.as_ref()
.map(SourceName::as_str)
.unwrap_or_default();
format!("{}.{}", self.subgraph_name, source)
}
pub fn coordinate(&self) -> String {
format!("{}:{}", self.subgraph_name, self.directive.coordinate())
}
pub fn new(
subgraph_name: String,
source_name: Option<SourceName>,
type_name: Name,
field_name: Name,
named: Option<Name>,
index: usize,
) -> Self {
Self {
subgraph_name,
source_name,
named,
directive: ConnectorPosition::Field(ObjectOrInterfaceFieldDirectivePosition {
field: ObjectOrInterfaceFieldDefinitionPosition::Object(
ObjectFieldDefinitionPosition {
type_name,
field_name,
},
),
directive_name: name!(connect),
directive_index: index,
}),
}
}
pub fn new_on_object(
subgraph_name: String,
source_name: Option<SourceName>,
type_name: Name,
named: Option<Name>,
index: usize,
) -> Self {
Self {
subgraph_name,
source_name,
named,
directive: ConnectorPosition::Type(ObjectTypeDefinitionDirectivePosition {
type_name,
directive_name: name!(connect),
directive_index: index,
}),
}
}
}
impl PartialEq<&str> for ConnectId {
fn eq(&self, other: &&str) -> bool {
let coordinate = self.directive.coordinate();
let coordinate_non_indexed = coordinate.strip_suffix("[0]").unwrap_or(&coordinate);
&coordinate == other
|| &coordinate_non_indexed == other
|| self
.named
.as_ref()
.is_some_and(|name| &name.as_str() == other)
}
}
impl PartialEq<String> for ConnectId {
fn eq(&self, other: &String) -> bool {
self == &other.as_str()
}
}
impl PartialEq for ConnectId {
fn eq(&self, other: &Self) -> bool {
self.subgraph_name == other.subgraph_name && self.directive == other.directive
}
}
impl Eq for ConnectId {}
impl Hash for ConnectId {
fn hash<H: Hasher>(&self, state: &mut H) {
self.subgraph_name.hash(state);
self.directive.hash(state);
}
}
impl Serialize for ConnectId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_eq_str_with_index_0() {
let id = ConnectId::new(
"subgraph".to_string(),
None,
name!("type"),
name!("field"),
Some(name!("my_id")),
0,
);
assert_eq!(id, "type.field[0]");
assert_eq!(id, "type.field[0]".to_string());
assert_eq!(id, "type.field");
assert_eq!(id, "type.field".to_string());
assert_eq!(id, "my_id");
assert_eq!(id, "my_id".to_string());
}
#[test]
fn id_eq_str_with_index_non_zero() {
let id = ConnectId::new(
"subgraph".to_string(),
None,
name!("type"),
name!("field"),
Some(name!("my_id")),
10,
);
assert_eq!(id, "type.field[10]");
assert_eq!(id, "type.field[10]".to_string());
assert!(id != "type.field");
assert_eq!(id, "my_id");
}
}