keelson_core/clause/
limit.rs1use crate::expr::{Expr, IntoExpr};
2use crate::writer::{Expression, SqlWriter};
3
4#[derive(Debug, Clone, Default)]
12pub struct Limit {
13 pub count: Option<Expr>,
15}
16
17impl Limit {
18 pub fn set_limit(&mut self, count: impl IntoExpr) {
20 self.count = Some(count.into_expr());
21 }
22
23 pub fn is_empty(&self) -> bool {
25 self.count.is_none()
26 }
27}
28
29impl Expression for Limit {
30 fn write_sql(&self, w: &mut SqlWriter<'_>) {
31 w.write_if_some(self.count.as_ref(), "LIMIT ", "");
32 }
33}
34
35pub trait HasLimit {
37 fn limit_mut(&mut self) -> &mut Limit;
39}
40
41impl HasLimit for Limit {
42 fn limit_mut(&mut self) -> &mut Limit {
43 self
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use keelson_sqlcheck::testing::assert_frag_sql;
50
51 use super::*;
52 use crate::dialect::testing::Numbered;
53 use crate::expr::arg;
54 use crate::value::Value;
55 use crate::writer::build;
56
57 const FRAME: &str = r#"SELECT "id" FROM users {}"#;
59
60 fn sql(l: &Limit) -> String {
61 build(&Numbered, l).expect("render").0
62 }
63
64 #[test]
65 fn an_unset_limit_writes_nothing() {
66 assert_frag_sql(FRAME, &sql(&Limit::default()), "");
67 assert!(Limit::default().is_empty());
68 }
69
70 #[test]
71 fn a_count_is_a_literal_unless_it_is_bound() {
72 let mut l = Limit::default();
73 l.set_limit(10i64);
74 let (rendered, args) = build(&Numbered, &l).unwrap();
75 assert_frag_sql(FRAME, &rendered, "LIMIT 10");
76 assert!(args.is_empty(), "a number is a literal, not an argument");
77
78 l.set_limit(arg(10i64));
79 let (rendered, args) = build(&Numbered, &l).unwrap();
80 assert_frag_sql(FRAME, &rendered, "LIMIT $1");
81 assert_eq!(args, vec![Value::I64(10)]);
82 }
83
84 #[test]
85 fn a_count_may_be_any_expression() {
86 let mut l = Limit::default();
90 l.set_limit("(SELECT count(*) FROM users)");
91 assert_frag_sql(FRAME, &sql(&l), "LIMIT (SELECT count(*) FROM users)");
92 }
93}