diesel/query_builder/
mod.rs1#[macro_use]
8mod query_id;
9#[macro_use]
10mod clause_macro;
11
12pub(crate) mod ast_pass;
13pub mod bind_collector;
14mod collected_query;
15pub(crate) mod combination_clause;
16mod debug_query;
17mod delete_statement;
18mod distinct_clause;
19pub(crate) mod from_clause;
20pub(crate) mod functions;
21pub(crate) mod group_by_clause;
22mod having_clause;
23pub(crate) mod insert_statement;
24pub(crate) mod limit_clause;
25pub(crate) mod limit_offset_clause;
26pub(crate) mod locking_clause;
27pub(crate) mod nodes;
28pub(crate) mod offset_clause;
29pub(crate) mod order_clause;
30pub(crate) mod returning_clause;
31pub(crate) mod select_clause;
32pub(crate) mod select_statement;
33mod sql_query;
34pub(crate) mod update_statement;
35pub(crate) mod upsert;
36pub(crate) mod where_clause;
37
38#[doc(inline)]
39pub use self::ast_pass::AstPass;
40#[doc(inline)]
41pub use self::bind_collector::{BindCollector, MoveableBindCollector};
42#[doc(inline)]
43pub use self::collected_query::CollectedQuery;
44#[doc(inline)]
45pub use self::debug_query::DebugQuery;
46#[doc(inline)]
47pub use self::delete_statement::{BoxedDeleteStatement, DeleteStatement};
48#[doc(inline)]
49pub use self::insert_statement::{
50 IncompleteInsertOrIgnoreStatement, IncompleteInsertStatement, IncompleteReplaceStatement,
51 InsertOrIgnoreStatement, InsertStatement, ReplaceStatement,
52};
53#[doc(inline)]
54pub use self::query_id::QueryId;
55#[doc(inline)]
56pub use self::sql_query::{BoxedSqlQuery, SqlQuery};
57#[doc(inline)]
58pub use self::upsert::on_conflict_target_decorations::DecoratableTarget;
59
60#[doc(inline)]
61pub use self::update_statement::changeset::AsChangeset;
62#[doc(inline)]
63pub use self::update_statement::target::{IntoUpdateTarget, UpdateTarget};
64#[doc(inline)]
65pub use self::update_statement::{BoxedUpdateStatement, UpdateStatement};
66
67#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
68pub use self::combination_clause::{
69 All, Distinct, Except, Intersect, ParenthesisWrapper, SupportsCombinationClause, Union,
70};
71#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
72pub use self::limit_clause::{LimitClause, NoLimitClause};
73#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
74pub use self::limit_offset_clause::{BoxedLimitOffsetClause, LimitOffsetClause};
75#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
76pub use self::offset_clause::{NoOffsetClause, OffsetClause};
77#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
78pub use self::order_clause::{NoOrderClause, OrderClause};
79
80#[diesel_derives::__diesel_public_if(
81 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
82)]
83#[doc(inline)]
84pub(crate) use self::insert_statement::batch_insert::BatchInsert;
85#[diesel_derives::__diesel_public_if(
86 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
87)]
88pub(crate) use self::insert_statement::{UndecoratedInsertRecord, ValuesClause};
89
90#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
91#[doc(inline)]
92pub use self::insert_statement::{DefaultValues, InsertOrIgnore, Replace};
93
94#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
95#[doc(inline)]
96pub use self::returning_clause::ReturningClause;
97
98#[doc(inline)]
99#[diesel_derives::__diesel_public_if(
100 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
101)]
102pub(crate) use self::ast_pass::AstPassToSqlOptions;
103
104#[doc(inline)]
105#[diesel_derives::__diesel_public_if(
106 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
107)]
108pub(crate) use self::select_clause::SelectClauseExpression;
109
110#[doc(inline)]
111#[diesel_derives::__diesel_public_if(
112 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
113)]
114pub(crate) use self::from_clause::{FromClause, NoFromClause};
115#[diesel_derives::__diesel_public_if(
116 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
117)]
118#[doc(inline)]
119pub(crate) use self::select_statement::BoxedSelectStatement;
120
121#[diesel_derives::__diesel_public_if(
122 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
123)]
124#[doc(inline)]
125pub(crate) use self::select_statement::SelectStatement;
126
127pub(crate) use self::insert_statement::ColumnList;
128
129#[cfg(feature = "postgres_backend")]
130pub use crate::pg::query_builder::only::Only;
131
132#[cfg(feature = "postgres_backend")]
133pub use crate::pg::query_builder::tablesample::{Tablesample, TablesampleMethod};
134
135#[cfg(feature = "postgres_backend")]
136pub(crate) use self::bind_collector::ByteWrapper;
137use crate::backend::Backend;
138use crate::result::QueryResult;
139use std::error::Error;
140
141#[doc(hidden)]
142pub type Binds = Vec<Option<Vec<u8>>>;
143pub type BuildQueryResult = Result<(), Box<dyn Error + Send + Sync>>;
145
146pub trait QueryBuilder<DB: Backend> {
154 fn push_sql(&mut self, sql: &str);
156
157 fn push_identifier(&mut self, identifier: &str) -> QueryResult<()>;
160
161 fn push_bind_param(&mut self);
164
165 fn push_bind_param_value_only(&mut self) {}
168
169 fn finish(self) -> String;
171}
172
173pub trait Query {
185 type SqlType;
191}
192
193impl<T: Query> Query for &T {
194 type SqlType = T::SqlType;
195}
196
197pub trait SelectQuery {
206 type SqlType;
208}
209
210#[diagnostic::on_unimplemented(
220 message = "`{Self}` is no valid SQL fragment for the `{DB}` backend",
221 note = "this usually means that the `{DB}` database system does not support \n\
222 this SQL syntax"
223)]
224pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
225 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()>;
232
233 #[diesel_derives::__diesel_public_if(
237 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
238 )]
239 fn to_sql(&self, out: &mut DB::QueryBuilder, backend: &DB) -> QueryResult<()> {
240 let mut options = AstPassToSqlOptions::default();
241 self.walk_ast(AstPass::to_sql(out, &mut options, backend))
242 }
243
244 #[diesel_derives::__diesel_public_if(
251 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
252 )]
253 fn collect_binds<'b>(
254 &'b self,
255 out: &mut DB::BindCollector<'b>,
256 metadata_lookup: &mut DB::MetadataLookup,
257 backend: &'b DB,
258 ) -> QueryResult<()> {
259 self.walk_ast(AstPass::collect_binds(out, metadata_lookup, backend))
260 }
261
262 #[diesel_derives::__diesel_public_if(
278 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
279 )]
280 fn is_safe_to_cache_prepared(&self, backend: &DB) -> QueryResult<bool> {
281 let mut result = true;
282 self.walk_ast(AstPass::is_safe_to_cache_prepared(&mut result, backend))?;
283 Ok(result)
284 }
285
286 #[diesel_derives::__diesel_public_if(
288 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
289 )]
290 fn is_noop(&self, backend: &DB) -> QueryResult<bool> {
291 let mut result = true;
292 self.walk_ast(AstPass::is_noop(&mut result, backend))?;
293 Ok(result)
294 }
295}
296
297impl<T: ?Sized, DB> QueryFragment<DB> for Box<T>
298where
299 DB: Backend,
300 T: QueryFragment<DB>,
301{
302 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
303 QueryFragment::walk_ast(&**self, pass)
304 }
305}
306
307impl<T: ?Sized, DB> QueryFragment<DB> for &T
308where
309 DB: Backend,
310 T: QueryFragment<DB>,
311{
312 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
313 QueryFragment::walk_ast(&**self, pass)
314 }
315}
316
317impl<DB: Backend> QueryFragment<DB> for () {
318 fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
319 Ok(())
320 }
321}
322
323impl<T, DB> QueryFragment<DB> for Option<T>
324where
325 DB: Backend,
326 T: QueryFragment<DB>,
327{
328 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
329 match *self {
330 Some(ref c) => c.walk_ast(out),
331 None => Ok(()),
332 }
333 }
334}
335
336pub trait IntoBoxedClause<'a, DB> {
340 type BoxedClause;
342
343 fn into_boxed(self) -> Self::BoxedClause;
345}
346
347pub trait AsQuery {
354 type SqlType;
356
357 type Query: Query<SqlType = Self::SqlType>;
359
360 #[allow(clippy::wrong_self_convention)]
367 fn as_query(self) -> Self::Query;
368}
369
370impl<T: Query> AsQuery for T {
371 type SqlType = <T as Query>::SqlType;
372 type Query = T;
373
374 fn as_query(self) -> <T as AsQuery>::Query {
375 self
376 }
377}
378
379pub fn debug_query<DB, T>(query: &T) -> DebugQuery<'_, T, DB> {
428 DebugQuery::new(query)
429}
430
431mod private {
432 #[allow(missing_debug_implementations, missing_copy_implementations)]
433 pub struct NotSpecialized;
434}