dsq_shared/ops/
special_ops.rs1use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::{AssignmentOperator, Context, Operation};
10
11type BuiltinFunc =
13 std::sync::Arc<dyn Fn(&[crate::value::Value]) -> Result<crate::value::Value> + Send + Sync>;
14
15pub struct FunctionCallOperation {
17 pub function_name: String,
19 pub arg_ops: Vec<Box<dyn Operation + Send + Sync>>,
21 pub builtin_func: Option<BuiltinFunc>,
23}
24
25impl FunctionCallOperation {
26 pub fn new(
28 function_name: String,
29 arg_ops: Vec<Box<dyn Operation + Send + Sync>>,
30 builtin_func: Option<BuiltinFunc>,
31 ) -> Self {
32 Self {
33 function_name,
34 arg_ops,
35 builtin_func,
36 }
37 }
38}
39
40impl Operation for FunctionCallOperation {
41 fn apply(&self, value: &Value) -> Result<Value> {
42 let mut context = None;
43 self.apply_with_context(value, &mut context)
44 }
45
46 fn apply_with_context(
47 &self,
48 value: &Value,
49 context: &mut Option<&mut dyn Context>,
50 ) -> Result<Value> {
51 if let Some(func) = &self.builtin_func {
52 let mut args = Vec::new();
54 for arg_op in &self.arg_ops {
55 let arg_value = arg_op.apply_with_context(value, context)?;
56 args.push(arg_value);
57 }
58
59 if self.function_name == "select" && args.len() == 1 {
61 args.insert(0, value.clone());
62 }
63
64 func(&args)
66 } else {
67 Err(crate::error::operation_error(format!(
68 "Unknown function '{}'",
69 self.function_name
70 )))
71 }
72 }
73
74 fn description(&self) -> String {
75 format!("call function {}", self.function_name)
76 }
77
78 fn as_any(&self) -> &dyn Any {
79 self
80 }
81}
82
83pub struct DelOperation {
87 pub path_ops: Vec<Box<dyn Operation + Send + Sync>>,
89}
90
91impl DelOperation {
92 pub fn new(path_ops: Vec<Box<dyn Operation + Send + Sync>>) -> Self {
94 Self { path_ops }
95 }
96}
97
98impl Operation for DelOperation {
99 fn apply(&self, value: &Value) -> Result<Value> {
100 let mut context = None;
101 self.apply_with_context(value, &mut context)
102 }
103
104 fn apply_with_context(
105 &self,
106 value: &Value,
107 _context: &mut Option<&mut dyn Context>,
108 ) -> Result<Value> {
109 Ok(value.clone())
112 }
113
114 fn description(&self) -> String {
115 "delete".to_string()
116 }
117
118 fn as_any(&self) -> &dyn Any {
119 self
120 }
121}
122
123pub struct AssignmentOperation {
127 pub target_ops: Vec<Box<dyn Operation + Send + Sync>>,
129 pub operator: AssignmentOperator,
131 pub value_ops: Vec<Box<dyn Operation + Send + Sync>>,
133}
134
135impl AssignmentOperation {
136 pub fn new(
138 target_ops: Vec<Box<dyn Operation + Send + Sync>>,
139 operator: AssignmentOperator,
140 value_ops: Vec<Box<dyn Operation + Send + Sync>>,
141 ) -> Self {
142 Self {
143 target_ops,
144 operator,
145 value_ops,
146 }
147 }
148}
149
150impl Operation for AssignmentOperation {
151 fn apply(&self, value: &Value) -> Result<Value> {
152 let mut context = None;
153 self.apply_with_context(value, &mut context)
154 }
155
156 fn apply_with_context(
157 &self,
158 value: &Value,
159 context: &mut Option<&mut dyn Context>,
160 ) -> Result<Value> {
161 if let Value::Object(obj) = value {
163 if self.target_ops.len() == 2 {
166 if let Some(field_op) = self.target_ops[1]
168 .as_any()
169 .downcast_ref::<super::basic_ops::FieldAccessOperation>()
170 {
171 if !field_op.fields.is_empty() {
172 let new_value = if self.value_ops.len() == 1 {
174 self.value_ops[0].apply_with_context(value, context)?
175 } else {
176 Value::Null
177 };
178
179 fn update_nested(
181 obj: &std::collections::HashMap<String, Value>,
182 fields: &[String],
183 new_value: Value,
184 operator: &AssignmentOperator,
185 ) -> Value {
186 if fields.is_empty() {
187 return Value::Object(obj.clone());
188 }
189
190 let field_name = &fields[0];
191 let mut new_obj = obj.clone();
192
193 if fields.len() == 1 {
194 let current_value =
196 obj.get(field_name).cloned().unwrap_or(Value::Null);
197 let final_value = match operator {
198 AssignmentOperator::AddAssign => {
199 match (¤t_value, &new_value) {
200 (Value::Int(a), Value::Int(b)) => Value::Int(a + b),
201 (Value::Float(a), Value::Float(b)) => {
202 Value::Float(a + b)
203 }
204 (Value::String(a), Value::String(b)) => {
205 Value::String(format!("{}{}", a, b))
206 }
207 _ => new_value,
208 }
209 }
210 AssignmentOperator::UpdateAssign => new_value,
211 };
212 new_obj.insert(field_name.clone(), final_value);
213 } else {
214 if let Some(Value::Object(nested)) = obj.get(field_name) {
216 let updated =
217 update_nested(nested, &fields[1..], new_value, operator);
218 new_obj.insert(field_name.clone(), updated);
219 } else {
220 let empty = std::collections::HashMap::new();
222 let updated =
223 update_nested(&empty, &fields[1..], new_value, operator);
224 new_obj.insert(field_name.clone(), updated);
225 }
226 }
227 Value::Object(new_obj)
228 }
229
230 return Ok(update_nested(
231 obj,
232 &field_op.fields,
233 new_value,
234 &self.operator,
235 ));
236 }
237 }
238 }
239 }
240
241 if self.value_ops.len() == 1 {
244 self.value_ops[0].apply_with_context(value, context)
245 } else {
246 Ok(value.clone())
247 }
248 }
249
250 fn description(&self) -> String {
251 "assignment".to_string()
252 }
253
254 fn as_any(&self) -> &dyn Any {
255 self
256 }
257}
258
259pub struct JoinFromFileOperation {
263 pub file_path: String,
265 pub left_key: String,
267 pub right_key: String,
269}
270
271impl JoinFromFileOperation {
272 pub fn new(file_path: String, left_key: String, right_key: String) -> Self {
274 Self {
275 file_path,
276 left_key,
277 right_key,
278 }
279 }
280}
281
282impl Operation for JoinFromFileOperation {
283 fn apply(&self, value: &Value) -> Result<Value> {
284 let mut context = None;
285 self.apply_with_context(value, &mut context)
286 }
287
288 fn apply_with_context(
289 &self,
290 value: &Value,
291 _context: &mut Option<&mut dyn Context>,
292 ) -> Result<Value> {
293 Ok(value.clone())
296 }
297
298 fn description(&self) -> String {
299 "join from file".to_string()
300 }
301
302 fn as_any(&self) -> &dyn Any {
303 self
304 }
305}