diesel/sqlite/query_builder/
limit_offset.rs

1use crate::query_builder::limit_clause::{LimitClause, NoLimitClause};
2use crate::query_builder::limit_offset_clause::{BoxedLimitOffsetClause, LimitOffsetClause};
3use crate::query_builder::offset_clause::{NoOffsetClause, OffsetClause};
4use crate::query_builder::{AstPass, IntoBoxedClause, QueryFragment};
5use crate::result::QueryResult;
6use crate::sqlite::Sqlite;
7
8impl QueryFragment<Sqlite> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
9    fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
10        Ok(())
11    }
12}
13
14impl<L> QueryFragment<Sqlite> for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
15where
16    LimitClause<L>: QueryFragment<Sqlite>,
17{
18    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
19        self.limit_clause.walk_ast(out)?;
20        Ok(())
21    }
22}
23
24impl<O> QueryFragment<Sqlite> for LimitOffsetClause<NoLimitClause, OffsetClause<O>>
25where
26    OffsetClause<O>: QueryFragment<Sqlite>,
27{
28    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
29        // Sqlite requires a limit clause in front of any offset clause
30        // using `LIMIT -1` is the same as not having any limit clause
31        // https://sqlite.org/lang_select.html
32        out.push_sql(" LIMIT -1 ");
33        self.offset_clause.walk_ast(out)?;
34        Ok(())
35    }
36}
37
38impl<L, O> QueryFragment<Sqlite> for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
39where
40    LimitClause<L>: QueryFragment<Sqlite>,
41    OffsetClause<O>: QueryFragment<Sqlite>,
42{
43    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
44        self.limit_clause.walk_ast(out.reborrow())?;
45        self.offset_clause.walk_ast(out.reborrow())?;
46        Ok(())
47    }
48}
49
50impl QueryFragment<Sqlite> for BoxedLimitOffsetClause<'_, Sqlite> {
51    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
52        match (self.limit.as_ref(), self.offset.as_ref()) {
53            (Some(limit), Some(offset)) => {
54                limit.walk_ast(out.reborrow())?;
55                offset.walk_ast(out.reborrow())?;
56            }
57            (Some(limit), None) => {
58                limit.walk_ast(out.reborrow())?;
59            }
60            (None, Some(offset)) => {
61                // See the `QueryFragment` implementation for `LimitOffsetClause` for details.
62                out.push_sql(" LIMIT -1 ");
63                offset.walk_ast(out.reborrow())?;
64            }
65            (None, None) => {}
66        }
67        Ok(())
68    }
69}
70
71// Have explicit impls here because we need to set `Some`/`None` for the clauses
72// correspondingly, otherwise we cannot match on it in the `QueryFragment` impl
73// above
74impl<'a> IntoBoxedClause<'a, Sqlite> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
75    type BoxedClause = BoxedLimitOffsetClause<'a, Sqlite>;
76
77    fn into_boxed(self) -> Self::BoxedClause {
78        BoxedLimitOffsetClause {
79            limit: None,
80            offset: None,
81        }
82    }
83}
84
85impl<'a, L> IntoBoxedClause<'a, Sqlite> for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
86where
87    L: QueryFragment<Sqlite> + Send + 'a,
88{
89    type BoxedClause = BoxedLimitOffsetClause<'a, Sqlite>;
90
91    fn into_boxed(self) -> Self::BoxedClause {
92        BoxedLimitOffsetClause {
93            limit: Some(Box::new(self.limit_clause)),
94            offset: None,
95        }
96    }
97}
98
99impl<'a, O> IntoBoxedClause<'a, Sqlite> for LimitOffsetClause<NoLimitClause, OffsetClause<O>>
100where
101    O: QueryFragment<Sqlite> + Send + 'a,
102{
103    type BoxedClause = BoxedLimitOffsetClause<'a, Sqlite>;
104
105    fn into_boxed(self) -> Self::BoxedClause {
106        BoxedLimitOffsetClause {
107            limit: None,
108            offset: Some(Box::new(self.offset_clause)),
109        }
110    }
111}
112
113impl<'a, L, O> IntoBoxedClause<'a, Sqlite> for LimitOffsetClause<LimitClause<L>, OffsetClause<O>>
114where
115    L: QueryFragment<Sqlite> + Send + 'a,
116    O: QueryFragment<Sqlite> + Send + 'a,
117{
118    type BoxedClause = BoxedLimitOffsetClause<'a, Sqlite>;
119
120    fn into_boxed(self) -> Self::BoxedClause {
121        BoxedLimitOffsetClause {
122            limit: Some(Box::new(self.limit_clause)),
123            offset: Some(Box::new(self.offset_clause)),
124        }
125    }
126}