good_ormning/sqlite/query/
helpers.rs

1use {
2    super::expr::{
3        BinOp,
4        ComputeType,
5        Expr,
6        Binding,
7    },
8    crate::sqlite::{
9        schema::field::Field,
10        types::{
11            SimpleSimpleType,
12            SimpleType,
13            Type,
14        },
15    },
16    flowcontrol::shed,
17};
18
19/// Generates a field element for instert and update statements, to set a field
20/// from a parameter of the same type.
21pub fn set_field(param_name: impl Into<String>, f: &Field) -> (Field, Expr) {
22    (f.clone(), field_param(param_name, f))
23}
24
25/// Generates a param matching a field in name in type
26pub fn field_param(param_name: impl Into<String>, f: &Field) -> Expr {
27    Expr::Param {
28        name: param_name.into(),
29        type_: f.type_.type_.clone(),
30    }
31}
32
33/// Generates an expression checking for equality of a field and a parameter and
34/// the same type.
35pub fn expr_field_eq(param_name: impl Into<String>, f: &Field) -> Expr {
36    Expr::BinOp {
37        left: Box::new(Expr::Binding(Binding::field(f))),
38        op: BinOp::Equals,
39        right: Box::new(Expr::Param {
40            name: param_name.into(),
41            type_: f.type_.type_.clone(),
42        }),
43    }
44}
45
46/// Generates an expression selecting field values greater than a corresponding
47/// parameter
48pub fn expr_field_gt(param_name: impl Into<String>, f: &Field) -> Expr {
49    Expr::BinOp {
50        left: Box::new(Expr::Binding(Binding::field(f))),
51        op: BinOp::GreaterThan,
52        right: Box::new(Expr::Param {
53            name: param_name.into(),
54            type_: f.type_.type_.clone(),
55        }),
56    }
57}
58
59/// Generates an expression selecting field values greater than or equal to a
60/// corresponding parameter
61pub fn expr_field_gte(param_name: impl Into<String>, f: &Field) -> Expr {
62    Expr::BinOp {
63        left: Box::new(Expr::Binding(Binding::field(f))),
64        op: BinOp::GreaterThanEqualTo,
65        right: Box::new(Expr::Param {
66            name: param_name.into(),
67            type_: f.type_.type_.clone(),
68        }),
69    }
70}
71
72/// Generates an expression selecting field values greater than a corresponding
73/// parameter
74pub fn expr_field_lt(param_name: impl Into<String>, f: &Field) -> Expr {
75    Expr::BinOp {
76        left: Box::new(Expr::Binding(Binding::field(f))),
77        op: BinOp::LessThan,
78        right: Box::new(Expr::Param {
79            name: param_name.into(),
80            type_: f.type_.type_.clone(),
81        }),
82    }
83}
84
85/// Generates an expression selecting field values greater than or equal to a
86/// corresponding parameter
87pub fn expr_field_lte(param_name: impl Into<String>, f: &Field) -> Expr {
88    Expr::BinOp {
89        left: Box::new(Expr::Binding(Binding::field(f))),
90        op: BinOp::LessThanEqualTo,
91        right: Box::new(Expr::Param {
92            name: param_name.into(),
93            type_: f.type_.type_.clone(),
94        }),
95    }
96}
97
98/// Shortcut for chain AND expressions.
99pub fn expr_and(exprs: Vec<Expr>) -> Expr {
100    Expr::BinOpChain {
101        op: BinOp::And,
102        exprs: exprs,
103    }
104}
105
106/// Shortcut for chain OR expressions.
107pub fn expr_or(exprs: Vec<Expr>) -> Expr {
108    Expr::BinOpChain {
109        op: BinOp::Or,
110        exprs: exprs,
111    }
112}
113
114#[cfg(feature = "chrono")]
115pub fn as_utc_chrono(expr: Expr) -> Expr {
116    return Expr::Call {
117        func: "strftime".to_string(),
118        args: vec![Expr::LitString("%Y-%m-%dT%H:%M:%f".to_string()), expr],
119        compute_type: ComputeType::new(|ctx, path, args| {
120            shed!{
121                let arg = args.get(1).unwrap();
122                let Some(type_) = arg.0.iter().next() else {
123                    break;
124                };
125                if !matches!(type_.1.type_.type_, SimpleSimpleType::FixedOffsetTimeMsChrono) {
126                    ctx
127                        .errs
128                        .err(
129                            path,
130                            format!(
131                                "This method only operates on fixed-offset timestamps, but the argument is of type {:?}",
132                                type_.1.type_.type_
133                            ),
134                        );
135                }
136            };
137            return Some(Type {
138                type_: SimpleType {
139                    type_: SimpleSimpleType::UtcTimeMsChrono,
140                    custom: None,
141                },
142                opt: false,
143                array: false,
144            });
145        }),
146    }
147}
148
149pub fn fn_min(expr: Expr) -> Expr {
150    return Expr::Call {
151        func: "min".to_string(),
152        args: vec![expr],
153        compute_type: ComputeType::new(|ctx, path, args| {
154            let Some(t) = args.get(0).unwrap().assert_scalar(&mut ctx.errs, path) else {
155                return None;
156            };
157            return Some(t.1);
158        }),
159    }
160}
161
162pub fn fn_max(expr: Expr) -> Expr {
163    return Expr::Call {
164        func: "max".to_string(),
165        args: vec![expr],
166        compute_type: ComputeType::new(|ctx, path, args| {
167            let Some(t) = args.get(0).unwrap().assert_scalar(&mut ctx.errs, path) else {
168                return None;
169            };
170            return Some(t.1);
171        }),
172    }
173}
174
175pub fn fn_avg(expr: Expr) -> Expr {
176    return Expr::Call {
177        func: "avg".to_string(),
178        args: vec![expr],
179        compute_type: ComputeType::new(|ctx, path, args| {
180            let Some(t) = args.get(0).unwrap().assert_scalar(&mut ctx.errs, path) else {
181                return None;
182            };
183            return Some(t.1);
184        }),
185    }
186}
187
188pub fn fn_count(expr: Expr) -> Expr {
189    return Expr::Call {
190        func: "count".to_string(),
191        args: vec![expr],
192        compute_type: ComputeType::new(|_ctx, _path, _args| {
193            return Some(Type {
194                type_: SimpleType {
195                    type_: SimpleSimpleType::I64,
196                    custom: None,
197                },
198                opt: false,
199                array: false,
200            });
201        }),
202    }
203}