1use std::marker::PhantomData;
2
3use super::Query;
4use crate::backend::{Backend, DieselReserveSpecialization};
5use crate::connection::Connection;
6use crate::query_builder::{AstPass, QueryFragment, QueryId};
7use crate::query_dsl::RunQueryDsl;
8use crate::result::QueryResult;
9use crate::serialize::ToSql;
10use crate::sql_types::{HasSqlType, Untyped};
11
12#[derive(#[automatically_derived]
impl<Inner: ::core::fmt::Debug> ::core::fmt::Debug for SqlQuery<Inner> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SqlQuery",
"inner", &self.inner, "query", &&self.query)
}
}Debug, #[automatically_derived]
impl<Inner: ::core::clone::Clone> ::core::clone::Clone for SqlQuery<Inner> {
#[inline]
fn clone(&self) -> SqlQuery<Inner> {
SqlQuery {
inner: ::core::clone::Clone::clone(&self.inner),
query: ::core::clone::Clone::clone(&self.query),
}
}
}Clone)]
13#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
14pub struct SqlQuery<Inner = self::private::Empty> {
22 inner: Inner,
23 query: String,
24}
25
26impl<Inner> SqlQuery<Inner> {
27 pub(crate) fn new(inner: Inner, query: String) -> Self {
28 SqlQuery { inner, query }
29 }
30
31 pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
84 UncheckedBind::new(self, value)
85 }
86
87 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
141 BoxedSqlQuery::new(self)
142 }
143
144 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
146 self.query += sql.as_ref();
147 self
148 }
149}
150
151impl SqlQuery {
152 pub(crate) fn from_sql(query: String) -> SqlQuery {
153 Self {
154 inner: self::private::Empty,
155 query,
156 }
157 }
158}
159
160impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
161where
162 DB: Backend + DieselReserveSpecialization,
163 Inner: QueryFragment<DB>,
164{
165 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
166 out.unsafe_to_cache_prepared();
167 self.inner.walk_ast(out.reborrow())?;
168 out.push_sql(&self.query);
169 Ok(())
170 }
171}
172
173impl<Inner> QueryId for SqlQuery<Inner> {
174 type QueryId = ();
175
176 const HAS_STATIC_QUERY_ID: bool = false;
177}
178
179impl<Inner> Query for SqlQuery<Inner> {
180 type SqlType = Untyped;
181}
182
183impl<Inner, Conn> RunQueryDsl<Conn> for SqlQuery<Inner> {}
184
185#[derive(#[automatically_derived]
impl<Query: ::core::fmt::Debug, Value: ::core::fmt::Debug,
ST: ::core::fmt::Debug> ::core::fmt::Debug for
UncheckedBind<Query, Value, ST> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "UncheckedBind",
"query", &self.query, "value", &self.value, "_marker",
&&self._marker)
}
}Debug, #[automatically_derived]
impl<Query: ::core::clone::Clone, Value: ::core::clone::Clone,
ST: ::core::clone::Clone> ::core::clone::Clone for
UncheckedBind<Query, Value, ST> {
#[inline]
fn clone(&self) -> UncheckedBind<Query, Value, ST> {
UncheckedBind {
query: ::core::clone::Clone::clone(&self.query),
value: ::core::clone::Clone::clone(&self.value),
_marker: ::core::clone::Clone::clone(&self._marker),
}
}
}Clone, #[automatically_derived]
impl<Query: ::core::marker::Copy, Value: ::core::marker::Copy,
ST: ::core::marker::Copy> ::core::marker::Copy for
UncheckedBind<Query, Value, ST> {
}Copy)]
186#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
187pub struct UncheckedBind<Query, Value, ST> {
189 query: Query,
190 value: Value,
191 _marker: PhantomData<ST>,
192}
193
194impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
195 pub fn new(query: Query, value: Value) -> Self {
196 UncheckedBind {
197 query,
198 value,
199 _marker: PhantomData,
200 }
201 }
202
203 pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
204 UncheckedBind::new(self, value)
205 }
206
207 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
208 BoxedSqlQuery::new(self)
209 }
210
211 pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
272 SqlQuery::new(self, sql.into())
273 }
274}
275
276impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
277where
278 Query: QueryId,
279 ST: QueryId,
280{
281 type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
282
283 const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
284}
285
286impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
287where
288 DB: Backend + HasSqlType<ST> + DieselReserveSpecialization,
289 Query: QueryFragment<DB>,
290 Value: ToSql<ST, DB>,
291{
292 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
293 self.query.walk_ast(out.reborrow())?;
294 out.push_bind_param_value_only(&self.value)?;
295 Ok(())
296 }
297}
298
299impl<Q, Value, ST> Query for UncheckedBind<Q, Value, ST> {
300 type SqlType = Untyped;
301}
302
303impl<Conn, Query, Value, ST> RunQueryDsl<Conn> for UncheckedBind<Query, Value, ST> {}
304
305#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
306#[allow(missing_debug_implementations)]
310pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
311 query: Query,
312 sql: String,
313 binds: Vec<Box<dyn QueryFragment<DB> + Send + 'f>>,
314}
315
316struct RawBind<ST, U> {
317 value: U,
318 p: PhantomData<ST>,
319}
320
321impl<ST, U, DB> QueryFragment<DB> for RawBind<ST, U>
322where
323 DB: Backend + HasSqlType<ST>,
324 U: ToSql<ST, DB>,
325{
326 fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
327 pass.push_bind_param_value_only(&self.value)
328 }
329}
330
331impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
332 pub(crate) fn new(query: Query) -> Self {
333 BoxedSqlQuery {
334 query,
335 sql: "".to_string(),
336 binds: ::alloc::vec::Vec::new()vec![],
337 }
338 }
339
340 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
344 where
345 DB: HasSqlType<BindSt>,
346 Value: ToSql<BindSt, DB> + Send + 'f,
347 BindSt: Send + 'f,
348 {
349 self.binds.push(Box::new(RawBind {
350 value: b,
351 p: PhantomData,
352 }) as Box<_>);
353 self
354 }
355
356 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
360 self.sql += sql.as_ref();
361 self
362 }
363}
364
365impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
366where
367 DB: Backend + DieselReserveSpecialization,
368 Query: QueryFragment<DB>,
369{
370 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
371 out.unsafe_to_cache_prepared();
372 self.query.walk_ast(out.reborrow())?;
373 out.push_sql(&self.sql);
374
375 for b in &self.binds {
376 b.walk_ast(out.reborrow())?;
377 }
378 Ok(())
379 }
380}
381
382impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
383 type QueryId = ();
384
385 const HAS_STATIC_QUERY_ID: bool = false;
386}
387
388impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
389where
390 DB: Backend,
391{
392 type SqlType = Untyped;
393}
394
395impl<Conn: Connection, Query> RunQueryDsl<Conn> for BoxedSqlQuery<'_, Conn::Backend, Query> {}
396
397mod private {
398 use crate::backend::{Backend, DieselReserveSpecialization};
399 use crate::query_builder::{QueryFragment, QueryId};
400
401 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for Empty {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Empty")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Empty {
#[inline]
fn clone(&self) -> Empty { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Empty { }Copy, const _: () =
{
use diesel;
#[allow(non_camel_case_types)]
impl diesel::query_builder::QueryId for Empty {
type QueryId = Empty<>;
const HAS_STATIC_QUERY_ID: bool = true;
const IS_WINDOW_FUNCTION: bool = false;
}
};QueryId)]
402 pub struct Empty;
403
404 impl<DB> QueryFragment<DB> for Empty
405 where
406 DB: Backend + DieselReserveSpecialization,
407 {
408 fn walk_ast<'b>(
409 &'b self,
410 _pass: crate::query_builder::AstPass<'_, 'b, DB>,
411 ) -> crate::QueryResult<()> {
412 Ok(())
413 }
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 fn assert_send<S: Send>(_: S) {}
420
421 #[diesel_test_helper::test]
422 fn check_boxed_sql_query_is_send() {
423 let query = crate::sql_query("SELECT 1")
424 .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
425 );
426
427 assert_send(query);
428 }
429}