Skip to main content

vantage_aws/
operation.rs

1//! `column.eq(value)` / `column.in_(subquery)` for AWS-backed tables.
2//!
3//! Bring [`AwsOperation`] into scope and any column or identifier
4//! expression you already have picks up the methods automatically:
5//!
6//! ```ignore
7//! use vantage_aws::AwsOperation;
8//!
9//! let cond = events["logGroupName"].eq("/aws/lambda/foo");
10//! ```
11//!
12//! For literal multi-value sets — rare, since AWS only accepts a
13//! single value anyway — call [`crate::in_`] directly.
14
15use ciborium::Value as CborValue;
16use vantage_expressions::Expressive;
17
18use crate::condition::AwsCondition;
19
20fn field_name<T>(expr: &(impl Expressive<T> + ?Sized)) -> String {
21    expr.expr().template
22}
23
24/// `eq` / `in_` for AWS-backed columns. Auto-implemented for any
25/// `Expressive<CborValue>` — `Column<T>`, identifier expressions, etc.
26pub trait AwsOperation<T>: Expressive<T> {
27    /// `column == value`.
28    fn eq(&self, value: impl Into<CborValue>) -> AwsCondition
29    where
30        Self: Sized,
31    {
32        AwsCondition::eq(field_name(self), value)
33    }
34
35    /// `column == value` where `value` comes from another query.
36    /// The subquery runs at execute time and must yield exactly one
37    /// value (AWS APIs don't accept multi-value filters).
38    ///
39    /// Typical call:
40    /// `events["logGroupName"].in_(source.column_values_expr("logGroupName"))`.
41    fn in_<E>(&self, source: E) -> AwsCondition
42    where
43        Self: Sized,
44        E: Expressive<CborValue>,
45    {
46        AwsCondition::Deferred {
47            field: field_name(self),
48            source: source.expr(),
49        }
50    }
51}
52
53impl<T, S: Expressive<T>> AwsOperation<T> for S {}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use vantage_expressions::Expression;
59    use vantage_table::column::core::Column;
60
61    #[test]
62    fn column_eq_produces_aws_condition() {
63        let c = Column::<String>::new("logGroupName");
64        match c.eq("/aws/lambda/foo") {
65            AwsCondition::Eq { field, value } => {
66                assert_eq!(field, "logGroupName");
67                assert!(matches!(value, CborValue::Text(ref s) if s == "/aws/lambda/foo"));
68            }
69            other => panic!("expected Eq, got {other:?}"),
70        }
71    }
72
73    #[test]
74    fn column_in_produces_deferred() {
75        let c = Column::<String>::new("logGroupName");
76        let source: Expression<CborValue> = Expression::new("subquery", vec![]);
77        match c.in_(source) {
78            AwsCondition::Deferred { field, source } => {
79                assert_eq!(field, "logGroupName");
80                assert_eq!(source.template, "subquery");
81            }
82            other => panic!("expected Deferred, got {other:?}"),
83        }
84    }
85}