toasty_core/stmt/
expr_project.rs

1use crate::stmt::ExprArg;
2
3use super::{Expr, Projection};
4
5/// Projects a field or element from a base expression.
6///
7/// A [projection] extracts a nested value from a record, tuple, or other
8/// composite type using a path of field indices.
9///
10/// # Examples
11///
12/// ```text
13/// project(record, [0])     // extracts the first field
14/// project(record, [1, 2])  // extracts field 1, then field 2
15/// ```
16///
17/// [projection]: https://en.wikipedia.org/wiki/Projection_(relational_algebra)
18#[derive(Debug, Clone, PartialEq)]
19pub struct ExprProject {
20    /// The expression to project from.
21    pub base: Box<Expr>,
22
23    /// The path specifying which field(s) to extract.
24    pub projection: Projection,
25}
26
27impl Expr {
28    /// Creates a projection expression that extracts a field from `base`
29    /// using the given projection path.
30    pub fn project(base: impl Into<Self>, projection: impl Into<Projection>) -> Self {
31        ExprProject {
32            base: Box::new(base.into()),
33            projection: projection.into(),
34        }
35        .into()
36    }
37
38    /// Shorthand for `Expr::project(Expr::arg(expr_arg), projection)`.
39    pub fn arg_project(expr_arg: impl Into<ExprArg>, projection: impl Into<Projection>) -> Self {
40        Self::project(Self::arg(expr_arg), projection)
41    }
42
43    /// Returns `true` if this expression is a projection.
44    pub fn is_project(&self) -> bool {
45        matches!(self, Self::Project(..))
46    }
47
48    /// Returns a reference to the inner [`ExprProject`] if this is a
49    /// projection, or `None` otherwise.
50    pub fn as_project(&self) -> Option<&ExprProject> {
51        match self {
52            Self::Project(expr_project) => Some(expr_project),
53            _ => None,
54        }
55    }
56
57    /// Returns a reference to the inner [`ExprProject`].
58    ///
59    /// # Panics
60    ///
61    /// Panics if `self` is not `Expr::Project`.
62    #[track_caller]
63    pub fn as_project_unwrap(&self) -> &ExprProject {
64        self.as_project()
65            .unwrap_or_else(|| panic!("expected Expr::Project; actual={self:#?}"))
66    }
67}
68
69impl ExprProject {}
70
71impl From<ExprProject> for Expr {
72    fn from(value: ExprProject) -> Self {
73        Self::Project(value)
74    }
75}