libgraphql_core/operation/
query_builder.rs

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