dsq_shared/ops/
basic_ops.rs

1//! Basic data access operations
2//!
3//! This module contains fundamental operations for accessing and manipulating basic data structures.
4
5use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::Operation;
10
11/// Identity operation - returns input unchanged
12pub struct IdentityOperation;
13
14impl Operation for IdentityOperation {
15    fn apply(&self, value: &Value) -> Result<Value> {
16        Ok(value.clone())
17    }
18
19    fn description(&self) -> String {
20        "identity".to_string()
21    }
22
23    fn as_any(&self) -> &dyn Any {
24        self
25    }
26}
27
28/// Literal value operation
29///
30/// Represents a literal value that is returned unchanged when applied.
31pub struct LiteralOperation {
32    /// The literal value to return
33    pub value: Value,
34}
35
36impl LiteralOperation {
37    /// Creates a new literal operation with the given value
38    pub fn new(value: Value) -> Self {
39        Self { value }
40    }
41}
42
43impl Operation for LiteralOperation {
44    fn apply(&self, _value: &Value) -> Result<Value> {
45        Ok(self.value.clone())
46    }
47
48    fn description(&self) -> String {
49        format!("literal: {:?}", self.value)
50    }
51
52    fn as_any(&self) -> &dyn Any {
53        self
54    }
55}
56
57/// Field access operation
58pub struct FieldAccessOperation {
59    /// The sequence of field names to access
60    pub fields: Vec<String>,
61}
62
63impl FieldAccessOperation {
64    /// Create a new field access operation for a single field
65    pub fn new(field: String) -> Self {
66        Self {
67            fields: vec![field],
68        }
69    }
70
71    /// Create a new field access operation for multiple fields
72    pub fn with_fields(fields: Vec<String>) -> Self {
73        Self { fields }
74    }
75}
76
77impl Operation for FieldAccessOperation {
78    fn apply(&self, value: &Value) -> Result<Value> {
79        let mut current = value.clone();
80        for field in &self.fields {
81            current = current.field(field)?;
82        }
83        Ok(current)
84    }
85
86    fn description(&self) -> String {
87        format!("field access: {}", self.fields.join("."))
88    }
89
90    fn as_any(&self) -> &dyn Any {
91        self
92    }
93}
94
95/// Array indexing operation
96///
97/// Represents indexing into arrays, strings, or DataFrames using a sequence of index operations.
98pub struct IndexOperation {
99    /// The sequence of operations that produce the index values
100    pub index_ops: Vec<Box<dyn Operation + Send + Sync>>,
101}
102
103impl IndexOperation {
104    /// Creates a new index operation with the given index operations
105    pub fn new(index_ops: Vec<Box<dyn Operation + Send + Sync>>) -> Self {
106        Self { index_ops }
107    }
108}
109
110impl Operation for IndexOperation {
111    fn apply(&self, value: &Value) -> Result<Value> {
112        let mut current = value.clone();
113        for op in &self.index_ops {
114            let index_value = op.apply(&current)?;
115            match index_value {
116                Value::Int(idx) => current = current.index(idx)?,
117                _ => return Err(crate::error::operation_error("Index must be an integer")),
118            }
119        }
120        Ok(current)
121    }
122
123    fn description(&self) -> String {
124        "array index".to_string()
125    }
126
127    fn as_any(&self) -> &dyn Any {
128        self
129    }
130}
131
132/// Array iteration operation (.[])
133pub struct IterateOperation;
134
135impl Operation for IterateOperation {
136    fn apply(&self, value: &Value) -> Result<Value> {
137        match value {
138            Value::Array(arr) => Ok(Value::Array(arr.clone())),
139            Value::Object(obj) => {
140                let values: Vec<Value> = obj.values().cloned().collect();
141                Ok(Value::Array(values))
142            }
143            Value::DataFrame(df) => {
144                // Convert DataFrame to array of objects
145                let mut rows = Vec::new();
146                for i in 0..df.height() {
147                    let mut row_obj = std::collections::HashMap::new();
148                    for col_name in df.get_column_names() {
149                        if let Ok(series) = df.column(col_name) {
150                            if let Ok(val) = series.get(i) {
151                                let value = match val {
152                                    polars::prelude::AnyValue::Int64(i) => Value::Int(i),
153                                    polars::prelude::AnyValue::Float64(f) => Value::Float(f),
154                                    polars::prelude::AnyValue::String(s) => {
155                                        Value::String(s.to_string())
156                                    }
157                                    polars::prelude::AnyValue::Boolean(b) => Value::Bool(b),
158                                    _ => Value::Null,
159                                };
160                                row_obj.insert(col_name.to_string(), value);
161                            }
162                        }
163                    }
164                    rows.push(Value::Object(row_obj));
165                }
166                Ok(Value::Array(rows))
167            }
168            _ => Ok(value.clone()),
169        }
170    }
171
172    fn description(&self) -> String {
173        "iterate array/object".to_string()
174    }
175
176    fn as_any(&self) -> &dyn Any {
177        self
178    }
179}