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