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 {
Self {
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 {
Self {
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 {
Self {
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
460impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
461where
462 DB: Backend + DieselReserveSpecialization,
463 Query: QueryFragment<DB>,
464{
465 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
466 out.unsafe_to_cache_prepared();
467 self.query.walk_ast(out.reborrow())?;
468 out.push_sql(&self.sql);
469
470 for b in &self.binds {
471 b.walk_ast(out.reborrow())?;
472 }
473 Ok(())
474 }
475}
476
477impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
478 type QueryId = ();
479
480 const HAS_STATIC_QUERY_ID: bool = false;
481}
482
483impl<DB, Q> Query for BoxedSqlQuery<'_, DB, Q>
484where
485 DB: Backend,
486{
487 type SqlType = Untyped;
488}
489
490impl<DB: Backend, Query> RunQueryDslSupport for BoxedSqlQuery<'_, DB, Query> {}
491
492impl<'f, DB: Backend, Query> BoxedCloneSqlQuery<'f, DB, Query> {
493 pub(crate) fn new(query: Query) -> Self {
494 BoxedCloneSqlQuery {
495 query,
496 sql: "".to_string(),
497 binds: ::alloc::vec::Vec::new()alloc::vec![],
498 }
499 }
500
501 pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
505 where
506 DB: HasSqlType<BindSt>,
507 Value: ToSql<BindSt, DB> + Send + Sync + 'f,
508 BindSt: Send + Sync + 'f,
509 {
510 self.binds.push(Arc::new(RawBind {
511 value: b,
512 p: PhantomData,
513 }) as Arc<_>);
514 self
515 }
516
517 pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
521 self.sql += sql.as_ref();
522 self
523 }
524}
525
526impl<DB, Query> QueryFragment<DB> for BoxedCloneSqlQuery<'_, DB, Query>
527where
528 DB: Backend + DieselReserveSpecialization,
529 Query: QueryFragment<DB>,
530{
531 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
532 out.unsafe_to_cache_prepared();
533 self.query.walk_ast(out.reborrow())?;
534 out.push_sql(&self.sql);
535
536 for b in &self.binds {
537 b.walk_ast(out.reborrow())?;
538 }
539 Ok(())
540 }
541}
542
543impl<DB: Backend, Query> QueryId for BoxedCloneSqlQuery<'_, DB, Query> {
544 type QueryId = ();
545
546 const HAS_STATIC_QUERY_ID: bool = false;
547}
548
549impl<DB, Q> Query for BoxedCloneSqlQuery<'_, DB, Q>
550where
551 DB: Backend,
552{
553 type SqlType = Untyped;
554}
555
556impl<DB: Backend, Query> RunQueryDslSupport for BoxedCloneSqlQuery<'_, DB, Query> {}
557
558mod private {
559 use crate::backend::{Backend, DieselReserveSpecialization};
560 use crate::query_builder::{QueryFragment, QueryId};
561
562 #[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)]
563 pub struct Empty;
564
565 impl<DB> QueryFragment<DB> for Empty
566 where
567 DB: Backend + DieselReserveSpecialization,
568 {
569 fn walk_ast<'b>(
570 &'b self,
571 _pass: crate::query_builder::AstPass<'_, 'b, DB>,
572 ) -> crate::QueryResult<()> {
573 Ok(())
574 }
575 }
576}
577
578#[cfg(test)]
579mod tests {
580 fn assert_send<S: Send>(_: S) {}
581
582 #[diesel_test_helper::test]
583 fn check_boxed_sql_query_is_send() {
584 let query = crate::sql_query("SELECT 1")
585 .into_boxed::<<crate::test_helpers::TestConnection as crate::Connection>::Backend>(
586 );
587
588 assert_send(query);
589 }
590}