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 query", &self.inner, &&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> {
92 UncheckedBind::new(self, value)
93 }
94
95 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
159 BoxedSqlQuery::new(self)
160 }
161
162 pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
227 BoxedCloneSqlQuery::new(self)
228 }
229
230 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
241 self.query += sql.as_ref();
242 self
243 }
244}
245
246impl SqlQuery {
247 pub(crate) fn from_sql(query: String) -> SqlQuery {
248 Self {
249 inner: self::private::Empty,
250 query,
251 }
252 }
253}
254
255impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
256where
257 DB: Backend + DieselReserveSpecialization,
258 Inner: QueryFragment<DB>,
259{
260 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
261 out.unsafe_to_cache_prepared();
262 self.inner.walk_ast(out.reborrow())?;
263 out.push_sql(&self.query);
264 Ok(())
265 }
266}
267
268impl<Inner> QueryId for SqlQuery<Inner> {
269 type QueryId = ();
270
271 const HAS_STATIC_QUERY_ID: bool = false;
272}
273
274impl<Inner> Query for SqlQuery<Inner> {
275 type SqlType = Untyped;
276}
277
278impl<Inner> RunQueryDslSupport for SqlQuery<Inner> {}
279
280#[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 value _marker", &self.query, &self.value,
&&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)]
281#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
282pub struct UncheckedBind<Query, Value, ST> {
284 query: Query,
285 value: Value,
286 _marker: PhantomData<ST>,
287}
288
289impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
290 pub fn new(query: Query, value: Value) -> Self {
291 UncheckedBind {
292 query,
293 value,
294 _marker: PhantomData,
295 }
296 }
297
298 pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
299 UncheckedBind::new(self, value)
300 }
301
302 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
303 BoxedSqlQuery::new(self)
304 }
305
306 pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
307 BoxedCloneSqlQuery::new(self)
308 }
309
310 pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
375 SqlQuery::new(self, sql.into())
376 }
377}
378
379impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
380where
381 Query: QueryId,
382 ST: QueryId,
383{
384 type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
385
386 const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
387}
388
389impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
390where
391 DB: Backend + HasSqlType<ST> + DieselReserveSpecialization,
392 Query: QueryFragment<DB>,
393 Value: ToSql<ST, DB>,
394{
395 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
396 self.query.walk_ast(out.reborrow())?;
397 out.push_bind_param_value_only(&self.value)?;
398 Ok(())
399 }
400}
401
402impl<Q, Value, ST> Query for UncheckedBind<Q, Value, ST> {
403 type SqlType = Untyped;
404}
405
406impl<Query, Value, ST> RunQueryDslSupport for UncheckedBind<Query, Value, ST> {}
407
408#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
409#[allow(missing_debug_implementations)]
413pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
414 query: Query,
415 sql: String,
416 binds: Vec<Box<dyn QueryFragment<DB> + Send + 'f>>,
417}
418
419#[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)]
420#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
421#[allow(missing_debug_implementations)]
425pub struct BoxedCloneSqlQuery<'f, DB: Backend, Query> {
426 query: Query,
427 sql: String,
428 binds: Vec<Arc<dyn QueryFragment<DB> + Send + Sync + 'f>>,
429}
430
431struct RawBind<ST, U> {
432 value: U,
433 p: PhantomData<ST>,
434}
435
436impl<ST, U, DB> QueryFragment<DB> for RawBind<ST, U>
437where
438 DB: Backend + HasSqlType<ST>,
439 U: ToSql<ST, DB>,
440{
441 fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
442 pass.push_bind_param_value_only(&self.value)
443 }
444}
445
446impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
447 pub(crate) fn new(query: Query) -> Self {
448 BoxedSqlQuery {
449 query,
450 sql: "".to_string(),
451 binds: ::alloc::vec::Vec::new()alloc::vec![],
452 }
453 }
454
455 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
459 where
460 DB: HasSqlType<BindSt>,
461 Value: ToSql<BindSt, DB> + Send + 'f,
462 BindSt: Send + 'f,
463 {
464 self.binds.push(Box::new(RawBind {
465 value: b,
466 p: PhantomData,
467 }) as Box<_>);
468 self
469 }
470
471 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
475 self.sql += sql.as_ref();
476 self
477 }
478}
479
480fn walk_boxed_sql_query<'b, DB, Query, P>(
482 query: &'b Query,
483 sql: &'b str,
484 binds: &'b [P],
485 mut out: AstPass<'_, 'b, DB>,
486) -> QueryResult<()>
487where
488 DB: Backend,
489 Query: QueryFragment<DB>,
490 P: QueryFragment<DB>,
491{
492 out.unsafe_to_cache_prepared();
493 query.walk_ast(out.reborrow())?;
494 out.push_sql(sql);
495
496 for b in binds {
497 b.walk_ast(out.reborrow())?;
498 }
499 Ok(())
500}
501
502impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
503where
504 DB: Backend + DieselReserveSpecialization,
505 Query: QueryFragment<DB>,
506{
507 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
508 walk_boxed_sql_query(&self.query, &self.sql, &self.binds, out)
509 }
510}
511
512impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
513 type QueryId = ();
514
515 const HAS_STATIC_QUERY_ID: bool = false;
516}
517
518impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
519where
520 DB: Backend,
521{
522 type SqlType = Untyped;
523}
524
525impl<DB: Backend, Query> RunQueryDslSupport for BoxedSqlQuery<'_, DB, Query> {}
526
527impl<'f, DB: Backend, Query> BoxedCloneSqlQuery<'f, DB, Query> {
528 pub(crate) fn new(query: Query) -> Self {
529 BoxedCloneSqlQuery {
530 query,
531 sql: "".to_string(),
532 binds: ::alloc::vec::Vec::new()alloc::vec![],
533 }
534 }
535
536 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
540 where
541 DB: HasSqlType<BindSt>,
542 Value: ToSql<BindSt, DB> + Send + Sync + 'f,
543 BindSt: Send + Sync + 'f,
544 {
545 self.binds.push(Arc::new(RawBind {
546 value: b,
547 p: PhantomData,
548 }) as Arc<_>);
549 self
550 }
551
552 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
556 self.sql += sql.as_ref();
557 self
558 }
559}
560
561impl<DB, Query> QueryFragment<DB> for BoxedCloneSqlQuery<'_, DB, Query>
562where
563 DB: Backend + DieselReserveSpecialization,
564 Query: QueryFragment<DB>,
565{
566 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
567 walk_boxed_sql_query(&self.query, &self.sql, &self.binds, out)
568 }
569}
570
571impl<DB: Backend, Query> QueryId for BoxedCloneSqlQuery<'_, DB, Query> {
572 type QueryId = ();
573
574 const HAS_STATIC_QUERY_ID: bool = false;
575}
576
577impl<DB, Q> Query for BoxedCloneSqlQuery<'_, DB, Q>
578where
579 DB: Backend,
580{
581 type SqlType = Untyped;
582}
583
584impl<DB: Backend, Query> RunQueryDslSupport for BoxedCloneSqlQuery<'_, DB, Query> {}
585
586mod private {
587 use crate::backend::{Backend, DieselReserveSpecialization};
588 use crate::query_builder::{QueryFragment, QueryId};
589
590 #[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)]
591 pub struct Empty;
592
593 impl<DB> QueryFragment<DB> for Empty
594 where
595 DB: Backend + DieselReserveSpecialization,
596 {
597 fn walk_ast<'b>(
598 &'b self,
599 _pass: crate::query_builder::AstPass<'_, 'b, DB>,
600 ) -> crate::QueryResult<()> {
601 Ok(())
602 }
603 }
604}
605
606#[cfg(test)]
607mod tests {
608 fn assert_send<S: Send>(_: S) {}
609
610 #[diesel_test_helper::test]
611 fn check_boxed_sql_query_is_send() {
612 let query = crate::sql_query("SELECT 1")
613 .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
614 );
615
616 assert_send(query);
617 }
618}