1use super::Query;
2use crate::backend::{Backend, DieselReserveSpecialization};
3use crate::query_builder::{AstPass, QueryFragment, QueryId};
4use crate::query_dsl::RunQueryDslSupport;
5use crate::result::QueryResult;
6use crate::serialize::ToSql;
7use crate::sql_types::{HasSqlType, Untyped};
8use alloc::boxed::Box;
9use alloc::string::String;
10use alloc::string::ToString;
11use alloc::sync::Arc;
12use alloc::vec::Vec;
13use core::marker::PhantomData;
14
15#[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) -> Self {
SqlQuery {
inner: ::core::clone::Clone::clone(&self.inner),
query: ::core::clone::Clone::clone(&self.query),
}
}
}Clone)]
16#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
17pub struct SqlQuery<Inner = self::private::Empty> {
25 inner: Inner,
26 query: String,
27}
28
29impl<Inner> SqlQuery<Inner> {
30 pub(crate) fn new(inner: Inner, query: String) -> Self {
31 SqlQuery { inner, query }
32 }
33
34 pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
87 UncheckedBind::new(self, value)
88 }
89
90 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
149 BoxedSqlQuery::new(self)
150 }
151
152 pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
212 BoxedCloneSqlQuery::new(self)
213 }
214
215 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
226 self.query += sql.as_ref();
227 self
228 }
229}
230
231impl SqlQuery {
232 pub(crate) fn from_sql(query: String) -> SqlQuery {
233 Self {
234 inner: self::private::Empty,
235 query,
236 }
237 }
238}
239
240impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
241where
242 DB: Backend + DieselReserveSpecialization,
243 Inner: QueryFragment<DB>,
244{
245 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
246 out.unsafe_to_cache_prepared();
247 self.inner.walk_ast(out.reborrow())?;
248 out.push_sql(&self.query);
249 Ok(())
250 }
251}
252
253impl<Inner> QueryId for SqlQuery<Inner> {
254 type QueryId = ();
255
256 const HAS_STATIC_QUERY_ID: bool = false;
257}
258
259impl<Inner> Query for SqlQuery<Inner> {
260 type SqlType = Untyped;
261}
262
263impl<Inner> RunQueryDslSupport for SqlQuery<Inner> {}
264
265#[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) -> Self {
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)]
266#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
267pub struct UncheckedBind<Query, Value, ST> {
269 query: Query,
270 value: Value,
271 _marker: PhantomData<ST>,
272}
273
274impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
275 pub fn new(query: Query, value: Value) -> Self {
276 UncheckedBind {
277 query,
278 value,
279 _marker: PhantomData,
280 }
281 }
282
283 pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
284 UncheckedBind::new(self, value)
285 }
286
287 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
288 BoxedSqlQuery::new(self)
289 }
290
291 pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
292 BoxedCloneSqlQuery::new(self)
293 }
294
295 pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
355 SqlQuery::new(self, sql.into())
356 }
357}
358
359impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
360where
361 Query: QueryId,
362 ST: QueryId,
363{
364 type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
365
366 const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
367}
368
369impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
370where
371 DB: Backend + HasSqlType<ST> + DieselReserveSpecialization,
372 Query: QueryFragment<DB>,
373 Value: ToSql<ST, DB>,
374{
375 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
376 self.query.walk_ast(out.reborrow())?;
377 out.push_bind_param_value_only(&self.value)?;
378 Ok(())
379 }
380}
381
382impl<Q, Value, ST> Query for UncheckedBind<Q, Value, ST> {
383 type SqlType = Untyped;
384}
385
386impl<Query, Value, ST> RunQueryDslSupport for UncheckedBind<Query, Value, ST> {}
387
388#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
389#[allow(missing_debug_implementations)]
393pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
394 query: Query,
395 sql: String,
396 binds: Vec<Box<dyn QueryFragment<DB> + Send + 'f>>,
397}
398
399#[derive(#[automatically_derived]
#[allow(missing_debug_implementations)]
impl<'f, DB: ::core::clone::Clone + Backend, Query: ::core::clone::Clone>
::core::clone::Clone for BoxedCloneSqlQuery<'f, DB, Query> {
#[inline]
fn clone(&self) -> Self {
BoxedCloneSqlQuery {
query: ::core::clone::Clone::clone(&self.query),
sql: ::core::clone::Clone::clone(&self.sql),
binds: ::core::clone::Clone::clone(&self.binds),
}
}
}Clone)]
400#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
401#[allow(missing_debug_implementations)]
405pub struct BoxedCloneSqlQuery<'f, DB: Backend, Query> {
406 query: Query,
407 sql: String,
408 binds: Vec<Arc<dyn QueryFragment<DB> + Send + Sync + 'f>>,
409}
410
411struct RawBind<ST, U> {
412 value: U,
413 p: PhantomData<ST>,
414}
415
416impl<ST, U, DB> QueryFragment<DB> for RawBind<ST, U>
417where
418 DB: Backend + HasSqlType<ST>,
419 U: ToSql<ST, DB>,
420{
421 fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
422 pass.push_bind_param_value_only(&self.value)
423 }
424}
425
426impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
427 pub(crate) fn new(query: Query) -> Self {
428 BoxedSqlQuery {
429 query,
430 sql: "".to_string(),
431 binds: ::alloc::vec::Vec::new()alloc::vec![],
432 }
433 }
434
435 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
439 where
440 DB: HasSqlType<BindSt>,
441 Value: ToSql<BindSt, DB> + Send + 'f,
442 BindSt: Send + 'f,
443 {
444 self.binds.push(Box::new(RawBind {
445 value: b,
446 p: PhantomData,
447 }) as Box<_>);
448 self
449 }
450
451 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
455 self.sql += sql.as_ref();
456 self
457 }
458}
459
460fn walk_boxed_sql_query<'b, DB, Query, P>(
462 query: &'b Query,
463 sql: &'b str,
464 binds: &'b [P],
465 mut out: AstPass<'_, 'b, DB>,
466) -> QueryResult<()>
467where
468 DB: Backend,
469 Query: QueryFragment<DB>,
470 P: QueryFragment<DB>,
471{
472 out.unsafe_to_cache_prepared();
473 query.walk_ast(out.reborrow())?;
474 out.push_sql(sql);
475
476 for b in binds {
477 b.walk_ast(out.reborrow())?;
478 }
479 Ok(())
480}
481
482impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
483where
484 DB: Backend + DieselReserveSpecialization,
485 Query: QueryFragment<DB>,
486{
487 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
488 walk_boxed_sql_query(&self.query, &self.sql, &self.binds, out)
489 }
490}
491
492impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
493 type QueryId = ();
494
495 const HAS_STATIC_QUERY_ID: bool = false;
496}
497
498impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
499where
500 DB: Backend,
501{
502 type SqlType = Untyped;
503}
504
505impl<DB: Backend, Query> RunQueryDslSupport for BoxedSqlQuery<'_, DB, Query> {}
506
507impl<'f, DB: Backend, Query> BoxedCloneSqlQuery<'f, DB, Query> {
508 pub(crate) fn new(query: Query) -> Self {
509 BoxedCloneSqlQuery {
510 query,
511 sql: "".to_string(),
512 binds: ::alloc::vec::Vec::new()alloc::vec![],
513 }
514 }
515
516 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
520 where
521 DB: HasSqlType<BindSt>,
522 Value: ToSql<BindSt, DB> + Send + Sync + 'f,
523 BindSt: Send + Sync + 'f,
524 {
525 self.binds.push(Arc::new(RawBind {
526 value: b,
527 p: PhantomData,
528 }) as Arc<_>);
529 self
530 }
531
532 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
536 self.sql += sql.as_ref();
537 self
538 }
539}
540
541impl<DB, Query> QueryFragment<DB> for BoxedCloneSqlQuery<'_, DB, Query>
542where
543 DB: Backend + DieselReserveSpecialization,
544 Query: QueryFragment<DB>,
545{
546 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
547 walk_boxed_sql_query(&self.query, &self.sql, &self.binds, out)
548 }
549}
550
551impl<DB: Backend, Query> QueryId for BoxedCloneSqlQuery<'_, DB, Query> {
552 type QueryId = ();
553
554 const HAS_STATIC_QUERY_ID: bool = false;
555}
556
557impl<DB, Q> Query for BoxedCloneSqlQuery<'_, DB, Q>
558where
559 DB: Backend,
560{
561 type SqlType = Untyped;
562}
563
564impl<DB: Backend, Query> RunQueryDslSupport for BoxedCloneSqlQuery<'_, DB, Query> {}
565
566mod private {
567 use crate::backend::{Backend, DieselReserveSpecialization};
568 use crate::query_builder::{QueryFragment, QueryId};
569
570 #[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Empty { }
#[automatically_derived]
impl ::core::clone::Clone for Empty {
#[inline]
fn clone(&self) -> Self { *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)]
571 pub struct Empty;
572
573 impl<DB> QueryFragment<DB> for Empty
574 where
575 DB: Backend + DieselReserveSpecialization,
576 {
577 fn walk_ast<'b>(
578 &'b self,
579 _pass: crate::query_builder::AstPass<'_, 'b, DB>,
580 ) -> crate::QueryResult<()> {
581 Ok(())
582 }
583 }
584}
585
586#[cfg(test)]
587mod tests {
588 fn assert_send<S: Send>(_: S) {}
589
590 #[diesel_test_helper::test]
591 fn check_boxed_sql_query_is_send() {
592 let query = crate::sql_query("SELECT 1")
593 .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
594 );
595
596 assert_send(query);
597 }
598}