Skip to main content

toasty_core/stmt/
expr.rs

1use crate::stmt::{ExprExists, ExprSet, Input};
2
3use super::{
4    Entry, EntryMut, EntryPath, ExprAllOp, ExprAnd, ExprAny, ExprAnyOp, ExprArg, ExprBetween,
5    ExprBinaryOp, ExprCast, ExprError, ExprFunc, ExprInList, ExprInSubquery, ExprIncoming,
6    ExprIntersects, ExprIsNull, ExprIsSuperset, ExprIsVariant, ExprLength, ExprLet, ExprLike,
7    ExprList, ExprMap, ExprMatch, ExprNot, ExprOr, ExprProject, ExprRecord, ExprStartsWith,
8    ExprStmt, ExprVariant, Node, Projection, Resolve, Substitute, Type, Value, Visit, VisitMut,
9    expr_reference::ExprReference,
10};
11use std::fmt;
12
13/// An expression node in Toasty's query AST.
14///
15/// `Expr` is the central type in the statement intermediate representation. Every
16/// filter, projection, value, and computed result in a Toasty query is
17/// represented as an `Expr` tree. The query engine compiles these trees through
18/// several phases (simplify, lower, plan, execute) before they reach a database
19/// driver.
20///
21/// # Examples
22///
23/// ```ignore
24/// use toasty_core::stmt::{Expr, Value};
25///
26/// // Constant value expressions
27/// let t = Expr::TRUE;
28/// assert!(t.is_true());
29///
30/// let n = Expr::null();
31/// assert!(n.is_value_null());
32///
33/// // From conversions
34/// let i: Expr = 42i64.into();
35/// assert!(i.is_value());
36/// ```
37#[derive(Clone, PartialEq)]
38pub enum Expr {
39    /// `lhs <op> ALL(rhs)` predicate against an array-valued operand. See [`ExprAllOp`].
40    AllOp(ExprAllOp),
41
42    /// Logical AND of multiple expressions. See [`ExprAnd`].
43    And(ExprAnd),
44
45    /// Returns `true` if any item in a collection is truthy. See [`ExprAny`].
46    Any(ExprAny),
47
48    /// `lhs <op> ANY(rhs)` predicate against an array-valued operand. See [`ExprAnyOp`].
49    AnyOp(ExprAnyOp),
50
51    /// `expr BETWEEN low AND high` inclusive range test. See [`ExprBetween`].
52    Between(ExprBetween),
53
54    /// Positional argument placeholder. See [`ExprArg`].
55    Arg(ExprArg),
56
57    /// Binary comparison or arithmetic operation. See [`ExprBinaryOp`].
58    BinaryOp(ExprBinaryOp),
59
60    /// Type cast. See [`ExprCast`].
61    Cast(ExprCast),
62
63    /// Instructs the database to use its default value for a column. Useful for
64    /// auto-increment fields and other columns with server-side defaults.
65    Default,
66
67    /// An error expression that fails evaluation with a message. See [`ExprError`].
68    Error(ExprError),
69
70    /// `[NOT] EXISTS(SELECT ...)` check. See [`ExprExists`].
71    Exists(ExprExists),
72
73    /// Aggregate or scalar function call. See [`ExprFunc`].
74    Func(ExprFunc),
75
76    /// An **unresolved** reference to a name (e.g. a column name in a DDL
77    /// context).
78    ///
79    /// Unlike [`Expr::Reference`] / [`ExprReference`], which hold **resolved**
80    /// index-based references into the schema, `Ident` carries only the raw
81    /// name string. It is used in contexts where schema resolution is not
82    /// applicable, such as CHECK constraints in CREATE TABLE statements.
83    Ident(String),
84
85    /// `expr IN (list)` membership test. See [`ExprInList`].
86    InList(ExprInList),
87
88    /// `expr IN (SELECT ...)` membership test. See [`ExprInSubquery`].
89    InSubquery(ExprInSubquery),
90
91    /// The row proposed by an upsert's create branch. See [`ExprIncoming`].
92    Incoming(ExprIncoming),
93
94    /// Boolean: two array operands share at least one element
95    /// (PostgreSQL `&&`). See [`ExprIntersects`].
96    Intersects(ExprIntersects),
97
98    /// `IS [NOT] NULL` check. Separate from binary operators because of
99    /// three-valued logic semantics in SQL. See [`ExprIsNull`].
100    IsNull(ExprIsNull),
101
102    /// Boolean: an array operand contains every element of another
103    /// (PostgreSQL `@>`). See [`ExprIsSuperset`].
104    IsSuperset(ExprIsSuperset),
105
106    /// Tests whether a value is a specific enum variant. See [`ExprIsVariant`].
107    IsVariant(ExprIsVariant),
108
109    /// Integer: the cardinality of an array (PostgreSQL `cardinality(expr)`).
110    /// See [`ExprLength`].
111    Length(ExprLength),
112
113    /// Scoped binding expression (transient -- inlined before planning).
114    /// See [`ExprLet`].
115    Let(ExprLet),
116
117    /// SQL `LIKE` pattern match: `expr LIKE pattern`. See [`ExprLike`].
118    Like(ExprLike),
119
120    /// Applies a transformation to each item in a collection. See [`ExprMap`].
121    Map(ExprMap),
122
123    /// Pattern-match dispatching on a subject. See [`ExprMatch`].
124    Match(ExprMatch),
125
126    /// Boolean negation. See [`ExprNot`].
127    Not(ExprNot),
128
129    /// Logical OR of multiple expressions. See [`ExprOr`].
130    Or(ExprOr),
131
132    /// Field projection from a composite value. See [`ExprProject`].
133    Project(ExprProject),
134
135    /// Fixed-size heterogeneous tuple of expressions. See [`ExprRecord`].
136    Record(ExprRecord),
137
138    // TODO: delete this
139    /// Reference to a field, column, or model in the current or an outer query
140    /// scope. See [`ExprReference`].
141    Reference(ExprReference),
142
143    /// Ordered, homogeneous collection of expressions. See [`ExprList`].
144    List(ExprList),
145
146    /// String prefix match: `starts_with(expr, prefix)`. See [`ExprStartsWith`].
147    StartsWith(ExprStartsWith),
148
149    /// Embedded sub-statement (e.g., a subquery). See [`ExprStmt`].
150    Stmt(ExprStmt),
151
152    /// Constant value rendered as a bind parameter.  The default for
153    /// user-supplied leaves; `extract_params` replaces this with
154    /// `Expr::Arg(n)`.
155    Value(Value),
156
157    /// Constant value rendered inline as a SQL literal instead of a bind
158    /// parameter. Parameter extraction skips it, so the value is part of the
159    /// SQL text: a cached statement carries it for every execution rather
160    /// than taking it per call.
161    ///
162    /// Use it for values the statement itself fixes. `.first()` emits its
163    /// `LIMIT 1` this way. Caller-supplied values use [`Expr::Value`].
164    Static(Value),
165
166    /// Selects a variant of an embedded enum value. See [`ExprVariant`].
167    Variant(ExprVariant),
168}
169
170impl Expr {
171    /// The boolean `true` constant expression.
172    pub const TRUE: Expr = Expr::Value(Value::Bool(true));
173
174    /// The boolean `false` constant expression.
175    pub const FALSE: Expr = Expr::Value(Value::Bool(false));
176
177    /// Alias for [`Expr::Default`] as a constant.
178    pub const DEFAULT: Expr = Expr::Default;
179
180    /// Creates a null value expression.
181    pub fn null() -> Self {
182        Self::Value(Value::Null)
183    }
184
185    /// Is a value that evaluates to null
186    pub fn is_value_null(&self) -> bool {
187        matches!(self, Self::Value(Value::Null))
188    }
189
190    /// Returns true if the expression is the `true` boolean expression
191    pub fn is_true(&self) -> bool {
192        matches!(self, Self::Value(Value::Bool(true)))
193    }
194
195    /// Returns `true` if the expression is the `false` boolean expression
196    pub fn is_false(&self) -> bool {
197        matches!(self, Self::Value(Value::Bool(false)))
198    }
199
200    /// Returns `true` if the expression can never evaluate to `true`.
201    ///
202    /// In SQL's three-valued logic, both `false` and `null` are unsatisfiable:
203    /// a filter producing either value will never match any rows.
204    pub fn is_unsatisfiable(&self) -> bool {
205        self.is_false() || self.is_value_null()
206    }
207
208    /// Returns `true` if the expression is the default expression
209    pub fn is_default(&self) -> bool {
210        matches!(self, Self::Default)
211    }
212
213    /// Returns true if the expression is a constant value.
214    pub fn is_value(&self) -> bool {
215        matches!(self, Self::Value(..))
216    }
217
218    /// Returns `true` if the expression is a sub-statement.
219    pub fn is_stmt(&self) -> bool {
220        matches!(self, Self::Stmt(..))
221    }
222
223    /// Returns `true` if this expression can evaluate to a value compatible
224    /// with `ty`.
225    ///
226    /// Mirrors [`Value::is_a`]: a value expression is checked directly, record
227    /// and list expressions are checked structurally, and expressions with a
228    /// statically known result type (boolean predicates, `COUNT`, ...) check
229    /// that result type against `ty`.
230    ///
231    /// # Panics
232    ///
233    /// Panics with `todo!` on expression variants whose result type cannot be
234    /// determined without evaluation context (arguments, references, casts,
235    /// ...). Support is added as callers need it.
236    pub fn is_a(&self, resolve: &impl Resolve, ty: &Type) -> bool {
237        if let Type::Union(types) = ty {
238            return types.iter().any(|t| self.is_a(resolve, t));
239        }
240        match self {
241            Self::Value(value) => value.is_a(resolve, ty),
242            Self::Record(expr_record) => match ty {
243                Type::Record(field_tys) if expr_record.fields.len() == field_tys.len() => {
244                    expr_record
245                        .fields
246                        .iter()
247                        .zip(field_tys)
248                        .all(|(expr, ty)| expr.is_a(resolve, ty))
249                }
250                // A record expression can evaluate to a document value (a
251                // `#[document]` embed): check each field against the embedded
252                // model's layout, as `Value::is_a` does. Unresolvable in a
253                // schema-free context, in which case there is no layout to
254                // check against.
255                Type::Model(id) => match resolve.model(*id) {
256                    Some(model) => {
257                        let fields = model.fields();
258                        expr_record.fields.len() == fields.len()
259                            && expr_record
260                                .fields
261                                .iter()
262                                .zip(fields)
263                                .all(|(expr, field)| expr.is_a(resolve, field.expr_ty()))
264                    }
265                    None => true,
266                },
267                _ => false,
268            },
269            Self::List(expr_list) => match ty {
270                Type::List(item_ty) => expr_list
271                    .items
272                    .iter()
273                    .all(|item| item.is_a(resolve, item_ty)),
274                _ => false,
275            },
276            // Expressions that always evaluate to a boolean.
277            Self::And(_)
278            | Self::Or(_)
279            | Self::Not(_)
280            | Self::Any(_)
281            | Self::AnyOp(_)
282            | Self::AllOp(_)
283            | Self::Between(_)
284            | Self::Exists(_)
285            | Self::InList(_)
286            | Self::InSubquery(_)
287            | Self::Intersects(_)
288            | Self::IsNull(_)
289            | Self::IsSuperset(_)
290            | Self::IsVariant(_)
291            | Self::Like(_)
292            | Self::StartsWith(_) => ty.is_bool(),
293            Self::BinaryOp(e) if !e.op.is_arithmetic() => ty.is_bool(),
294            Self::Func(ExprFunc::Count(_)) => ty.is_u64(),
295            Self::Func(ExprFunc::LastInsertId(_)) => ty.is_i64(),
296            // A match can produce the value of any of its arms.
297            Self::Match(expr_match) => {
298                expr_match.arms.iter().any(|arm| arm.expr.is_a(resolve, ty))
299                    || expr_match.else_expr.is_a(resolve, ty)
300            }
301            _ => todo!("Expr::is_a: expr={self:#?}; ty={ty:#?}"),
302        }
303    }
304
305    /// Returns true if the expression is a binary operation
306    pub fn is_binary_op(&self) -> bool {
307        matches!(self, Self::BinaryOp(..))
308    }
309
310    /// Returns `true` if the expression is an argument placeholder.
311    pub fn is_arg(&self) -> bool {
312        matches!(self, Self::Arg(_))
313    }
314
315    /// Returns true if the expression is always non-nullable.
316    ///
317    /// This method is conservative and only returns true for expressions we can
318    /// prove are non-nullable.
319    pub fn is_always_non_nullable(&self) -> bool {
320        match self {
321            // A constant value is non-nullable if it's not null.
322            Self::Value(value) => !value.is_null(),
323            // Boolean logic expressions always evaluate to true or false.
324            Self::And(_) | Self::Or(_) | Self::Not(_) => true,
325            // ANY returns true if any item matches, always boolean.
326            Self::Any(_) => true,
327            // ANY/ALL array predicates always evaluate to true or false.
328            Self::AnyOp(_) | Self::AllOp(_) => true,
329            // BETWEEN always evaluates to true or false.
330            Self::Between(_) => true,
331            // Comparisons always evaluate to true or false.
332            Self::BinaryOp(_) => true,
333            // IS NULL checks always evaluate to true or false.
334            Self::IsNull(_) => true,
335            // Variant checks always evaluate to true or false.
336            Self::IsVariant(_) => true,
337            // EXISTS checks always evaluate to true or false.
338            Self::Exists(_) => true,
339            // IN expressions always evaluate to true or false.
340            Self::InList(_) | Self::InSubquery(_) => true,
341            // Array predicates always evaluate to true or false.
342            Self::IsSuperset(_) | Self::Intersects(_) => true,
343            // Array length is an integer — non-null when the array is non-null.
344            Self::Length(_) => true,
345            // For other expressions, we cannot prove non-nullability.
346            _ => false,
347        }
348    }
349
350    /// Consumes the expression and returns the inner [`Value`].
351    ///
352    /// # Panics
353    ///
354    /// Panics (via `todo!()`) if `self` is not an `Expr::Value`.
355    pub fn into_value(self) -> Value {
356        match self {
357            Self::Value(value) => value,
358            _ => todo!(),
359        }
360    }
361
362    /// Consumes the expression and returns the inner [`ExprStmt`].
363    ///
364    /// # Panics
365    ///
366    /// Panics (via `todo!()`) if `self` is not an `Expr::Stmt`.
367    pub fn into_stmt(self) -> ExprStmt {
368        match self {
369            Self::Stmt(stmt) => stmt,
370            _ => todo!(),
371        }
372    }
373
374    /// Returns `true` if the expression is stable
375    ///
376    /// An expression is stable if it yields the same value each time it is evaluated
377    pub fn is_stable(&self) -> bool {
378        match self {
379            // Always stable - constant values
380            Self::Value(_) | Self::Static(_) => true,
381
382            // Unresolved identifiers refer to external state (e.g. a column)
383            Self::Ident(_) => false,
384
385            // Never stable - generates new values each evaluation
386            Self::Default => false,
387
388            // Error expressions are stable (they always produce the same error)
389            Self::Error(_) => true,
390
391            // Stable if all children are stable
392            Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_stable()),
393            Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_stable()),
394            Self::Cast(expr_cast) => expr_cast.expr.is_stable(),
395            Self::StartsWith(e) => e.expr.is_stable() && e.prefix.is_stable(),
396            Self::Like(e) => e.expr.is_stable() && e.pattern.is_stable(),
397            Self::Between(expr_between) => {
398                expr_between.expr.is_stable()
399                    && expr_between.low.is_stable()
400                    && expr_between.high.is_stable()
401            }
402            Self::BinaryOp(expr_binary) => {
403                expr_binary.lhs.is_stable() && expr_binary.rhs.is_stable()
404            }
405            Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_stable()),
406            Self::Any(expr_any) => expr_any.expr.is_stable(),
407            Self::AnyOp(e) => e.lhs.is_stable() && e.rhs.is_stable(),
408            Self::AllOp(e) => e.lhs.is_stable() && e.rhs.is_stable(),
409            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_stable()),
410            Self::IsNull(expr_is_null) => expr_is_null.expr.is_stable(),
411            Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_stable(),
412            Self::Variant(expr_variant) => expr_variant.base.is_stable(),
413            Self::Not(expr_not) => expr_not.expr.is_stable(),
414            Self::InList(expr_in_list) => {
415                expr_in_list.expr.is_stable() && expr_in_list.list.is_stable()
416            }
417            Self::Project(expr_project) => expr_project.base.is_stable(),
418            Self::Let(expr_let) => {
419                expr_let.bindings.iter().all(|b| b.is_stable()) && expr_let.body.is_stable()
420            }
421            Self::Map(expr_map) => expr_map.base.is_stable() && expr_map.map.is_stable(),
422            Self::Match(expr_match) => {
423                expr_match.subject.is_stable()
424                    && expr_match.arms.iter().all(|arm| arm.expr.is_stable())
425            }
426
427            // References and statements - stable (they reference existing data)
428            Self::Reference(_) | Self::Incoming(_) | Self::Arg(_) => true,
429
430            // Array predicates and length — stable if all operands are stable.
431            Self::IsSuperset(e) => e.lhs.is_stable() && e.rhs.is_stable(),
432            Self::Intersects(e) => e.lhs.is_stable() && e.rhs.is_stable(),
433            Self::Length(e) => e.expr.is_stable(),
434
435            // Subqueries and functions - could be unstable
436            // For now, conservatively mark as unstable
437            Self::Stmt(_) | Self::Func(_) | Self::InSubquery(_) | Self::Exists(_) => false,
438        }
439    }
440
441    /// Returns `true` if `self` and `other` are syntactically identical **and**
442    /// both sides are stable.
443    ///
444    /// This is the soundness-preserving comparison used by simplification
445    /// rules that rewrite on the assumption that two equal sub-expressions
446    /// produce the same value (idempotent, absorption, complement,
447    /// range-to-equality, OR-to-IN, factoring, variant tautology).
448    ///
449    /// Syntactic identity alone is not enough: `LAST_INSERT_ID() =
450    /// LAST_INSERT_ID()` is two independent evaluations and may yield
451    /// different values, so rewriting `a AND a` to `a` would be unsound when
452    /// `a` is non-deterministic. Gating on [`Self::is_stable`] excludes any
453    /// sub-expression whose value may change across evaluations.
454    pub fn is_equivalent_to(&self, other: &Self) -> bool {
455        self == other && self.is_stable()
456    }
457
458    /// Returns `true` if the expression is a constant expression.
459    ///
460    /// A constant expression is one that does not reference any external data.
461    /// This means it contains no `Reference`, `Stmt`, or `Arg` expressions that
462    /// reference external inputs.
463    ///
464    /// `Arg` expressions inside `Map` bodies *with `nesting` less than the current
465    /// map depth* are local bindings (bound to the mapped element), not external
466    /// inputs, and are therefore considered const in that context.
467    pub fn is_const(&self) -> bool {
468        self.is_const_at_depth(0)
469    }
470
471    /// Inner implementation of [`is_const`] that tracks the number of enclosing
472    /// `Map` scopes. An `Arg` with `nesting < map_depth` is a local binding
473    /// introduced by one of those `Map`s and does not count as external input.
474    fn is_const_at_depth(&self, map_depth: usize) -> bool {
475        match self {
476            // Always constant
477            Self::Value(_) | Self::Static(_) => true,
478
479            // Unresolved identifiers reference external data
480            Self::Ident(_) => false,
481
482            // Arg: local if nesting is within map_depth, otherwise external
483            Self::Arg(arg) => arg.nesting < map_depth,
484
485            // Error expressions are constant (no external data)
486            Self::Error(_) => true,
487
488            // Never constant - references external data
489            Self::Reference(_)
490            | Self::Incoming(_)
491            | Self::Stmt(_)
492            | Self::InSubquery(_)
493            | Self::Exists(_)
494            | Self::Default
495            | Self::Func(_) => false,
496
497            // Const if all children are const at the same depth
498            Self::Record(expr_record) => expr_record
499                .iter()
500                .all(|expr| expr.is_const_at_depth(map_depth)),
501            Self::List(expr_list) => expr_list
502                .items
503                .iter()
504                .all(|expr| expr.is_const_at_depth(map_depth)),
505            Self::Cast(expr_cast) => expr_cast.expr.is_const_at_depth(map_depth),
506            Self::StartsWith(e) => {
507                e.expr.is_const_at_depth(map_depth) && e.prefix.is_const_at_depth(map_depth)
508            }
509            Self::Like(e) => {
510                e.expr.is_const_at_depth(map_depth) && e.pattern.is_const_at_depth(map_depth)
511            }
512            Self::Between(expr_between) => {
513                expr_between.expr.is_const_at_depth(map_depth)
514                    && expr_between.low.is_const_at_depth(map_depth)
515                    && expr_between.high.is_const_at_depth(map_depth)
516            }
517            Self::BinaryOp(expr_binary) => {
518                expr_binary.lhs.is_const_at_depth(map_depth)
519                    && expr_binary.rhs.is_const_at_depth(map_depth)
520            }
521            Self::And(expr_and) => expr_and
522                .iter()
523                .all(|expr| expr.is_const_at_depth(map_depth)),
524            Self::Any(expr_any) => expr_any.expr.is_const_at_depth(map_depth),
525            Self::AnyOp(e) => {
526                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
527            }
528            Self::AllOp(e) => {
529                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
530            }
531            Self::Not(expr_not) => expr_not.expr.is_const_at_depth(map_depth),
532            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_const_at_depth(map_depth)),
533            Self::IsNull(expr_is_null) => expr_is_null.expr.is_const_at_depth(map_depth),
534            Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_const_at_depth(map_depth),
535            Self::Variant(expr_variant) => expr_variant.base.is_const_at_depth(map_depth),
536            Self::InList(expr_in_list) => {
537                expr_in_list.expr.is_const_at_depth(map_depth)
538                    && expr_in_list.list.is_const_at_depth(map_depth)
539            }
540            Self::Project(expr_project) => expr_project.base.is_const_at_depth(map_depth),
541
542            // Let: binding is checked at the current depth; the body is checked
543            // at depth+1 so that arg(nesting=0) in the body is treated as local.
544            Self::Let(expr_let) => {
545                expr_let
546                    .bindings
547                    .iter()
548                    .all(|b| b.is_const_at_depth(map_depth))
549                    && expr_let.body.is_const_at_depth(map_depth + 1)
550            }
551            // Map: base is checked at the current depth; the map body is checked
552            // at depth+1 so that arg(nesting=0) in the body is treated as local.
553            Self::Map(expr_map) => {
554                expr_map.base.is_const_at_depth(map_depth)
555                    && expr_map.map.is_const_at_depth(map_depth + 1)
556            }
557            Self::Match(expr_match) => {
558                expr_match.subject.is_const_at_depth(map_depth)
559                    && expr_match
560                        .arms
561                        .iter()
562                        .all(|arm| arm.expr.is_const_at_depth(map_depth))
563            }
564
565            // Array predicates and length: const iff all operands are const.
566            Self::IsSuperset(e) => {
567                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
568            }
569            Self::Intersects(e) => {
570                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
571            }
572            Self::Length(e) => e.expr.is_const_at_depth(map_depth),
573        }
574    }
575
576    /// Returns `true` if the in-memory evaluator supports this expression.
577    ///
578    /// Args are allowed because they can be bound at evaluation time. References
579    /// to external data and operations that require lowering or a database are
580    /// rejected. `Exists` supports only `Values` bodies with evaluable rows.
581    /// Evaluation can still fail for invalid values or missing arguments.
582    pub fn is_eval(&self) -> bool {
583        match self {
584            // Always evaluable
585            Self::Value(_) | Self::Static(_) => true,
586
587            // Unresolved identifiers cannot be evaluated
588            Self::Ident(_) => false,
589
590            // Args are OK for evaluation
591            Self::Arg(_) => true,
592
593            // Error expressions are evaluable (they produce an error)
594            Self::Error(_) => true,
595
596            // Requires external data, lowering, or a database driver.
597            Self::Default
598            | Self::Reference(_)
599            | Self::Incoming(_)
600            | Self::Stmt(_)
601            | Self::InSubquery(_)
602            | Self::StartsWith(_)
603            | Self::Like(_)
604            | Self::Between(_)
605            | Self::IsVariant(_)
606            | Self::Variant(_)
607            | Self::IsSuperset(_)
608            | Self::Intersects(_)
609            | Self::Length(_) => false,
610
611            // Evaluable if all children are evaluable
612            Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_eval()),
613            Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_eval()),
614            Self::Cast(expr_cast) => expr_cast.expr.is_eval(),
615            Self::BinaryOp(expr_binary) => expr_binary.lhs.is_eval() && expr_binary.rhs.is_eval(),
616            Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_eval()),
617            Self::Any(expr_any) => expr_any.expr.is_eval(),
618            Self::AnyOp(e) => e.lhs.is_eval() && e.rhs.is_eval(),
619            Self::AllOp(e) => e.lhs.is_eval() && e.rhs.is_eval(),
620            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_eval()),
621            Self::Not(expr_not) => expr_not.expr.is_eval(),
622            Self::IsNull(expr_is_null) => expr_is_null.expr.is_eval(),
623            Self::InList(expr_in_list) => {
624                expr_in_list.expr.is_eval() && expr_in_list.list.is_eval()
625            }
626            Self::Project(expr_project) => expr_project.base.is_eval(),
627            Self::Let(expr_let) => {
628                expr_let.bindings.iter().all(|b| b.is_eval()) && expr_let.body.is_eval()
629            }
630            Self::Map(expr_map) => expr_map.base.is_eval() && expr_map.map.is_eval(),
631            Self::Match(expr_match) => {
632                expr_match.subject.is_eval()
633                    && expr_match.arms.iter().all(|arm| arm.expr.is_eval())
634                    && expr_match.else_expr.is_eval()
635            }
636            Self::Exists(expr_exists) => match &expr_exists.subquery.body {
637                ExprSet::Values(values) => values.rows.iter().all(Self::is_eval),
638                _ => false,
639            },
640            Self::Func(ExprFunc::JsonExtract(func)) => func.base.is_eval(),
641            Self::Func(_) => false,
642        }
643    }
644
645    /// Returns a clone of this expression with all [`Projection`] nodes
646    /// transformed by `f`.
647    pub fn map_projections(&self, f: impl FnMut(&Projection) -> Projection) -> Self {
648        struct MapProjections<T>(T);
649
650        impl<T: FnMut(&Projection) -> Projection> VisitMut for MapProjections<T> {
651            fn visit_projection_mut(&mut self, i: &mut Projection) {
652                *i = self.0(i);
653            }
654        }
655
656        let mut mapped = self.clone();
657        MapProjections(f).visit_expr_mut(&mut mapped);
658        mapped
659    }
660
661    /// Navigates into a nested record or list expression by `path` and returns
662    /// a read-only [`Entry`] reference.
663    ///
664    /// Returns `None` if the path cannot be followed: the expression is not a
665    /// record or list at the expected depth, or a step indexes past the end of
666    /// a record or list.
667    #[track_caller]
668    pub fn entry(&self, path: impl EntryPath) -> Option<Entry<'_>> {
669        let mut ret = Entry::Expr(self);
670
671        for step in path.step_iter() {
672            ret = match ret {
673                Entry::Expr(Self::Record(expr)) => Entry::Expr(expr.get(step)?),
674                Entry::Expr(Self::List(expr)) => Entry::Expr(expr.items.get(step)?),
675                Entry::Value(Value::Record(record))
676                | Entry::Expr(Self::Value(Value::Record(record))) => {
677                    Entry::Value(record.get(step)?)
678                }
679                Entry::Value(Value::List(items)) | Entry::Expr(Self::Value(Value::List(items))) => {
680                    Entry::Value(items.get(step)?)
681                }
682                _ => return None,
683            }
684        }
685
686        Some(ret)
687    }
688
689    /// Navigates into a nested record or list expression by `path` and returns
690    /// a mutable [`EntryMut`] reference.
691    ///
692    /// # Panics
693    ///
694    /// Panics if the path cannot be followed on the current expression shape.
695    #[track_caller]
696    pub fn entry_mut(&mut self, path: impl EntryPath) -> EntryMut<'_> {
697        let mut ret = EntryMut::Expr(self);
698
699        for step in path.step_iter() {
700            ret = match ret {
701                EntryMut::Expr(Self::Record(expr)) => EntryMut::Expr(&mut expr[step]),
702                EntryMut::Value(Value::Record(record))
703                | EntryMut::Expr(Self::Value(Value::Record(record))) => {
704                    EntryMut::Value(&mut record[step])
705                }
706                _ => todo!("ret={ret:#?}; step={step:#?}"),
707            }
708        }
709
710        ret
711    }
712
713    /// Takes the expression out, leaving `Expr::Value(Value::Null)` in its
714    /// place. Equivalent to `std::mem::replace(self, Expr::null())`.
715    pub fn take(&mut self) -> Self {
716        std::mem::replace(self, Self::Value(Value::Null))
717    }
718
719    /// Replaces every [`ExprArg`] in this expression tree with the
720    /// corresponding value from `input`.
721    pub fn substitute(&mut self, input: impl Input) {
722        Substitute::new(input).visit_expr_mut(self);
723    }
724}
725
726impl Node for Expr {
727    fn visit<V: Visit>(&self, mut visit: V) {
728        visit.visit_expr(self);
729    }
730
731    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
732        visit.visit_expr_mut(self);
733    }
734}
735
736// === Conversions ===
737
738impl From<bool> for Expr {
739    fn from(value: bool) -> Self {
740        Self::Value(Value::from(value))
741    }
742}
743
744impl From<i64> for Expr {
745    fn from(value: i64) -> Self {
746        Self::Value(value.into())
747    }
748}
749
750impl From<&i64> for Expr {
751    fn from(value: &i64) -> Self {
752        Self::Value(value.into())
753    }
754}
755
756impl From<String> for Expr {
757    fn from(value: String) -> Self {
758        Self::Value(value.into())
759    }
760}
761
762impl From<&String> for Expr {
763    fn from(value: &String) -> Self {
764        Self::Value(value.into())
765    }
766}
767
768impl From<&str> for Expr {
769    fn from(value: &str) -> Self {
770        Self::Value(value.into())
771    }
772}
773
774impl From<Value> for Expr {
775    fn from(value: Value) -> Self {
776        Self::Value(value)
777    }
778}
779
780impl<E1, E2> From<(E1, E2)> for Expr
781where
782    E1: Into<Self>,
783    E2: Into<Self>,
784{
785    fn from(value: (E1, E2)) -> Self {
786        Self::Record(value.into())
787    }
788}
789
790impl fmt::Debug for Expr {
791    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
792        match self {
793            Self::AllOp(e) => e.fmt(f),
794            Self::And(e) => e.fmt(f),
795            Self::Any(e) => e.fmt(f),
796            Self::AnyOp(e) => e.fmt(f),
797            Self::Arg(e) => e.fmt(f),
798            Self::Between(e) => e.fmt(f),
799            Self::BinaryOp(e) => e.fmt(f),
800            Self::Cast(e) => e.fmt(f),
801            Self::Default => write!(f, "Default"),
802            Self::Error(e) => e.fmt(f),
803            Self::Exists(e) => e.fmt(f),
804            Self::Func(e) => e.fmt(f),
805            Self::Ident(e) => write!(f, "Ident({e:?})"),
806            Self::InList(e) => e.fmt(f),
807            Self::InSubquery(e) => e.fmt(f),
808            Self::Incoming(e) => write!(f, "Incoming({e:?})"),
809            Self::Intersects(e) => e.fmt(f),
810            Self::IsNull(e) => e.fmt(f),
811            Self::IsSuperset(e) => e.fmt(f),
812            Self::IsVariant(e) => e.fmt(f),
813            Self::Variant(e) => e.fmt(f),
814            Self::Length(e) => e.fmt(f),
815            Self::Let(e) => e.fmt(f),
816            Self::Like(e) => e.fmt(f),
817            Self::Map(e) => e.fmt(f),
818            Self::Match(e) => e.fmt(f),
819            Self::Not(e) => e.fmt(f),
820            Self::Or(e) => e.fmt(f),
821            Self::Project(e) => e.fmt(f),
822            Self::Record(e) => e.fmt(f),
823            Self::Reference(e) => e.fmt(f),
824            Self::List(e) => e.fmt(f),
825            Self::StartsWith(e) => e.fmt(f),
826            Self::Stmt(e) => e.fmt(f),
827            Self::Value(e) => e.fmt(f),
828            Self::Static(e) => write!(f, "Static({e:?})"),
829        }
830    }
831}