libgraphql_core/operation/
mutation_builder.rs

1use crate::ast;
2use crate::DirectiveAnnotation;
3use crate::schema::Schema;
4use crate::operation::FragmentRegistry;
5use crate::operation::Operation;
6use crate::operation::OperationBuilder;
7use crate::operation::OperationBuildError;
8use crate::operation::OperationBuilderTrait;
9use crate::operation::Mutation;
10use crate::operation::Selection;
11use crate::operation::Variable;
12use inherent::inherent;
13use std::path::Path;
14use thiserror::Error;
15
16type Result<T> = std::result::Result<T, MutationBuildError>;
17
18#[derive(Clone, Debug, PartialEq)]
19pub struct MutationBuilder<'schema: 'fragreg, 'fragreg>(
20    OperationBuilder<'schema, 'fragreg>,
21);
22
23#[inherent]
24impl<'schema: 'fragreg, 'fragreg> OperationBuilderTrait<
25    'schema,
26    'fragreg,
27    ast::operation::Mutation,
28    MutationBuildError,
29    Mutation<'schema, 'fragreg>,
30> for MutationBuilder<'schema, 'fragreg> {
31    /// Add a [`DirectiveAnnotation`] after any previously added
32    /// `DirectiveAnnotation`s.
33    pub fn add_directive(self, annot: DirectiveAnnotation) -> Result<Self> {
34        Ok(Self(self.0.add_directive(annot)?))
35    }
36
37    /// Add a [`Selection`] after any previously added `Selection`s.
38    pub fn add_selection(self, selection: Selection<'schema>) -> Result<Self> {
39        Ok(Self(self.0.add_selection(selection)?))
40    }
41
42    /// Add a [`Variable`] after any previously added `Variable`s.
43    pub fn add_variable(self, variable: Variable) -> Result<Self> {
44        Ok(Self(self.0.add_variable(variable)?))
45    }
46
47    /// Consume this [`MutationBuilder`] to produce a [`Mutation`].
48    pub fn build(self) -> Result<Mutation<'schema, 'fragreg>> {
49        let operation_kind = self.0.operation_kind.to_owned();
50        match self.0.build()? {
51            Operation::Mutation(query) => Ok(*query),
52            _ => panic!("Unexpected OperationKind: `{operation_kind:#?}`"),
53        }
54    }
55
56    /// Produce a [`Mutation`] from a
57    /// [`ast::operation::Mutation`](ast::operation::Mutation).
58    pub fn build_from_ast(
59        schema: &'schema Schema,
60        fragment_registry: &'fragreg FragmentRegistry<'schema>,
61        ast: &ast::operation::Mutation,
62        file_path: Option<&Path>,
63    ) -> Result<Mutation<'schema, 'fragreg>> {
64        Self::build_from_ast(schema, fragment_registry, ast, file_path)
65    }
66
67    /// Produce a [`Mutation`] from a file on disk that whose contents contain
68    /// an
69    /// [executable document](https://spec.graphql.org/October2021/#ExecutableDocument)
70    /// with only a single query defined in it.
71    ///
72    /// If multiple operations are defined in the document, an error will be
73    /// returned. For cases where multiple operations may be defined in a single
74    /// document, use
75    /// [`ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
76    ///
77    /// If the document contents include any fragment definitions, an error will
78    /// be returned. For cases where operations and fragments may be defined
79    /// together in a single document, use
80    /// ['ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
81    pub fn build_from_file(
82        schema: &'schema Schema,
83        fragment_registry: &'fragreg FragmentRegistry<'schema>,
84        file_path: impl AsRef<Path>,
85    ) -> Result<Mutation<'schema, 'fragreg>> {
86        Self::build_from_file(schema, fragment_registry, file_path)
87    }
88
89    /// Produce a [`Mutation`] from a string whose contents contain a
90    /// [document](https://spec.graphql.org/October2021/#sec-Document) with only
91    /// a single query defined in it.
92    ///
93    /// If multiple operations are defined in the document, an error will be
94    /// returned. For cases where multiple operations may be defined in a single
95    /// document, use
96    /// [`ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
97    ///
98    /// If the document contents include any fragment definitions, an error will
99    /// be returned. For cases where operations and fragments may be defined
100    /// together in a single document, use
101    /// ['ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
102    pub fn build_from_str(
103        schema: &'schema Schema,
104        fragment_registry: &'fragreg FragmentRegistry<'schema>,
105        file_path: Option<&Path>,
106        content: impl AsRef<str>,
107    ) -> Result<Mutation<'schema, 'fragreg>> {
108        Self::build_from_str(schema, fragment_registry, file_path, content)
109    }
110
111    /// Produce a [`MutationBuilder`] from a [`Mutation`](ast::operation::Mutation).
112    pub fn from_ast(
113        schema: &'schema Schema,
114        fragment_registry: &'fragreg FragmentRegistry<'schema>,
115        ast: &ast::operation::Mutation,
116        file_path: Option<&Path>,
117    ) -> Result<Self> {
118        Ok(Self(OperationBuilder::from_ast(
119            schema,
120            fragment_registry,
121            &ast::operation::OperationDefinition::Mutation(ast.to_owned()),
122            file_path
123        )?))
124    }
125
126    /// Produce a [`MutationBuilder`] from a file on disk that whose contents
127    /// contain an
128    /// [executable document](https://spec.graphql.org/October2021/#ExecutableDocument)
129    /// with only a single query defined in it.
130    ///
131    /// If multiple operations are defined in the document, an error will be
132    /// returned. For cases where multiple operations may be defined in a single
133    /// document, use
134    /// [`ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
135    ///
136    /// If the document contents include any fragment definitions, an error will
137    /// be returned. For cases where operations and fragments may be defined
138    /// together in a single document, use
139    /// ['ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
140    pub fn from_file(
141        schema: &'schema Schema,
142        fragment_registry: &'fragreg FragmentRegistry<'schema>,
143        file_path: impl AsRef<Path>,
144    ) -> Result<Self> {
145        Ok(Self(OperationBuilder::from_file(schema, fragment_registry, file_path)?))
146    }
147
148    /// Produce a [`MutationBuilder`] from a string whose contents contain a
149    /// [document](https://spec.graphql.org/October2021/#sec-Document) with only
150    /// a single query defined in it.
151    ///
152    /// If multiple operations are defined in the document, an error will be
153    /// returned. For cases where multiple operations may be defined in a single
154    /// document, use
155    /// [`ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
156    ///
157    /// If the document contents include any fragment definitions, an error will
158    /// be returned. For cases where operations and fragments may be defined
159    /// together in a single document, use
160    /// ['ExecutableDocumentBuilder`](crate::operation::ExecutableDocumentBuilder).
161    pub fn from_str(
162        schema: &'schema Schema,
163        fragment_registry: &'fragreg FragmentRegistry<'schema>,
164        content: impl AsRef<str>,
165        file_path: Option<&Path>,
166    ) -> Result<Self> {
167        Ok(Self(OperationBuilder::from_str(schema, fragment_registry, content, file_path)?))
168    }
169
170    pub fn new(
171        schema: &'schema Schema,
172        fragment_registry: &'fragreg FragmentRegistry<'schema>,
173    ) -> Self {
174        Self(OperationBuilder::new(schema, fragment_registry))
175    }
176
177    /// Set the list of [`DirectiveAnnotation`]s.
178    ///
179    /// NOTE: If any previous directives were added (either using this function
180    /// or [`MutationBuilder::add_directive()`]), they will be fully replaced by
181    /// the [`DirectiveAnnotation`]s passed here.
182    pub fn set_directives(
183        self,
184        directives: &[DirectiveAnnotation],
185    ) -> Result<Self> {
186        Ok(Self(self.0.set_directives(directives)?))
187    }
188
189    /// Set the name of the [`Mutation`].
190    pub fn set_name(self, name: Option<String>) -> Result<Self> {
191        Ok(Self(self.0.set_name(name)?))
192    }
193
194    /// Set the list of [`Variable`]s.
195    ///
196    /// NOTE: If any previous variables were added (either using this function
197    /// or [`MutationBuilder::add_variable()`]), they will be fully replaced by the
198    /// collection of variables passed here.
199    pub fn set_variables(self, variables: Vec<Variable>) -> Result<Self> {
200        Ok(Self(self.0.set_variables(variables)?))
201    }
202}
203
204#[derive(Clone, Debug, Error)]
205pub enum MutationBuildError {
206    #[error("Error building Mutation operation: $0")]
207    OperationBuildErrors(Vec<OperationBuildError>),
208}
209impl std::convert::From<Vec<OperationBuildError>> for MutationBuildError {
210    fn from(value: Vec<OperationBuildError>) -> Self {
211        Self::OperationBuildErrors(value)
212    }
213}