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}