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 the integer of a bound or static `I64` literal, or `None` for
219    /// any other expression.
220    pub fn as_i64_literal(&self) -> Option<i64> {
221        match self {
222            Self::Value(Value::I64(n)) | Self::Static(Value::I64(n)) => Some(*n),
223            _ => None,
224        }
225    }
226
227    /// Returns `true` if the expression is a sub-statement.
228    pub fn is_stmt(&self) -> bool {
229        matches!(self, Self::Stmt(..))
230    }
231
232    /// Returns `true` if this expression can evaluate to a value compatible
233    /// with `ty`.
234    ///
235    /// Mirrors [`Value::is_a`]: a value expression is checked directly, record
236    /// and list expressions are checked structurally, and expressions with a
237    /// statically known result type (boolean predicates, `COUNT`, ...) check
238    /// that result type against `ty`.
239    ///
240    /// # Panics
241    ///
242    /// Panics with `todo!` on expression variants whose result type cannot be
243    /// determined without evaluation context (arguments, references, casts,
244    /// ...). Support is added as callers need it.
245    pub fn is_a(&self, resolve: &impl Resolve, ty: &Type) -> bool {
246        if let Type::Union(types) = ty {
247            return types.iter().any(|t| self.is_a(resolve, t));
248        }
249        match self {
250            Self::Value(value) => value.is_a(resolve, ty),
251            Self::Record(expr_record) => match ty {
252                Type::Record(field_tys) if expr_record.fields.len() == field_tys.len() => {
253                    expr_record
254                        .fields
255                        .iter()
256                        .zip(field_tys)
257                        .all(|(expr, ty)| expr.is_a(resolve, ty))
258                }
259                // A record expression can evaluate to a document value (a
260                // `#[document]` embed): check each field against the embedded
261                // model's layout, as `Value::is_a` does. Unresolvable in a
262                // schema-free context, in which case there is no layout to
263                // check against.
264                Type::Model(id) => match resolve.model(*id) {
265                    Some(model) => {
266                        let fields = model.fields();
267                        expr_record.fields.len() == fields.len()
268                            && expr_record
269                                .fields
270                                .iter()
271                                .zip(fields)
272                                .all(|(expr, field)| expr.is_a(resolve, field.expr_ty()))
273                    }
274                    None => true,
275                },
276                _ => false,
277            },
278            Self::List(expr_list) => match ty {
279                Type::List(item_ty) => expr_list
280                    .items
281                    .iter()
282                    .all(|item| item.is_a(resolve, item_ty)),
283                _ => false,
284            },
285            // Expressions that always evaluate to a boolean.
286            Self::And(_)
287            | Self::Or(_)
288            | Self::Not(_)
289            | Self::Any(_)
290            | Self::AnyOp(_)
291            | Self::AllOp(_)
292            | Self::Between(_)
293            | Self::Exists(_)
294            | Self::InList(_)
295            | Self::InSubquery(_)
296            | Self::Intersects(_)
297            | Self::IsNull(_)
298            | Self::IsSuperset(_)
299            | Self::IsVariant(_)
300            | Self::Like(_)
301            | Self::StartsWith(_) => ty.is_bool(),
302            Self::BinaryOp(e) if !e.op.is_arithmetic() => ty.is_bool(),
303            Self::Func(ExprFunc::Count(_)) => ty.is_u64(),
304            Self::Func(ExprFunc::LastInsertId(_)) => ty.is_i64(),
305            // A match can produce the value of any of its arms.
306            Self::Match(expr_match) => {
307                expr_match.arms.iter().any(|arm| arm.expr.is_a(resolve, ty))
308                    || expr_match.else_expr.is_a(resolve, ty)
309            }
310            _ => todo!("Expr::is_a: expr={self:#?}; ty={ty:#?}"),
311        }
312    }
313
314    /// Returns true if the expression is a binary operation
315    pub fn is_binary_op(&self) -> bool {
316        matches!(self, Self::BinaryOp(..))
317    }
318
319    /// Returns `true` if the expression is an argument placeholder.
320    pub fn is_arg(&self) -> bool {
321        matches!(self, Self::Arg(_))
322    }
323
324    /// Returns true if the expression is always non-nullable.
325    ///
326    /// This method is conservative and only returns true for expressions we can
327    /// prove are non-nullable.
328    pub fn is_always_non_nullable(&self) -> bool {
329        match self {
330            // A constant value is non-nullable if it's not null.
331            Self::Value(value) => !value.is_null(),
332            // Boolean logic expressions always evaluate to true or false.
333            Self::And(_) | Self::Or(_) | Self::Not(_) => true,
334            // ANY returns true if any item matches, always boolean.
335            Self::Any(_) => true,
336            // ANY/ALL array predicates always evaluate to true or false.
337            Self::AnyOp(_) | Self::AllOp(_) => true,
338            // BETWEEN always evaluates to true or false.
339            Self::Between(_) => true,
340            // Comparisons always evaluate to true or false.
341            Self::BinaryOp(_) => true,
342            // IS NULL checks always evaluate to true or false.
343            Self::IsNull(_) => true,
344            // Variant checks always evaluate to true or false.
345            Self::IsVariant(_) => true,
346            // EXISTS checks always evaluate to true or false.
347            Self::Exists(_) => true,
348            // IN expressions always evaluate to true or false.
349            Self::InList(_) | Self::InSubquery(_) => true,
350            // Array predicates always evaluate to true or false.
351            Self::IsSuperset(_) | Self::Intersects(_) => true,
352            // Array length is an integer — non-null when the array is non-null.
353            Self::Length(_) => true,
354            // For other expressions, we cannot prove non-nullability.
355            _ => false,
356        }
357    }
358
359    /// Consumes the expression and returns the inner [`Value`].
360    ///
361    /// # Panics
362    ///
363    /// Panics (via `todo!()`) if `self` is not an `Expr::Value`.
364    pub fn into_value(self) -> Value {
365        match self {
366            Self::Value(value) => value,
367            _ => todo!(),
368        }
369    }
370
371    /// Consumes the expression and returns the inner [`ExprStmt`].
372    ///
373    /// # Panics
374    ///
375    /// Panics (via `todo!()`) if `self` is not an `Expr::Stmt`.
376    pub fn into_stmt(self) -> ExprStmt {
377        match self {
378            Self::Stmt(stmt) => stmt,
379            _ => todo!(),
380        }
381    }
382
383    /// Returns `true` if the expression is stable
384    ///
385    /// An expression is stable if it yields the same value each time it is evaluated
386    pub fn is_stable(&self) -> bool {
387        match self {
388            // Always stable - constant values
389            Self::Value(_) | Self::Static(_) => true,
390
391            // Unresolved identifiers refer to external state (e.g. a column)
392            Self::Ident(_) => false,
393
394            // Never stable - generates new values each evaluation
395            Self::Default => false,
396
397            // Error expressions are stable (they always produce the same error)
398            Self::Error(_) => true,
399
400            // Stable if all children are stable
401            Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_stable()),
402            Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_stable()),
403            Self::Cast(expr_cast) => expr_cast.expr.is_stable(),
404            Self::StartsWith(e) => e.expr.is_stable() && e.prefix.is_stable(),
405            Self::Like(e) => e.expr.is_stable() && e.pattern.is_stable(),
406            Self::Between(expr_between) => {
407                expr_between.expr.is_stable()
408                    && expr_between.low.is_stable()
409                    && expr_between.high.is_stable()
410            }
411            Self::BinaryOp(expr_binary) => {
412                expr_binary.lhs.is_stable() && expr_binary.rhs.is_stable()
413            }
414            Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_stable()),
415            Self::Any(expr_any) => expr_any.expr.is_stable(),
416            Self::AnyOp(e) => e.lhs.is_stable() && e.rhs.is_stable(),
417            Self::AllOp(e) => e.lhs.is_stable() && e.rhs.is_stable(),
418            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_stable()),
419            Self::IsNull(expr_is_null) => expr_is_null.expr.is_stable(),
420            Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_stable(),
421            Self::Variant(expr_variant) => expr_variant.base.is_stable(),
422            Self::Not(expr_not) => expr_not.expr.is_stable(),
423            Self::InList(expr_in_list) => {
424                expr_in_list.expr.is_stable() && expr_in_list.list.is_stable()
425            }
426            Self::Project(expr_project) => expr_project.base.is_stable(),
427            Self::Let(expr_let) => {
428                expr_let.bindings.iter().all(|b| b.is_stable()) && expr_let.body.is_stable()
429            }
430            Self::Map(expr_map) => expr_map.base.is_stable() && expr_map.map.is_stable(),
431            Self::Match(expr_match) => {
432                expr_match.subject.is_stable()
433                    && expr_match.arms.iter().all(|arm| arm.expr.is_stable())
434            }
435
436            // References and statements - stable (they reference existing data)
437            Self::Reference(_) | Self::Incoming(_) | Self::Arg(_) => true,
438
439            // Array predicates and length — stable if all operands are stable.
440            Self::IsSuperset(e) => e.lhs.is_stable() && e.rhs.is_stable(),
441            Self::Intersects(e) => e.lhs.is_stable() && e.rhs.is_stable(),
442            Self::Length(e) => e.expr.is_stable(),
443
444            // Subqueries and functions - could be unstable
445            // For now, conservatively mark as unstable
446            Self::Stmt(_) | Self::Func(_) | Self::InSubquery(_) | Self::Exists(_) => false,
447        }
448    }
449
450    /// Returns `true` if `self` and `other` are syntactically identical **and**
451    /// both sides are stable.
452    ///
453    /// This is the soundness-preserving comparison used by simplification
454    /// rules that rewrite on the assumption that two equal sub-expressions
455    /// produce the same value (idempotent, absorption, complement,
456    /// range-to-equality, OR-to-IN, factoring, variant tautology).
457    ///
458    /// Syntactic identity alone is not enough: `LAST_INSERT_ID() =
459    /// LAST_INSERT_ID()` is two independent evaluations and may yield
460    /// different values, so rewriting `a AND a` to `a` would be unsound when
461    /// `a` is non-deterministic. Gating on [`Self::is_stable`] excludes any
462    /// sub-expression whose value may change across evaluations.
463    pub fn is_equivalent_to(&self, other: &Self) -> bool {
464        self == other && self.is_stable()
465    }
466
467    /// Returns `true` if the expression is a constant expression.
468    ///
469    /// A constant expression is one that does not reference any external data.
470    /// This means it contains no `Reference`, `Stmt`, or `Arg` expressions that
471    /// reference external inputs.
472    ///
473    /// `Arg` expressions inside `Map` bodies *with `nesting` less than the current
474    /// map depth* are local bindings (bound to the mapped element), not external
475    /// inputs, and are therefore considered const in that context.
476    pub fn is_const(&self) -> bool {
477        self.is_const_at_depth(0)
478    }
479
480    /// Inner implementation of [`is_const`] that tracks the number of enclosing
481    /// `Map` scopes. An `Arg` with `nesting < map_depth` is a local binding
482    /// introduced by one of those `Map`s and does not count as external input.
483    fn is_const_at_depth(&self, map_depth: usize) -> bool {
484        match self {
485            // Always constant
486            Self::Value(_) | Self::Static(_) => true,
487
488            // Unresolved identifiers reference external data
489            Self::Ident(_) => false,
490
491            // Arg: local if nesting is within map_depth, otherwise external
492            Self::Arg(arg) => arg.nesting < map_depth,
493
494            // Error expressions are constant (no external data)
495            Self::Error(_) => true,
496
497            // Never constant - references external data
498            Self::Reference(_)
499            | Self::Incoming(_)
500            | Self::Stmt(_)
501            | Self::InSubquery(_)
502            | Self::Exists(_)
503            | Self::Default
504            | Self::Func(_) => false,
505
506            // Const if all children are const at the same depth
507            Self::Record(expr_record) => expr_record
508                .iter()
509                .all(|expr| expr.is_const_at_depth(map_depth)),
510            Self::List(expr_list) => expr_list
511                .items
512                .iter()
513                .all(|expr| expr.is_const_at_depth(map_depth)),
514            Self::Cast(expr_cast) => expr_cast.expr.is_const_at_depth(map_depth),
515            Self::StartsWith(e) => {
516                e.expr.is_const_at_depth(map_depth) && e.prefix.is_const_at_depth(map_depth)
517            }
518            Self::Like(e) => {
519                e.expr.is_const_at_depth(map_depth) && e.pattern.is_const_at_depth(map_depth)
520            }
521            Self::Between(expr_between) => {
522                expr_between.expr.is_const_at_depth(map_depth)
523                    && expr_between.low.is_const_at_depth(map_depth)
524                    && expr_between.high.is_const_at_depth(map_depth)
525            }
526            Self::BinaryOp(expr_binary) => {
527                expr_binary.lhs.is_const_at_depth(map_depth)
528                    && expr_binary.rhs.is_const_at_depth(map_depth)
529            }
530            Self::And(expr_and) => expr_and
531                .iter()
532                .all(|expr| expr.is_const_at_depth(map_depth)),
533            Self::Any(expr_any) => expr_any.expr.is_const_at_depth(map_depth),
534            Self::AnyOp(e) => {
535                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
536            }
537            Self::AllOp(e) => {
538                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
539            }
540            Self::Not(expr_not) => expr_not.expr.is_const_at_depth(map_depth),
541            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_const_at_depth(map_depth)),
542            Self::IsNull(expr_is_null) => expr_is_null.expr.is_const_at_depth(map_depth),
543            Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_const_at_depth(map_depth),
544            Self::Variant(expr_variant) => expr_variant.base.is_const_at_depth(map_depth),
545            Self::InList(expr_in_list) => {
546                expr_in_list.expr.is_const_at_depth(map_depth)
547                    && expr_in_list.list.is_const_at_depth(map_depth)
548            }
549            Self::Project(expr_project) => expr_project.base.is_const_at_depth(map_depth),
550
551            // Let: binding is checked at the current depth; the body is checked
552            // at depth+1 so that arg(nesting=0) in the body is treated as local.
553            Self::Let(expr_let) => {
554                expr_let
555                    .bindings
556                    .iter()
557                    .all(|b| b.is_const_at_depth(map_depth))
558                    && expr_let.body.is_const_at_depth(map_depth + 1)
559            }
560            // Map: base is checked at the current depth; the map body is checked
561            // at depth+1 so that arg(nesting=0) in the body is treated as local.
562            Self::Map(expr_map) => {
563                expr_map.base.is_const_at_depth(map_depth)
564                    && expr_map.map.is_const_at_depth(map_depth + 1)
565            }
566            Self::Match(expr_match) => {
567                expr_match.subject.is_const_at_depth(map_depth)
568                    && expr_match
569                        .arms
570                        .iter()
571                        .all(|arm| arm.expr.is_const_at_depth(map_depth))
572            }
573
574            // Array predicates and length: const iff all operands are const.
575            Self::IsSuperset(e) => {
576                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
577            }
578            Self::Intersects(e) => {
579                e.lhs.is_const_at_depth(map_depth) && e.rhs.is_const_at_depth(map_depth)
580            }
581            Self::Length(e) => e.expr.is_const_at_depth(map_depth),
582        }
583    }
584
585    /// Returns `true` if the in-memory evaluator supports this expression.
586    ///
587    /// Args are allowed because they can be bound at evaluation time. References
588    /// to external data and operations that require lowering or a database are
589    /// rejected. `Exists` supports only `Values` bodies with evaluable rows.
590    /// Evaluation can still fail for invalid values or missing arguments.
591    pub fn is_eval(&self) -> bool {
592        match self {
593            // Always evaluable
594            Self::Value(_) | Self::Static(_) => true,
595
596            // Unresolved identifiers cannot be evaluated
597            Self::Ident(_) => false,
598
599            // Args are OK for evaluation
600            Self::Arg(_) => true,
601
602            // Error expressions are evaluable (they produce an error)
603            Self::Error(_) => true,
604
605            // Requires external data, lowering, or a database driver.
606            Self::Default
607            | Self::Reference(_)
608            | Self::Incoming(_)
609            | Self::Stmt(_)
610            | Self::InSubquery(_)
611            | Self::StartsWith(_)
612            | Self::Like(_)
613            | Self::Between(_)
614            | Self::IsVariant(_)
615            | Self::Variant(_)
616            | Self::IsSuperset(_)
617            | Self::Intersects(_)
618            | Self::Length(_) => false,
619
620            // Evaluable if all children are evaluable
621            Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_eval()),
622            Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_eval()),
623            Self::Cast(expr_cast) => expr_cast.expr.is_eval(),
624            Self::BinaryOp(expr_binary) => expr_binary.lhs.is_eval() && expr_binary.rhs.is_eval(),
625            Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_eval()),
626            Self::Any(expr_any) => expr_any.expr.is_eval(),
627            Self::AnyOp(e) => e.lhs.is_eval() && e.rhs.is_eval(),
628            Self::AllOp(e) => e.lhs.is_eval() && e.rhs.is_eval(),
629            Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_eval()),
630            Self::Not(expr_not) => expr_not.expr.is_eval(),
631            Self::IsNull(expr_is_null) => expr_is_null.expr.is_eval(),
632            Self::InList(expr_in_list) => {
633                expr_in_list.expr.is_eval() && expr_in_list.list.is_eval()
634            }
635            Self::Project(expr_project) => expr_project.base.is_eval(),
636            Self::Let(expr_let) => {
637                expr_let.bindings.iter().all(|b| b.is_eval()) && expr_let.body.is_eval()
638            }
639            Self::Map(expr_map) => expr_map.base.is_eval() && expr_map.map.is_eval(),
640            Self::Match(expr_match) => {
641                expr_match.subject.is_eval()
642                    && expr_match.arms.iter().all(|arm| arm.expr.is_eval())
643                    && expr_match.else_expr.is_eval()
644            }
645            Self::Exists(expr_exists) => match &expr_exists.subquery.body {
646                ExprSet::Values(values) => values.rows.iter().all(Self::is_eval),
647                _ => false,
648            },
649            Self::Func(ExprFunc::JsonExtract(func)) => func.base.is_eval(),
650            Self::Func(_) => false,
651        }
652    }
653
654    /// Returns a clone of this expression with all [`Projection`] nodes
655    /// transformed by `f`.
656    pub fn map_projections(&self, f: impl FnMut(&Projection) -> Projection) -> Self {
657        struct MapProjections<T>(T);
658
659        impl<T: FnMut(&Projection) -> Projection> VisitMut for MapProjections<T> {
660            fn visit_projection_mut(&mut self, i: &mut Projection) {
661                *i = self.0(i);
662            }
663        }
664
665        let mut mapped = self.clone();
666        MapProjections(f).visit_expr_mut(&mut mapped);
667        mapped
668    }
669
670    /// Navigates into a nested record or list expression by `path` and returns
671    /// a read-only [`Entry`] reference.
672    ///
673    /// Returns `None` if the path cannot be followed: the expression is not a
674    /// record or list at the expected depth, or a step indexes past the end of
675    /// a record or list.
676    #[track_caller]
677    pub fn entry(&self, path: impl EntryPath) -> Option<Entry<'_>> {
678        let mut ret = Entry::Expr(self);
679
680        for step in path.step_iter() {
681            ret = match ret {
682                Entry::Expr(Self::Record(expr)) => Entry::Expr(expr.get(step)?),
683                Entry::Expr(Self::List(expr)) => Entry::Expr(expr.items.get(step)?),
684                Entry::Value(Value::Record(record))
685                | Entry::Expr(Self::Value(Value::Record(record))) => {
686                    Entry::Value(record.get(step)?)
687                }
688                Entry::Value(Value::List(items)) | Entry::Expr(Self::Value(Value::List(items))) => {
689                    Entry::Value(items.get(step)?)
690                }
691                _ => return None,
692            }
693        }
694
695        Some(ret)
696    }
697
698    /// Navigates into a nested record or list expression by `path` and returns
699    /// a mutable [`EntryMut`] reference.
700    ///
701    /// # Panics
702    ///
703    /// Panics if the path cannot be followed on the current expression shape.
704    #[track_caller]
705    pub fn entry_mut(&mut self, path: impl EntryPath) -> EntryMut<'_> {
706        let mut ret = EntryMut::Expr(self);
707
708        for step in path.step_iter() {
709            ret = match ret {
710                EntryMut::Expr(Self::Record(expr)) => EntryMut::Expr(&mut expr[step]),
711                EntryMut::Value(Value::Record(record))
712                | EntryMut::Expr(Self::Value(Value::Record(record))) => {
713                    EntryMut::Value(&mut record[step])
714                }
715                _ => todo!("ret={ret:#?}; step={step:#?}"),
716            }
717        }
718
719        ret
720    }
721
722    /// Takes the expression out, leaving `Expr::Value(Value::Null)` in its
723    /// place. Equivalent to `std::mem::replace(self, Expr::null())`.
724    pub fn take(&mut self) -> Self {
725        std::mem::replace(self, Self::Value(Value::Null))
726    }
727
728    /// Replaces every [`ExprArg`] in this expression tree with the
729    /// corresponding value from `input`.
730    pub fn substitute(&mut self, input: impl Input) {
731        Substitute::new(input).visit_expr_mut(self);
732    }
733}
734
735impl Node for Expr {
736    fn visit<V: Visit>(&self, mut visit: V) {
737        visit.visit_expr(self);
738    }
739
740    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
741        visit.visit_expr_mut(self);
742    }
743}
744
745// === Conversions ===
746
747impl From<bool> for Expr {
748    fn from(value: bool) -> Self {
749        Self::Value(Value::from(value))
750    }
751}
752
753impl From<i64> for Expr {
754    fn from(value: i64) -> Self {
755        Self::Value(value.into())
756    }
757}
758
759impl From<&i64> for Expr {
760    fn from(value: &i64) -> Self {
761        Self::Value(value.into())
762    }
763}
764
765impl From<String> for Expr {
766    fn from(value: String) -> Self {
767        Self::Value(value.into())
768    }
769}
770
771impl From<&String> for Expr {
772    fn from(value: &String) -> Self {
773        Self::Value(value.into())
774    }
775}
776
777impl From<&str> for Expr {
778    fn from(value: &str) -> Self {
779        Self::Value(value.into())
780    }
781}
782
783impl From<Value> for Expr {
784    fn from(value: Value) -> Self {
785        Self::Value(value)
786    }
787}
788
789impl<E1, E2> From<(E1, E2)> for Expr
790where
791    E1: Into<Self>,
792    E2: Into<Self>,
793{
794    fn from(value: (E1, E2)) -> Self {
795        Self::Record(value.into())
796    }
797}
798
799impl fmt::Debug for Expr {
800    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
801        match self {
802            Self::AllOp(e) => e.fmt(f),
803            Self::And(e) => e.fmt(f),
804            Self::Any(e) => e.fmt(f),
805            Self::AnyOp(e) => e.fmt(f),
806            Self::Arg(e) => e.fmt(f),
807            Self::Between(e) => e.fmt(f),
808            Self::BinaryOp(e) => e.fmt(f),
809            Self::Cast(e) => e.fmt(f),
810            Self::Default => write!(f, "Default"),
811            Self::Error(e) => e.fmt(f),
812            Self::Exists(e) => e.fmt(f),
813            Self::Func(e) => e.fmt(f),
814            Self::Ident(e) => write!(f, "Ident({e:?})"),
815            Self::InList(e) => e.fmt(f),
816            Self::InSubquery(e) => e.fmt(f),
817            Self::Incoming(e) => write!(f, "Incoming({e:?})"),
818            Self::Intersects(e) => e.fmt(f),
819            Self::IsNull(e) => e.fmt(f),
820            Self::IsSuperset(e) => e.fmt(f),
821            Self::IsVariant(e) => e.fmt(f),
822            Self::Variant(e) => e.fmt(f),
823            Self::Length(e) => e.fmt(f),
824            Self::Let(e) => e.fmt(f),
825            Self::Like(e) => e.fmt(f),
826            Self::Map(e) => e.fmt(f),
827            Self::Match(e) => e.fmt(f),
828            Self::Not(e) => e.fmt(f),
829            Self::Or(e) => e.fmt(f),
830            Self::Project(e) => e.fmt(f),
831            Self::Record(e) => e.fmt(f),
832            Self::Reference(e) => e.fmt(f),
833            Self::List(e) => e.fmt(f),
834            Self::StartsWith(e) => e.fmt(f),
835            Self::Stmt(e) => e.fmt(f),
836            Self::Value(e) => e.fmt(f),
837            Self::Static(e) => write!(f, "Static({e:?})"),
838        }
839    }
840}