good_ormning/sqlite/query/
expr.rs

1use {
2    super::{
3        select_body::{
4            Order,
5            SelectBody,
6            SelectJunction,
7        },
8        utils::SqliteQueryCtx,
9    },
10    crate::{
11        sqlite::{
12            query::select_body::build_select_junction,
13            schema::field::Field,
14            types::{
15                to_rust_types,
16                SimpleSimpleType,
17                SimpleType,
18                Type,
19            },
20            QueryResCount,
21        },
22        utils::{
23            sanitize_ident,
24            Errs,
25            Tokens,
26        },
27    },
28    quote::{
29        format_ident,
30        quote,
31        ToTokens,
32    },
33    samevariant::samevariant,
34    std::{
35        collections::HashMap,
36        fmt::Display,
37        rc::Rc,
38    },
39    syn::Path,
40};
41#[cfg(feature = "chrono")]
42use {
43    chrono::{
44        DateTime,
45        FixedOffset,
46        Utc,
47    },
48};
49#[cfg(feature = "jiff")]
50use {
51    jiff::{
52        Timestamp,
53    },
54};
55
56/// This is used for function expressions, to check the argument types and compute
57/// a result type from them.  See readme for details.
58#[derive(Clone)]
59pub struct ComputeType(Rc<dyn Fn(&mut SqliteQueryCtx, &rpds::Vector<String>, Vec<ExprType>) -> Option<Type>>);
60
61impl ComputeType {
62    pub fn new(
63        f: impl Fn(&mut SqliteQueryCtx, &rpds::Vector<String>, Vec<ExprType>) -> Option<Type> + 'static,
64    ) -> ComputeType {
65        return ComputeType(Rc::new(f));
66    }
67}
68
69impl std::fmt::Debug for ComputeType {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        return f.write_str("ComputeType");
72    }
73}
74
75#[derive(Clone, Debug)]
76pub enum Expr {
77    LitArray(Vec<Expr>),
78    // A null value needs a type for type checking purposes. It will always be trated
79    // as an optional value.
80    LitNull(SimpleType),
81    LitBool(bool),
82    LitI32(i32),
83    LitI64(i64),
84    LitU32(u32),
85    LitF32(f32),
86    LitF64(f64),
87    LitString(String),
88    LitBytes(Vec<u8>),
89    #[cfg(feature = "chrono")]
90    LitUtcTimeSChrono(DateTime<Utc>),
91    #[cfg(feature = "chrono")]
92    LitUtcTimeMsChrono(DateTime<Utc>),
93    #[cfg(feature = "chrono")]
94    LitFixedOffsetTimeMsChrono(DateTime<FixedOffset>),
95    #[cfg(feature = "jiff")]
96    LitUtcTimeSJiff(Timestamp),
97    #[cfg(feature = "jiff")]
98    LitUtcTimeMsJiff(Timestamp),
99    /// A query parameter. This will become a parameter to the generated Rust function
100    /// with the specified `name` and `type_`.
101    Param {
102        name: String,
103        type_: Type,
104    },
105    /// This evaluates to the value of a field in the query main or joined tables. If
106    /// you've aliased tables or field names, you'll have to instantiate `FieldId`
107    /// yourself with the appropriate values. For synthetic values like function
108    /// results you may need a `FieldId` with an empty `TableId` (`""`).
109    Binding(Binding),
110    BinOp {
111        left: Box<Expr>,
112        op: BinOp,
113        right: Box<Expr>,
114    },
115    /// This is the same as `BinOp` but allows chaining multiple expressions with the
116    /// same operator. This can be useful if you have many successive `AND`s or similar.
117    BinOpChain {
118        op: BinOp,
119        exprs: Vec<Expr>,
120    },
121    PrefixOp {
122        op: PrefixOp,
123        right: Box<Expr>,
124    },
125    /// Represents a call to an SQL function, like `collate()`. You must provide the
126    /// type of the result since we don't have a table of functions and their return
127    /// types at present.
128    Call {
129        func: String,
130        args: Vec<Expr>,
131        /// Checks the input types and computes the resulting type
132        compute_type: ComputeType,
133    },
134    // This is an `OVER` windowing function. If neither `partition_by` nor `order_by`
135    // have elements it'll be rendered as `OVER()` (all rows).
136    Window {
137        expr: Box<Expr>,
138        partition_by: Vec<Expr>,
139        order_by: Vec<(Expr, Order)>,
140    },
141    /// A sub SELECT query.
142    Select {
143        body: Box<SelectBody>,
144        body_junctions: Vec<SelectJunction>,
145    },
146    Exists {
147        not: bool,
148        body: Box<SelectBody>,
149        body_junctions: Vec<SelectJunction>,
150    },
151    /// This is a synthetic expression, saying to treat the result of the expression as
152    /// having the specified type. Use this for casting between primitive types and
153    /// Rust new-types for instance.
154    Cast(Box<Expr>, Type),
155}
156
157impl Expr {
158    pub fn field(f: &Field) -> Expr {
159        return Expr::Binding(Binding::field(f));
160    }
161}
162
163#[derive(Clone, Hash, PartialEq, Eq, Debug)]
164pub struct Binding {
165    pub table_id: String,
166    pub id: String,
167}
168
169impl Binding {
170    /// Create an expression field/value name for a select-local (tableless) field, for
171    /// instance `WINDOW` fields.
172    pub fn local(name: impl AsRef<str>) -> Self {
173        Binding {
174            table_id: "".into(),
175            id: name.as_ref().to_string(),
176        }
177    }
178
179    pub(crate) fn empty() -> Self {
180        Binding {
181            table_id: "".into(),
182            id: "".into(),
183        }
184    }
185
186    /// Create an expression field/value name from a table field.
187    pub fn field(f: &Field) -> Self {
188        Binding {
189            table_id: f.table.id.clone(),
190            id: f.id.clone(),
191        }
192    }
193
194    /// Derive an expression field/value name from a different name, with a new alias.
195    pub fn with_alias(&self, s: &str) -> Binding {
196        Binding {
197            table_id: s.into(),
198            id: self.id.clone(),
199        }
200    }
201}
202
203impl Display for Binding {
204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205        Display::fmt(&format!("{}.{}", self.table_id, self.id), f)
206    }
207}
208
209pub struct ExprType(pub Vec<(Binding, Type)>);
210
211impl ExprType {
212    pub fn assert_scalar(&self, errs: &mut Errs, path: &rpds::Vector<String>) -> Option<(Binding, Type)> {
213        if self.0.len() != 1 {
214            errs.err(path, format!("Select outputs must be scalars, but got result with {} fields", self.0.len()));
215            return None;
216        }
217        Some(self.0[0].clone())
218    }
219}
220
221pub fn check_general_same_type(ctx: &mut SqliteQueryCtx, path: &rpds::Vector<String>, left: &Type, right: &Type) {
222    if left.opt != right.opt {
223        ctx.errs.err(path, format!("Operator arms have differing optionality"));
224    }
225    if left.array != right.array {
226        ctx.errs.err(path, format!("Operator arms are either not both arrays or not both scalars"));
227    }
228
229    #[derive(Debug)]
230    #[samevariant(GeneralTypePairs)]
231    enum GeneralType {
232        Bool,
233        Numeric,
234        Blob,
235    }
236
237    fn general_type(t: &Type) -> GeneralType {
238        match t.type_.type_ {
239            SimpleSimpleType::U32 => GeneralType::Numeric,
240            SimpleSimpleType::I32 => GeneralType::Numeric,
241            SimpleSimpleType::I64 => GeneralType::Numeric,
242            SimpleSimpleType::F32 => GeneralType::Numeric,
243            SimpleSimpleType::F64 => GeneralType::Numeric,
244            SimpleSimpleType::Bool => GeneralType::Bool,
245            SimpleSimpleType::String => GeneralType::Blob,
246            SimpleSimpleType::Bytes => GeneralType::Blob,
247            #[cfg(feature = "chrono")]
248            SimpleSimpleType::UtcTimeSChrono => GeneralType::Numeric,
249            #[cfg(feature = "chrono")]
250            SimpleSimpleType::UtcTimeMsChrono => GeneralType::Blob,
251            #[cfg(feature = "chrono")]
252            SimpleSimpleType::FixedOffsetTimeMsChrono => GeneralType::Blob,
253            #[cfg(feature = "jiff")]
254            SimpleSimpleType::UtcTimeSJiff => GeneralType::Numeric,
255            #[cfg(feature = "jiff")]
256            SimpleSimpleType::UtcTimeMsJiff => GeneralType::Blob,
257        }
258    }
259
260    match GeneralTypePairs::pairs(&general_type(left), &general_type(right)) {
261        GeneralTypePairs::Nonmatching(left, right) => {
262            ctx.errs.err(path, format!("Operator arms have incompatible types: {:?} and {:?}", left, right));
263        },
264        _ => { },
265    }
266}
267
268pub(crate) fn check_general_same(
269    ctx: &mut SqliteQueryCtx,
270    path: &rpds::Vector<String>,
271    left: &ExprType,
272    right: &ExprType,
273) {
274    if left.0.len() != right.0.len() {
275        ctx
276            .errs
277            .err(
278                path,
279                format!(
280                    "Operator arms record type lengths don't match: left has {} fields and right has {}",
281                    left.0.len(),
282                    right.0.len()
283                ),
284            );
285    } else if left.0.len() == 1 && right.0.len() == 1 {
286        check_general_same_type(ctx, path, &left.0[0].1, &left.0[0].1);
287    } else {
288        for (i, (left, right)) in left.0.iter().zip(right.0.iter()).enumerate() {
289            check_general_same_type(ctx, &path.push_back(format!("Record pair {}", i)), &left.1, &right.1);
290        }
291    }
292}
293
294pub(crate) fn check_same(
295    errs: &mut Errs,
296    path: &rpds::Vector<String>,
297    left: &ExprType,
298    right: &ExprType,
299) -> Option<Type> {
300    let left = match left.assert_scalar(errs, &path.push_back("Left".into())) {
301        Some(t) => t,
302        None => {
303            return None;
304        },
305    };
306    let right = match right.assert_scalar(errs, &path.push_back("Right".into())) {
307        Some(t) => t,
308        None => {
309            return None;
310        },
311    };
312    if left.1.opt != right.1.opt {
313        errs.err(
314            path,
315            format!(
316                "Expected same types, but left nullability is {} but right nullability is {}",
317                left.1.opt,
318                right.1.opt
319            ),
320        );
321    }
322    if left.1.type_.custom != right.1.type_.custom {
323        errs.err(
324            path,
325            format!(
326                "Expected same types, but left rust type is {:?} while right rust type is {:?}",
327                left.1.type_.custom,
328                right.1.type_.custom
329            ),
330        );
331    }
332    if left.1.type_.type_ != right.1.type_.type_ {
333        errs.err(
334            path,
335            format!(
336                "Expected same types, but left base type is {:?} while right base type is {:?}",
337                left.1.type_.type_,
338                right.1.type_.type_
339            ),
340        );
341    }
342    Some(left.1.clone())
343}
344
345pub(crate) fn check_bool(ctx: &mut SqliteQueryCtx, path: &rpds::Vector<String>, a: &ExprType) {
346    let t = match a.assert_scalar(&mut ctx.errs, path) {
347        Some(t) => t,
348        None => {
349            return;
350        },
351    };
352    if t.1.opt {
353        ctx.errs.err(path, format!("Expected bool type but is nullable: got {:?}", t));
354    }
355    if !matches!(t.1.type_.type_, SimpleSimpleType::Bool) {
356        ctx.errs.err(path, format!("Expected bool but type is non-bool: got {:?}", t.1.type_.type_));
357    }
358}
359
360#[cfg(feature = "chrono")]
361pub(crate) fn check_utc_if_time(ctx: &mut SqliteQueryCtx, path: &rpds::Vector<String>, t: &ExprType) {
362    for (i, el) in t.0.iter().enumerate() {
363        if matches!(el.1.type_.type_, SimpleSimpleType::FixedOffsetTimeMsChrono) {
364            ctx.errs.err(
365                &if t.0.len() == 1 {
366                    path.clone()
367                } else {
368                    path.push_back(format!("Record pair {}", i))
369                },
370                format!(
371                    "Datetimes with non-utc offsets may not be used in normal binary operators - use the `Tz` operators instead"
372                ),
373            );
374        }
375    }
376}
377
378pub(crate) fn check_assignable(errs: &mut Errs, path: &rpds::Vector<String>, a: &Type, b: &ExprType) {
379    check_same(errs, path, &ExprType(vec![(Binding::empty(), a.clone())]), b);
380}
381
382impl Expr {
383    pub(crate) fn build(
384        &self,
385        ctx: &mut SqliteQueryCtx,
386        path: &rpds::Vector<String>,
387        scope: &HashMap<Binding, Type>,
388    ) -> (ExprType, Tokens) {
389        macro_rules! empty_type{
390            ($o: expr, $t: expr) => {
391                (ExprType(vec![(Binding::empty(), Type {
392                    type_: SimpleType {
393                        type_: $t,
394                        custom: None,
395                    },
396                    opt: false,
397                    array: false,
398                })]), $o)
399            };
400        }
401
402        fn do_bin_op(
403            ctx: &mut SqliteQueryCtx,
404            path: &rpds::Vector<String>,
405            scope: &HashMap<Binding, Type>,
406            op: &BinOp,
407            exprs: &Vec<Expr>,
408        ) -> (ExprType, Tokens) {
409            let operand_lower_limit;
410            match op {
411                BinOp::Plus | BinOp::Minus | BinOp::Multiply | BinOp::Divide | BinOp::And | BinOp::Or => {
412                    operand_lower_limit = 1;
413                },
414                BinOp::Equals |
415                BinOp::NotEquals |
416                BinOp::Is |
417                BinOp::IsNot |
418                BinOp::TzEquals |
419                BinOp::TzNotEquals |
420                BinOp::TzIs |
421                BinOp::TzIsNot |
422                BinOp::LessThan |
423                BinOp::LessThanEqualTo |
424                BinOp::GreaterThan |
425                BinOp::GreaterThanEqualTo |
426                BinOp::Like |
427                BinOp::In |
428                BinOp::NotIn => {
429                    operand_lower_limit = 2;
430                },
431            };
432            if exprs.len() < operand_lower_limit {
433                ctx
434                    .errs
435                    .err(
436                        path,
437                        format!(
438                            "{:?} must have at least {} operand(s), but got {}",
439                            op,
440                            operand_lower_limit,
441                            exprs.len()
442                        ),
443                    );
444            }
445            let mut res = vec![];
446            for (i, e) in exprs.iter().enumerate() {
447                res.push(e.build(ctx, &path.push_back(format!("Operand {}", i)), scope));
448            }
449            let t = match op {
450                BinOp::Plus | BinOp::Minus | BinOp::Multiply | BinOp::Divide => {
451                    let base = res.get(0).unwrap();
452                    let t =
453                        match check_same(
454                            &mut ctx.errs,
455                            &path.push_back(format!("Operands 0, 1")),
456                            &base.0,
457                            &res.get(0).unwrap().0,
458                        ) {
459                            Some(t) => t,
460                            None => {
461                                return (ExprType(vec![]), Tokens::new());
462                            },
463                        };
464                    for (i, res) in res.iter().enumerate().skip(2) {
465                        match check_same(
466                            &mut ctx.errs,
467                            &path.push_back(format!("Operands 0, {}", i)),
468                            &base.0,
469                            &res.0,
470                        ) {
471                            Some(_) => { },
472                            None => {
473                                return (ExprType(vec![]), Tokens::new());
474                            },
475                        };
476                    }
477                    t
478                },
479                BinOp::And | BinOp::Or => {
480                    for (i, res) in res.iter().enumerate() {
481                        check_bool(ctx, &path.push_back(format!("Operand {}", i)), &res.0);
482                    }
483                    Type {
484                        type_: SimpleType {
485                            type_: SimpleSimpleType::Bool,
486                            custom: None,
487                        },
488                        array: false,
489                        opt: false,
490                    }
491                },
492                BinOp::Equals |
493                BinOp::NotEquals |
494                BinOp::Is |
495                BinOp::IsNot |
496                BinOp::TzEquals |
497                BinOp::TzNotEquals |
498                BinOp::TzIs |
499                BinOp::TzIsNot |
500                BinOp::LessThan |
501                BinOp::LessThanEqualTo |
502                BinOp::GreaterThan |
503                BinOp::GreaterThanEqualTo |
504                BinOp::Like => {
505                    #[cfg(feature = "chrono")]
506                    if match op {
507                        BinOp::TzEquals | BinOp::TzNotEquals | BinOp::TzIs | BinOp::TzIsNot => false,
508                        _ => true,
509                    } {
510                        for (i, el) in res.iter().enumerate() {
511                            check_utc_if_time(ctx, &path.push_back(format!("Operand {}", i)), &el.0);
512                        }
513                    }
514                    let base = res.get(0).unwrap();
515                    check_general_same(
516                        ctx,
517                        &path.push_back(format!("Operands 0, 1")),
518                        &base.0,
519                        &res.get(1).unwrap().0,
520                    );
521                    for (i, res) in res.iter().enumerate().skip(2) {
522                        check_general_same(ctx, &path.push_back(format!("Operands 0, {}", i)), &base.0, &res.0);
523                    }
524                    Type {
525                        type_: SimpleType {
526                            type_: SimpleSimpleType::Bool,
527                            custom: None,
528                        },
529                        opt: false,
530                        array: false,
531                    }
532                },
533                BinOp::In | BinOp::NotIn => {
534                    #[cfg(feature = "chrono")]
535                    if match op {
536                        BinOp::TzEquals | BinOp::TzNotEquals | BinOp::TzIs | BinOp::TzIsNot => false,
537                        _ => true,
538                    } {
539                        for (i, el) in res.iter().enumerate() {
540                            check_utc_if_time(ctx, &path.push_back(format!("Operand {}", i)), &el.0);
541                        }
542                    }
543                    let base = res.get(0).unwrap();
544                    check_general_same(
545                        ctx,
546                        &path.push_back(format!("Operands 0, 1")),
547                        &base.0,
548                        &res.get(1).unwrap().0,
549                    );
550                    for (i, res) in res.iter().enumerate().skip(2) {
551                        check_general_same(ctx, &path.push_back(format!("Operands 0, {}", i)), &base.0, &res.0);
552                    }
553                    Type {
554                        type_: SimpleType {
555                            type_: SimpleSimpleType::Bool,
556                            custom: None,
557                        },
558                        opt: false,
559                        array: false,
560                    }
561                },
562            };
563            let token = match op {
564                BinOp::Plus => "+",
565                BinOp::Minus => "-",
566                BinOp::Multiply => "*",
567                BinOp::Divide => "/",
568                BinOp::And => "and",
569                BinOp::Or => "or",
570                BinOp::Equals => "=",
571                BinOp::NotEquals => "!=",
572                BinOp::Is => "is",
573                BinOp::IsNot => "is not",
574                BinOp::TzEquals => "=",
575                BinOp::TzNotEquals => "!=",
576                BinOp::TzIs => "is",
577                BinOp::TzIsNot => "is not",
578                BinOp::LessThan => "<",
579                BinOp::LessThanEqualTo => "<=",
580                BinOp::GreaterThan => ">",
581                BinOp::GreaterThanEqualTo => ">=",
582                BinOp::Like => "like",
583                BinOp::In => "in",
584                BinOp::NotIn => "not in",
585            };
586            let mut out = Tokens::new();
587            out.s("(");
588            for (i, res) in res.iter().enumerate() {
589                if i > 0 {
590                    out.s(token);
591                }
592                out.s(&res.1.to_string());
593            }
594            out.s(")");
595            (ExprType(vec![(Binding::empty(), t)]), out)
596        }
597
598        match self {
599            Expr::LitArray(t) => {
600                let mut out = Tokens::new();
601                let mut child_types = vec![];
602                out.s("(");
603                for (i, child) in t.iter().enumerate() {
604                    if i > 0 {
605                        out.s(", ");
606                    }
607                    let (child_type, child_tokens) = child.build(ctx, path, scope);
608                    out.s(&child_tokens.to_string());
609                    child_types.extend(child_type.0);
610                }
611                out.s(")");
612                return (ExprType(child_types), out);
613            },
614            Expr::LitNull(t) => {
615                let mut out = Tokens::new();
616                out.s("null");
617                return (ExprType(vec![(Binding::empty(), Type {
618                    type_: t.clone(),
619                    opt: true,
620                    array: false,
621                })]), out);
622            },
623            Expr::LitBool(x) => {
624                let mut out = Tokens::new();
625                out.s(if *x {
626                    "true"
627                } else {
628                    "false"
629                });
630                return empty_type!(out, SimpleSimpleType::Bool);
631            },
632            Expr::LitI32(x) => {
633                let mut out = Tokens::new();
634                out.s(&x.to_string());
635                return empty_type!(out, SimpleSimpleType::I32);
636            },
637            Expr::LitI64(x) => {
638                let mut out = Tokens::new();
639                out.s(&x.to_string());
640                return empty_type!(out, SimpleSimpleType::I64);
641            },
642            Expr::LitU32(x) => {
643                let mut out = Tokens::new();
644                out.s(&x.to_string());
645                return empty_type!(out, SimpleSimpleType::U32);
646            },
647            Expr::LitF32(x) => {
648                let mut out = Tokens::new();
649                out.s(&x.to_string());
650                return empty_type!(out, SimpleSimpleType::F32);
651            },
652            Expr::LitF64(x) => {
653                let mut out = Tokens::new();
654                out.s(&x.to_string());
655                return empty_type!(out, SimpleSimpleType::F64);
656            },
657            Expr::LitString(x) => {
658                let mut out = Tokens::new();
659                out.s(&format!("'{}'", x.replace("'", "''")));
660                return empty_type!(out, SimpleSimpleType::String);
661            },
662            Expr::LitBytes(x) => {
663                let mut out = Tokens::new();
664                let h = hex::encode(&x);
665                out.s(&format!("x'{}'", h));
666                return empty_type!(out, SimpleSimpleType::Bytes);
667            },
668            #[cfg(feature = "chrono")]
669            Expr::LitUtcTimeSChrono(d) => {
670                let mut out = Tokens::new();
671                let d = d.timestamp();
672                out.s(&format!("{}", d));
673                return empty_type!(out, SimpleSimpleType::UtcTimeSChrono);
674            },
675            #[cfg(feature = "chrono")]
676            Expr::LitUtcTimeMsChrono(d) => {
677                let mut out = Tokens::new();
678                let d = d.to_rfc3339();
679                out.s(&format!("'{}'", d));
680                return empty_type!(out, SimpleSimpleType::UtcTimeMsChrono);
681            },
682            #[cfg(feature = "chrono")]
683            Expr::LitFixedOffsetTimeMsChrono(d) => {
684                let mut out = Tokens::new();
685                let d = d.to_rfc3339();
686                out.s(&format!("'{}'", d));
687                return empty_type!(out, SimpleSimpleType::FixedOffsetTimeMsChrono);
688            },
689            #[cfg(feature = "jiff")]
690            Expr::LitUtcTimeSJiff(d) => {
691                let mut out = Tokens::new();
692                out.s(&format!("{}", d.as_second()));
693                return empty_type!(out, SimpleSimpleType::UtcTimeSJiff);
694            },
695            #[cfg(feature = "jiff")]
696            Expr::LitUtcTimeMsJiff(d) => {
697                let mut out = Tokens::new();
698                out.s(&format!("'{}'", d.to_string()));
699                return empty_type!(out, SimpleSimpleType::UtcTimeMsJiff);
700            },
701            Expr::Param { name: x, type_: t } => {
702                let path = path.push_back(format!("Param ({})", x));
703                let mut out = Tokens::new();
704                let mut errs = vec![];
705                let i = match ctx.rust_arg_lookup.entry(x.clone()) {
706                    std::collections::hash_map::Entry::Occupied(e) => {
707                        let (i, prev_t) = e.get();
708                        if t != prev_t {
709                            errs.push(
710                                format!("Parameter {} specified with multiple types: {:?}, {:?}", x, t, prev_t),
711                            );
712                        }
713                        *i
714                    },
715                    std::collections::hash_map::Entry::Vacant(e) => {
716                        let i = ctx.query_args.len();
717                        e.insert((i, t.clone()));
718                        let rust_types = to_rust_types(&t.type_.type_);
719                        let custom_trait_ident = rust_types.custom_trait;
720                        let rust_type = rust_types.arg_type;
721                        let ident = format_ident!("{}", sanitize_ident(x).1);
722                        let (mut rust_type, mut rust_forward) = if let Some(custom) = &t.type_.custom {
723                            let custom_ident = match syn::parse_str::<Path>(custom.as_str()) {
724                                Ok(p) => p,
725                                Err(e) => {
726                                    ctx.errs.err(&path, format!("Couldn't parse custom type {}: {:?}", custom, e));
727                                    return (ExprType(vec![]), Tokens::new());
728                                },
729                            }.to_token_stream();
730                            let forward =
731                                quote!(< #custom_ident as #custom_trait_ident < #custom_ident >>:: to_sql(& #ident));
732                            (quote!(& #custom_ident), forward)
733                        } else {
734                            (rust_type, quote!(#ident))
735                        };
736                        rust_forward = match t.type_.type_ {
737                            SimpleSimpleType::U32 => rust_forward,
738                            SimpleSimpleType::I32 => rust_forward,
739                            SimpleSimpleType::I64 => rust_forward,
740                            SimpleSimpleType::F32 => rust_forward,
741                            SimpleSimpleType::F64 => rust_forward,
742                            SimpleSimpleType::Bool => rust_forward,
743                            SimpleSimpleType::String => rust_forward,
744                            SimpleSimpleType::Bytes => rust_forward,
745                            #[cfg(feature = "chrono")]
746                            SimpleSimpleType::UtcTimeSChrono => quote!(#rust_forward.timestamp()),
747                            #[cfg(feature = "chrono")]
748                            SimpleSimpleType::UtcTimeMsChrono => quote!(#rust_forward.to_rfc3339()),
749                            #[cfg(feature = "chrono")]
750                            SimpleSimpleType::FixedOffsetTimeMsChrono => quote!(#rust_forward.to_rfc3339()),
751                            #[cfg(feature = "jiff")]
752                            SimpleSimpleType::UtcTimeSJiff => quote!(#rust_forward.as_second()),
753                            #[cfg(feature = "jiff")]
754                            SimpleSimpleType::UtcTimeMsJiff => quote!(#rust_forward.to_string()),
755                        };
756                        if t.array {
757                            rust_type = quote!(Vec < #rust_type >);
758                            rust_forward =
759                                quote!(
760                                    std:: rc:: Rc:: new(
761                                        #ident.into_iter(
762                                        ).map(
763                                            | #ident | rusqlite:: types:: Value:: from(#rust_forward)
764                                        ).collect::< Vec < _ >>()
765                                    )
766                                );
767                        }
768                        if t.opt {
769                            rust_type = quote!(Option < #rust_type >);
770                            rust_forward = quote!(#ident.map(| #ident | #rust_forward));
771                        }
772                        ctx.rust_args.push(quote!(#ident: #rust_type));
773                        ctx.query_args.push(quote!(#rust_forward));
774                        i
775                    },
776                };
777                for e in errs {
778                    ctx.errs.err(&path, e);
779                }
780                if t.array {
781                    out.s(&format!("rarray(${})", i + 1));
782                } else {
783                    out.s(&format!("${}", i + 1));
784                }
785                return (ExprType(vec![(Binding::local(x.clone()), t.clone())]), out);
786            },
787            Expr::Binding(name) => {
788                let t = match scope.get(&name) {
789                    Some(t) => t.clone(),
790                    None => {
791                        ctx
792                            .errs
793                            .err(
794                                path,
795                                format!(
796                                    "Expression references {} but this field isn't available here (available fields: {:?})",
797                                    name,
798                                    scope.iter().map(|e| e.0.to_string()).collect::<Vec<String>>()
799                                ),
800                            );
801                        return (ExprType(vec![]), Tokens::new());
802                    },
803                };
804                let mut out = Tokens::new();
805                if name.table_id != "" {
806                    out.id(&name.table_id).s(".");
807                }
808                out.id(&name.id);
809                return (ExprType(vec![(name.clone(), t.clone())]), out);
810            },
811            Expr::BinOp { left, op, right } => {
812                return do_bin_op(
813                    ctx,
814                    &path.push_back(format!("Bin op {:?}", op)),
815                    scope,
816                    op,
817                    &vec![left.as_ref().clone(), right.as_ref().clone()],
818                );
819            },
820            Expr::BinOpChain { op, exprs } => {
821                return do_bin_op(ctx, &path.push_back(format!("Chain bin op {:?}", op)), scope, op, exprs);
822            },
823            Expr::PrefixOp { op, right } => {
824                let path = path.push_back(format!("Prefix op {:?}", op));
825                let mut out = Tokens::new();
826                let res = right.build(ctx, &path, scope);
827                let (op_text, op_type) = match op {
828                    PrefixOp::Not => {
829                        check_bool(ctx, &path, &res.0);
830                        ("not", SimpleSimpleType::Bool)
831                    },
832                };
833                out.s(op_text).s(&res.1.to_string());
834                return empty_type!(out, op_type);
835            },
836            Expr::Call { func, args, compute_type } => {
837                let mut types = vec![];
838                let mut out = Tokens::new();
839                out.s(func);
840                out.s("(");
841                for (i, arg) in args.iter().enumerate() {
842                    if i > 0 {
843                        out.s(",");
844                    }
845                    let (arg_type, tokens) =
846                        arg.build(ctx, &path.push_back(format!("Call [{}] arg {}", func, i)), scope);
847                    types.push(arg_type);
848                    out.s(&tokens.to_string());
849                }
850                out.s(")");
851                let type_ = match (compute_type.0)(ctx, &path, types) {
852                    Some(t) => t,
853                    None => {
854                        return (ExprType(vec![]), Tokens::new());
855                    },
856                };
857                return (ExprType(vec![(Binding::empty(), type_)]), out);
858            },
859            Expr::Window { expr, partition_by, order_by } => {
860                let mut out = Tokens::new();
861                let expr = expr.build(ctx, &path, &scope);
862                out.s(&expr.1.to_string());
863                out.s("over");
864                out.s("(");
865                if !partition_by.is_empty() {
866                    out.s("partition by");
867                    for (i, e) in partition_by.iter().enumerate() {
868                        let path = path.push_back(format!("Partition by {}", i));
869                        if i > 0 {
870                            out.s(",");
871                        }
872                        let (_, p) = e.build(ctx, &path, &scope);
873                        out.s(&p.to_string());
874                    }
875                }
876                if !order_by.is_empty() {
877                    out.s("order by");
878                    for (i, o) in order_by.iter().enumerate() {
879                        let path = path.push_back(format!("Order by clause {}", i));
880                        if i > 0 {
881                            out.s(",");
882                        }
883                        let (_, o_tokens) = o.0.build(ctx, &path, &scope);
884                        out.s(&o_tokens.to_string());
885                        out.s(match o.1 {
886                            Order::Asc => "asc",
887                            Order::Desc => "desc",
888                        });
889                    }
890                }
891                out.s(")");
892                return (expr.0, out);
893            },
894            Expr::Select { body, body_junctions } => {
895                let path = path.push_back(format!("Subselect"));
896                let mut out = Tokens::new();
897                let base = body.build(ctx, scope, &path, QueryResCount::Many);
898                out.s(&base.1.to_string());
899                out.s(&build_select_junction(ctx, &path, &base.0, &body_junctions).to_string());
900                return (base.0, out);
901            },
902            Expr::Exists { not, body, body_junctions } => {
903                let path = path.push_back(format!("(Not)Exists"));
904                let mut out = Tokens::new();
905                if *not {
906                    out.s("not");
907                }
908                out.s("exists");
909                out.s("(");
910                let base = body.build(ctx, scope, &path, QueryResCount::Many);
911                out.s(&base.1.to_string());
912                out.s(&build_select_junction(ctx, &path, &base.0, &body_junctions).to_string());
913                out.s(")");
914                return (ExprType(vec![(Binding::empty(), Type {
915                    type_: SimpleType {
916                        type_: SimpleSimpleType::Bool,
917                        custom: None,
918                    },
919                    opt: false,
920                    array: false,
921                })]), out);
922            },
923            Expr::Cast(e, t) => {
924                let path = path.push_back(format!("Cast"));
925                let out = e.build(ctx, &path, scope);
926                let got_t = match out.0.assert_scalar(&mut ctx.errs, &path) {
927                    Some(t) => t,
928                    None => {
929                        return (ExprType(vec![]), Tokens::new());
930                    },
931                };
932                check_general_same_type(ctx, &path, t, &got_t.1);
933                return (ExprType(vec![(got_t.0, t.clone())]), out.1);
934            },
935        };
936    }
937}
938
939/// Datetimes with fixed offsets must be converted to utc before comparison.
940///
941/// The Tz operators are for working with datetimes with fied offsets where you
942/// _want_ to not consider datetimes referring to the same instant but with
943/// different timezones equal (that is, to be equal both the time and timezone must
944/// match). I think this is probably a rare use case.
945#[derive(Clone, Debug)]
946pub enum BinOp {
947    Plus,
948    Minus,
949    Multiply,
950    Divide,
951    And,
952    Or,
953    Equals,
954    NotEquals,
955    Is,
956    IsNot,
957    TzEquals,
958    TzNotEquals,
959    TzIs,
960    TzIsNot,
961    LessThan,
962    LessThanEqualTo,
963    GreaterThan,
964    GreaterThanEqualTo,
965    Like,
966    In,
967    NotIn,
968}
969
970#[derive(Clone, Debug)]
971pub enum PrefixOp {
972    Not,
973}