Skip to main content

vantage_cmd/
expr_data_source.rs

1//! `DataSource` + `ExprDataSource` impls for `Cmd`.
2//!
3//! Same shape as `vantage-aws`: `execute` resolves the single deferred
4//! parameter that `column_table_values_expr` produces (the projection
5//! used by relation traversal). Nothing else needs a real implementation.
6
7use std::future::Future;
8use std::pin::Pin;
9
10use ciborium::Value as CborValue;
11use vantage_core::Result;
12use vantage_expressions::{
13    Expression,
14    traits::datasource::{DataSource, ExprDataSource},
15    traits::expressive::{DeferredFn, ExpressiveEnum},
16};
17
18use crate::cmd::Cmd;
19
20impl DataSource for Cmd {}
21
22impl ExprDataSource<CborValue> for Cmd {
23    async fn execute(&self, expr: &Expression<CborValue>) -> Result<CborValue> {
24        if expr.parameters.is_empty() {
25            Ok(CborValue::Text(expr.template.clone()))
26        } else if expr.parameters.len() == 1 {
27            resolve_param(&expr.parameters[0]).await
28        } else {
29            Ok(CborValue::Null)
30        }
31    }
32
33    fn defer(&self, expr: Expression<CborValue>) -> DeferredFn<CborValue> {
34        let this = self.clone();
35        DeferredFn::new(move || {
36            let this = this.clone();
37            let expr = expr.clone();
38            Box::pin(async move {
39                let result = ExprDataSource::execute(&this, &expr).await?;
40                Ok(ExpressiveEnum::Scalar(result))
41            })
42        })
43    }
44}
45
46/// Recursively unwrap an `ExpressiveEnum` into its underlying value —
47/// mirrors `vantage-csv` / `vantage-aws` so a `column_table_values_expr`
48/// chain (Nested → Deferred → Scalar) collapses to the projected array.
49pub(crate) fn resolve_param(
50    param: &ExpressiveEnum<CborValue>,
51) -> Pin<Box<dyn Future<Output = Result<CborValue>> + Send + '_>> {
52    Box::pin(async move {
53        match param {
54            ExpressiveEnum::Scalar(v) => Ok(v.clone()),
55            ExpressiveEnum::Deferred(deferred) => {
56                let result = deferred.call().await?;
57                match result {
58                    ExpressiveEnum::Scalar(v) => Ok(v),
59                    other => resolve_param(&other).await,
60                }
61            }
62            ExpressiveEnum::Nested(expr) => {
63                if expr.parameters.is_empty() {
64                    Ok(CborValue::Text(expr.template.clone()))
65                } else if expr.parameters.len() == 1 {
66                    resolve_param(&expr.parameters[0]).await
67                } else {
68                    Ok(CborValue::Text(expr.template.clone()))
69                }
70            }
71        }
72    })
73}