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