cynic/operation/
builder.rsuse std::{borrow::Cow, collections::HashSet, marker::PhantomData};
use crate::{
queries::{build_executable_document, OperationType},
schema::{MutationRoot, QueryRoot, SubscriptionRoot},
QueryFragment, QueryVariableLiterals, QueryVariables,
};
use super::Operation;
pub struct OperationBuilder<QueryFragment, Variables = ()> {
variables: Option<Variables>,
operation_kind: OperationType,
operation_name: Option<Cow<'static, str>>,
features: HashSet<String>,
phantom: PhantomData<fn() -> QueryFragment>,
}
impl<Fragment, Variables> OperationBuilder<Fragment, Variables>
where
Fragment: QueryFragment,
Variables: QueryVariables,
{
fn new(operation_kind: OperationType) -> Self {
OperationBuilder {
variables: None,
operation_kind,
operation_name: Fragment::name(),
features: HashSet::new(),
phantom: PhantomData,
}
}
pub fn query() -> Self
where
Fragment::SchemaType: QueryRoot,
{
Self::new(OperationType::Query)
}
pub fn mutation() -> Self
where
Fragment::SchemaType: MutationRoot,
{
Self::new(OperationType::Mutation)
}
pub fn subscription() -> Self
where
Fragment::SchemaType: SubscriptionRoot,
{
Self::new(OperationType::Subscription)
}
pub fn with_variables(self, variables: Variables) -> Self {
Self {
variables: Some(variables),
..self
}
}
pub fn set_variables(&mut self, variables: Variables) {
self.variables = Some(variables);
}
pub fn with_feature_enabled(mut self, feature: &str) -> Self {
self.enable_feature(feature);
self
}
pub fn enable_feature(&mut self, feature: &str) {
self.features.insert(feature.to_string());
}
pub fn with_operation_name(self, name: &str) -> Self {
OperationBuilder {
operation_name: Some(Cow::Owned(name.to_string())),
..self
}
}
pub fn set_operation_name(&mut self, name: &str) {
self.operation_name = Some(Cow::Owned(name.to_string()));
}
pub fn build(self) -> Result<super::Operation<Fragment, Variables>, OperationBuildError> {
Ok(Operation {
query: build_executable_document::<Fragment, Variables>(
self.operation_kind,
self.operation_name.as_deref(),
self.features.clone(),
None,
),
variables: self.variables.ok_or(OperationBuildError::VariablesNotSet)?,
operation_name: self.operation_name,
phantom: PhantomData,
})
}
pub fn build_with_variables_inlined(
self,
) -> Result<super::Operation<Fragment, ()>, OperationBuildError>
where
Variables: QueryVariableLiterals,
{
let variables = self.variables.ok_or(OperationBuildError::VariablesNotSet)?;
Ok(Operation {
query: build_executable_document::<Fragment, Variables>(
self.operation_kind,
self.operation_name.as_deref(),
self.features.clone(),
Some(&variables),
),
variables: (),
operation_name: self.operation_name,
phantom: PhantomData,
})
}
}
#[derive(thiserror::Error, Debug)]
pub enum OperationBuildError {
#[error("You need to call with_variables or set_variables before calling build")]
VariablesNotSet,
#[error("Couldn't format the query into a string: {0}")]
CouldntBuildQueryString(#[from] std::fmt::Error),
}