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