Skip to main content

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