dsq_shared/ops/
construct_ops.rs

1//! Data construction operations
2//!
3//! This module contains operations that create new data structures from existing values.
4
5use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::{Context, Operation};
10
11/// Type alias for field operation pairs in object construction
12type FieldOpPair = (
13    Box<dyn Operation + Send + Sync>,
14    Option<Vec<Box<dyn Operation + Send + Sync>>>,
15);
16
17/// Object construction operation
18///
19/// Creates a new object by evaluating key-value pairs from operations.
20pub struct ObjectConstructOperation {
21    /// Vector of (key_operation, optional_value_operations) pairs
22    ///
23    /// For each pair, the key operation produces the field name,
24    /// and the value operations (if present) produce the field value.
25    /// If no value operations are provided, the key is used as a field access.
26    pub field_ops: Vec<FieldOpPair>,
27}
28
29impl ObjectConstructOperation {
30    /// Creates a new object construction operation with the given field operations
31    pub fn new(field_ops: Vec<FieldOpPair>) -> Self {
32        Self { field_ops }
33    }
34}
35
36impl Operation for ObjectConstructOperation {
37    fn apply(&self, value: &Value) -> Result<Value> {
38        let mut context = None;
39        self.apply_with_context(value, &mut context)
40    }
41
42    fn apply_with_context(
43        &self,
44        value: &Value,
45        context: &mut Option<&mut dyn Context>,
46    ) -> Result<Value> {
47        // If the input value is null (e.g., from a failed select), return null
48        if matches!(value, Value::Null) {
49            return Ok(Value::Null);
50        }
51
52        // Apply object construction to the value (do not iterate over arrays)
53        let mut obj = std::collections::HashMap::new();
54
55        for (key_op, value_op) in &self.field_ops {
56            let key_value = key_op.apply_with_context(value, context)?;
57            let key = match key_value {
58                Value::String(s) => s,
59                _ => return Err(crate::error::operation_error("Object key must be a string")),
60            };
61
62            let field_value = if let Some(ops) = value_op {
63                let mut current = value.clone();
64                for op in ops {
65                    current = op.apply_with_context(&current, context)?;
66                }
67                current
68            } else {
69                // Shorthand: use the key as a field access
70                value.field(&key)?
71            };
72
73            obj.insert(key, field_value);
74        }
75
76        Ok(Value::Object(obj))
77    }
78
79    fn description(&self) -> String {
80        "object construction".to_string()
81    }
82
83    fn as_any(&self) -> &dyn Any {
84        self
85    }
86}
87
88/// Array construction operation
89///
90/// Creates a new array by evaluating a sequence of element operations.
91pub struct ArrayConstructOperation {
92    /// The operations that produce each element of the array
93    pub element_ops: Vec<Box<dyn Operation + Send + Sync>>,
94}
95
96impl ArrayConstructOperation {
97    /// Creates a new array construction operation with the given element operations
98    pub fn new(element_ops: Vec<Box<dyn Operation + Send + Sync>>) -> Self {
99        Self { element_ops }
100    }
101}
102
103impl Operation for ArrayConstructOperation {
104    fn apply(&self, value: &Value) -> Result<Value> {
105        let mut context = None;
106        self.apply_with_context(value, &mut context)
107    }
108
109    fn apply_with_context(
110        &self,
111        value: &Value,
112        context: &mut Option<&mut dyn Context>,
113    ) -> Result<Value> {
114        let mut arr = Vec::new();
115        for op in &self.element_ops {
116            arr.push(op.apply_with_context(value, context)?);
117        }
118        Ok(Value::Array(arr))
119    }
120
121    fn description(&self) -> String {
122        "array construction".to_string()
123    }
124
125    fn as_any(&self) -> &dyn Any {
126        self
127    }
128}
129
130/// Sequence operation (comma operator)
131///
132/// Evaluates multiple expressions and returns their results as an array.
133pub struct SequenceOperation {
134    /// Vector of expression sequences, where each inner vector represents one expression
135    pub expr_ops: Vec<Vec<Box<dyn Operation + Send + Sync>>>,
136}
137
138impl SequenceOperation {
139    /// Creates a new sequence operation with the given expression operations
140    pub fn new(expr_ops: Vec<Vec<Box<dyn Operation + Send + Sync>>>) -> Self {
141        Self { expr_ops }
142    }
143}
144
145impl Operation for SequenceOperation {
146    fn apply(&self, value: &Value) -> Result<Value> {
147        let mut context = None;
148        self.apply_with_context(value, &mut context)
149    }
150
151    fn apply_with_context(
152        &self,
153        value: &Value,
154        context: &mut Option<&mut dyn Context>,
155    ) -> Result<Value> {
156        let mut results = Vec::new();
157        for ops in &self.expr_ops {
158            let mut val = value.clone();
159            for op in ops {
160                val = op.apply_with_context(&val, context)?;
161            }
162            results.push(val);
163        }
164        Ok(Value::Array(results))
165    }
166
167    fn description(&self) -> String {
168        "sequence".to_string()
169    }
170
171    fn as_any(&self) -> &dyn Any {
172        self
173    }
174}