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) -> SqlQuery<Inner> {
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 {
217 self.query += sql.as_ref();
218 self
219 }
220}
221
222impl SqlQuery {
223 pub(crate) fn from_sql(query: String) -> SqlQuery {
224 Self {
225 inner: self::private::Empty,
226 query,
227 }
228 }
229}
230
231impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
232where
233 DB: Backend + DieselReserveSpecialization,
234 Inner: QueryFragment<DB>,
235{
236 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
237 out.unsafe_to_cache_prepared();
238 self.inner.walk_ast(out.reborrow())?;
239 out.push_sql(&self.query);
240 Ok(())
241 }
242}
243
244impl<Inner> QueryId for SqlQuery<Inner> {
245 type QueryId = ();
246
247 const HAS_STATIC_QUERY_ID: bool = false;
248}
249
250impl<Inner> Query for SqlQuery<Inner> {
251 type SqlType = Untyped;
252}
253
254impl<Inner> RunQueryDslSupport for SqlQuery<Inner> {}
255
256#[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)]
257#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
258pub struct UncheckedBind<Query, Value, ST> {
260 query: Query,
261 value: Value,
262 _marker: PhantomData<ST>,
263}
264
265impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
266 pub fn new(query: Query, value: Value) -> Self {
267 UncheckedBind {
268 query,
269 value,
270 _marker: PhantomData,
271 }
272 }
273
274 pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
275 UncheckedBind::new(self, value)
276 }
277
278 pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
279 BoxedSqlQuery::new(self)
280 }
281
282 pub fn into_boxed_clone<'f, DB: Backend>(self) -> BoxedCloneSqlQuery<'f, DB, Self> {
283 BoxedCloneSqlQuery::new(self)
284 }
285
286 pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
347 SqlQuery::new(self, sql.into())
348 }
349}
350
351impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
352where
353 Query: QueryId,
354 ST: QueryId,
355{
356 type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;
357
358 const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
359}
360
361impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
362where
363 DB: Backend + HasSqlType<ST> + DieselReserveSpecialization,
364 Query: QueryFragment<DB>,
365 Value: ToSql<ST, DB>,
366{
367 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
368 self.query.walk_ast(out.reborrow())?;
369 out.push_bind_param_value_only(&self.value)?;
370 Ok(())
371 }
372}
373
374impl<Q, Value, ST> Query for UncheckedBind<Q, Value, ST> {
375 type SqlType = Untyped;
376}
377
378impl<Query, Value, ST> RunQueryDslSupport for UncheckedBind<Query, Value, ST> {}
379
380#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
381#[allow(missing_debug_implementations)]
385pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
386 query: Query,
387 sql: String,
388 binds: Vec<Box<dyn QueryFragment<DB> + Send + 'f>>,
389}
390
391#[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) -> BoxedCloneSqlQuery<'f, DB, Query> {
BoxedCloneSqlQuery {
query: ::core::clone::Clone::clone(&self.query),
sql: ::core::clone::Clone::clone(&self.sql),
binds: ::core::clone::Clone::clone(&self.binds),
}
}
}Clone)]
392#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
393#[allow(missing_debug_implementations)]
397pub struct BoxedCloneSqlQuery<'f, DB: Backend, Query> {
398 query: Query,
399 sql: String,
400 binds: Vec<Arc<dyn QueryFragment<DB> + Send + Sync + 'f>>,
401}
402
403struct RawBind<ST, U> {
404 value: U,
405 p: PhantomData<ST>,
406}
407
408impl<ST, U, DB> QueryFragment<DB> for RawBind<ST, U>
409where
410 DB: Backend + HasSqlType<ST>,
411 U: ToSql<ST, DB>,
412{
413 fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
414 pass.push_bind_param_value_only(&self.value)
415 }
416}
417
418impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
419 pub(crate) fn new(query: Query) -> Self {
420 BoxedSqlQuery {
421 query,
422 sql: "".to_string(),
423 binds: ::alloc::vec::Vec::new()alloc::vec![],
424 }
425 }
426
427 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
431 where
432 DB: HasSqlType<BindSt>,
433 Value: ToSql<BindSt, DB> + Send + 'f,
434 BindSt: Send + 'f,
435 {
436 self.binds.push(Box::new(RawBind {
437 value: b,
438 p: PhantomData,
439 }) as Box<_>);
440 self
441 }
442
443 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
447 self.sql += sql.as_ref();
448 self
449 }
450}
451
452impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
453where
454 DB: Backend + DieselReserveSpecialization,
455 Query: QueryFragment<DB>,
456{
457 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
458 out.unsafe_to_cache_prepared();
459 self.query.walk_ast(out.reborrow())?;
460 out.push_sql(&self.sql);
461
462 for b in &self.binds {
463 b.walk_ast(out.reborrow())?;
464 }
465 Ok(())
466 }
467}
468
469impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
470 type QueryId = ();
471
472 const HAS_STATIC_QUERY_ID: bool = false;
473}
474
475impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
476where
477 DB: Backend,
478{
479 type SqlType = Untyped;
480}
481
482impl<DB: Backend, Query> RunQueryDslSupport for BoxedSqlQuery<'_, DB, Query> {}
483
484impl<'f, DB: Backend, Query> BoxedCloneSqlQuery<'f, DB, Query> {
485 pub(crate) fn new(query: Query) -> Self {
486 BoxedCloneSqlQuery {
487 query,
488 sql: "".to_string(),
489 binds: ::alloc::vec::Vec::new()alloc::vec![],
490 }
491 }
492
493 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
497 where
498 DB: HasSqlType<BindSt>,
499 Value: ToSql<BindSt, DB> + Send + Sync + 'f,
500 BindSt: Send + Sync + 'f,
501 {
502 self.binds.push(Arc::new(RawBind {
503 value: b,
504 p: PhantomData,
505 }) as Arc<_>);
506 self
507 }
508
509 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
513 self.sql += sql.as_ref();
514 self
515 }
516}
517
518impl<DB, Query> QueryFragment<DB> for BoxedCloneSqlQuery<'_, DB, Query>
519where
520 DB: Backend + DieselReserveSpecialization,
521 Query: QueryFragment<DB>,
522{
523 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
524 out.unsafe_to_cache_prepared();
525 self.query.walk_ast(out.reborrow())?;
526 out.push_sql(&self.sql);
527
528 for b in &self.binds {
529 b.walk_ast(out.reborrow())?;
530 }
531 Ok(())
532 }
533}
534
535impl<DB: Backend, Query> QueryId for BoxedCloneSqlQuery<'_, DB, Query> {
536 type QueryId = ();
537
538 const HAS_STATIC_QUERY_ID: bool = false;
539}
540
541impl<DB, Q> Query for BoxedCloneSqlQuery<'_, DB, Q>
542where
543 DB: Backend,
544{
545 type SqlType = Untyped;
546}
547
548impl<DB: Backend, Query> RunQueryDslSupport for BoxedCloneSqlQuery<'_, DB, Query> {}
549
550mod private {
551 use crate::backend::{Backend, DieselReserveSpecialization};
552 use crate::query_builder::{QueryFragment, QueryId};
553
554 #[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)]
555 pub struct Empty;
556
557 impl<DB> QueryFragment<DB> for Empty
558 where
559 DB: Backend + DieselReserveSpecialization,
560 {
561 fn walk_ast<'b>(
562 &'b self,
563 _pass: crate::query_builder::AstPass<'_, 'b, DB>,
564 ) -> crate::QueryResult<()> {
565 Ok(())
566 }
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 fn assert_send<S: Send>(_: S) {}
573
574 #[diesel_test_helper::test]
575 fn check_boxed_sql_query_is_send() {
576 let query = crate::sql_query("SELECT 1")
577 .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
578 );
579
580 assert_send(query);
581 }
582}