1use polars::prelude::{DataType, Expr, Series, col, lit};
5use serde_json::Value;
6use std::error::Error;
7use std::fmt;
8
9#[derive(Debug)]
11pub struct PlanExprError(String);
12
13impl fmt::Display for PlanExprError {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 write!(f, "{}", self.0)
16 }
17}
18
19impl Error for PlanExprError {}
20
21pub fn expr_from_value(v: &Value) -> Result<Expr, PlanExprError> {
27 if let Some(name) = v.as_str() {
29 return Ok(col(name));
30 }
31
32 if v.is_null() {
34 return Ok(lit(polars::prelude::NULL));
35 }
36 if let Some(n) = v.as_i64() {
37 return Ok(lit(n));
38 }
39 if let Some(n) = v.as_f64() {
40 return Ok(lit(n));
41 }
42 if let Some(b) = v.as_bool() {
43 return Ok(lit(b));
44 }
45
46 let obj = v.as_object().ok_or_else(|| {
47 PlanExprError(
48 "expression must be a JSON object, column name string, or literal (number/bool/null)"
49 .to_string(),
50 )
51 })?;
52
53 if let Some(name) = obj
55 .get("col")
56 .or_else(|| obj.get("column"))
57 .and_then(Value::as_str)
58 {
59 return Ok(col(name));
60 }
61
62 if let Some(lit_val) = obj.get("lit") {
64 return lit_from_value(lit_val);
65 }
66
67 if let Some(op) = obj.get("op").and_then(Value::as_str) {
70 let args_present = obj.get("args").and_then(Value::as_array).is_some();
71 let fn_style_with_args = args_present && matches!(op, "coalesce" | "nvl");
72 if !fn_style_with_args {
73 match op {
74 "eq" | "ne" | "gt" | "ge" | "lt" | "le" => {
75 let left_v = obj
76 .get("left")
77 .ok_or_else(|| PlanExprError(format!("op '{op}' requires 'left'")))?;
78 let right_v = obj
79 .get("right")
80 .ok_or_else(|| PlanExprError(format!("op '{op}' requires 'right'")))?;
81 let l = expr_from_value(left_v)?;
82 let r = expr_from_value(right_v)?;
83
84 let infer_lit_type = |e: &Expr| -> Option<DataType> {
87 if let Expr::Literal(lv) = e {
88 let dt = lv.get_datatype();
89 if matches!(dt, DataType::Unknown(_)) {
90 None
91 } else {
92 Some(dt)
93 }
94 } else {
95 None
96 }
97 };
98
99 let l_ty = infer_lit_type(&l);
100 let r_ty = infer_lit_type(&r);
101
102 use crate::type_coercion::{CompareOp, coerce_for_pyspark_comparison};
105 let op_enum = match op {
106 "eq" => CompareOp::Eq,
107 "ne" => CompareOp::NotEq,
108 "gt" => CompareOp::Gt,
109 "ge" => CompareOp::GtEq,
110 "lt" => CompareOp::Lt,
111 "le" => CompareOp::LtEq,
112 _ => unreachable!(),
113 };
114 let (lt, rt) = match (&l_ty, &r_ty) {
118 (Some(lt), Some(rt)) => (lt.clone(), rt.clone()),
119 (Some(lt), None) => (lt.clone(), DataType::String),
120 (None, Some(rt)) if *rt == DataType::String => {
121 return Ok(match op {
122 "eq" => l.eq(r),
123 "ne" => l.neq(r),
124 "gt" => l.gt(r),
125 "ge" => l.gt_eq(r),
126 "lt" => l.lt(r),
127 "le" => l.lt_eq(r),
128 _ => unreachable!(),
129 });
130 }
131 (None, Some(rt)) => (DataType::String, rt.clone()),
132 (None, None) => {
133 return Ok(match op {
135 "eq" => l.eq(r),
136 "ne" => l.neq(r),
137 "gt" => l.gt(r),
138 "ge" => l.gt_eq(r),
139 "lt" => l.lt(r),
140 "le" => l.lt_eq(r),
141 _ => unreachable!(),
142 });
143 }
144 };
145 let expr = match coerce_for_pyspark_comparison(
146 l.clone(),
147 r.clone(),
148 <,
149 &rt,
150 &op_enum,
151 ) {
152 Ok((lc, rc)) => match op {
153 "eq" => lc.eq(rc),
154 "ne" => lc.neq(rc),
155 "gt" => lc.gt(rc),
156 "ge" => lc.gt_eq(rc),
157 "lt" => lc.lt(rc),
158 "le" => lc.lt_eq(rc),
159 _ => unreachable!(),
160 },
161 Err(_) => match op {
162 "eq" => l.eq(r),
163 "ne" => l.neq(r),
164 "gt" => l.gt(r),
165 "ge" => l.gt_eq(r),
166 "lt" => l.lt(r),
167 "le" => l.lt_eq(r),
168 _ => unreachable!(),
169 },
170 };
171
172 return Ok(expr);
173 }
174 "eq_null_safe" => {
175 let left = obj.get("left").ok_or_else(|| {
176 PlanExprError("op 'eq_null_safe' requires 'left'".to_string())
177 })?;
178 let right = obj.get("right").ok_or_else(|| {
179 PlanExprError("op 'eq_null_safe' requires 'right'".to_string())
180 })?;
181 let l = expr_from_value(left)?;
182 let r = expr_from_value(right)?;
183 return eq_null_safe_expr(l, r);
184 }
185 "and" => {
186 let left = obj
187 .get("left")
188 .ok_or_else(|| PlanExprError("op 'and' requires 'left'".to_string()))?;
189 let right = obj
190 .get("right")
191 .ok_or_else(|| PlanExprError("op 'and' requires 'right'".to_string()))?;
192 return Ok(expr_from_value(left)?.and(expr_from_value(right)?));
193 }
194 "or" => {
195 let left = obj
196 .get("left")
197 .ok_or_else(|| PlanExprError("op 'or' requires 'left'".to_string()))?;
198 let right = obj
199 .get("right")
200 .ok_or_else(|| PlanExprError("op 'or' requires 'right'".to_string()))?;
201 return Ok(expr_from_value(left)?.or(expr_from_value(right)?));
202 }
203 "not" => {
204 let arg = obj
207 .get("arg")
208 .ok_or_else(|| PlanExprError("op 'not' requires 'arg'".to_string()))?;
209 let arg_expr = expr_from_value(arg)?;
210 let arg_col = expr_to_column(arg_expr);
211 return Ok(arg_col.bitwise_not().into_expr());
212 }
213 "bitwise_not" => {
214 let arg = obj.get("arg").ok_or_else(|| {
216 PlanExprError("op 'bitwise_not' requires 'arg'".to_string())
217 })?;
218 let arg_expr = expr_from_value(arg)?;
219 let arg_col = expr_to_column(arg_expr);
220 return Ok(arg_col.bitwise_not().into_expr());
221 }
222 "between" => {
223 let left_v = obj
224 .get("left")
225 .ok_or_else(|| PlanExprError("op 'between' requires 'left'".to_string()))?;
226 let lower_v = obj.get("lower").ok_or_else(|| {
227 PlanExprError("op 'between' requires 'lower'".to_string())
228 })?;
229 let upper_v = obj.get("upper").ok_or_else(|| {
230 PlanExprError("op 'between' requires 'upper'".to_string())
231 })?;
232 let left = expr_from_value(left_v)?;
233 let lower = expr_from_value(lower_v)?;
234 let upper = expr_from_value(upper_v)?;
235 let infer_lit_type = |e: &Expr| -> Option<DataType> {
237 if let Expr::Literal(lv) = e {
238 let dt = lv.get_datatype();
239 if matches!(dt, DataType::Unknown(_)) {
240 None
241 } else {
242 Some(dt)
243 }
244 } else {
245 None
246 }
247 };
248 let lower_ty = infer_lit_type(&lower);
249 let upper_ty = infer_lit_type(&upper);
250 use crate::type_coercion::{CompareOp, coerce_for_pyspark_comparison};
251 let lt = DataType::String;
253 let rt_lower = lower_ty.unwrap_or(DataType::String);
254 let rt_upper = upper_ty.unwrap_or(DataType::String);
255 let (left_c, lower_c) = match coerce_for_pyspark_comparison(
256 left.clone(),
257 lower.clone(),
258 <,
259 &rt_lower,
260 &CompareOp::GtEq,
261 ) {
262 Ok((a, b)) => (a, b),
263 Err(_) => (left.clone(), lower),
264 };
265 let upper_clone = upper.clone();
266 let (left_cc, upper_c) = match coerce_for_pyspark_comparison(
267 left_c.clone(),
268 upper,
269 <,
270 &rt_upper,
271 &CompareOp::LtEq,
272 ) {
273 Ok((a, b)) => (a, b),
274 Err(_) => (left_c.clone(), upper_clone),
275 };
276 return Ok(left_cc.clone().gt_eq(lower_c).and(left_cc.lt_eq(upper_c)));
277 }
278 "**" | "pow" => {
279 let left_v = obj
280 .get("left")
281 .ok_or_else(|| PlanExprError(format!("op '{op}' requires 'left'")))?;
282 let right_v = obj
283 .get("right")
284 .ok_or_else(|| PlanExprError(format!("op '{op}' requires 'right'")))?;
285 let l = expr_from_value(left_v)?;
286 let r = expr_from_value(right_v)?;
287 let left_col = expr_to_column(l);
288 let right_col = expr_to_column(r);
289 return Ok(left_col.pow_with(&right_col).into_expr());
290 }
291 "isin" => {
292 let left_v = obj
296 .get("left")
297 .ok_or_else(|| PlanExprError("op 'isin' requires 'left'".to_string()))?;
298 let left_expr = expr_from_value(left_v)?;
299 let values_opt =
300 if let Some(values_arr) = obj.get("values").and_then(Value::as_array) {
301 try_values_for_isin(values_arr)?
302 } else if let Some(right_v) = obj.get("right") {
303 try_values_from_plan_value(right_v)?
304 } else {
305 return Err(PlanExprError(
306 "op 'isin' requires 'right' or 'values'".to_string(),
307 ));
308 };
309 return Ok(match values_opt {
310 None => lit(false),
311 Some(values_expr) => {
312 left_expr
315 .cast(DataType::String)
316 .is_in(values_expr.implode(), false)
317 }
318 });
319 }
320 "getItem" => {
321 let left_v = obj
323 .get("left")
324 .ok_or_else(|| PlanExprError("op 'getItem' requires 'left'".to_string()))?;
325 let right_v = obj.get("right").ok_or_else(|| {
326 PlanExprError("op 'getItem' requires 'right'".to_string())
327 })?;
328 let col_expr = expr_from_value(left_v)?;
329 let idx = lit_as_i64(right_v)?;
330 let col_c = expr_to_column(col_expr);
331 return Ok(col_c.get_item(idx).into_expr());
332 }
333 "startswith" => {
334 let left_v = obj.get("left").ok_or_else(|| {
336 PlanExprError("op 'startswith' requires 'left'".to_string())
337 })?;
338 let right_v = obj.get("right").ok_or_else(|| {
339 PlanExprError("op 'startswith' requires 'right'".to_string())
340 })?;
341 let col_expr = expr_from_value(left_v)?;
342 let prefix = lit_as_string(right_v)?;
343 let col_c = expr_to_column(col_expr);
344 return Ok(crate::functions::startswith(&col_c, &prefix).into_expr());
345 }
346 "is_null" => {
347 let arg = obj
348 .get("arg")
349 .ok_or_else(|| PlanExprError("op 'is_null' requires 'arg'".to_string()))?;
350 return Ok(expr_from_value(arg)?.is_null());
351 }
352 "is_not_null" => {
353 let arg = obj.get("arg").ok_or_else(|| {
354 PlanExprError("op 'is_not_null' requires 'arg'".to_string())
355 })?;
356 return Ok(expr_from_value(arg)?.is_not_null());
357 }
358 "regexp_extract" => {
359 if let Some(args) = obj.get("args").and_then(Value::as_array) {
362 require_args_min("regexp_extract", args, 3)?;
363 let col_expr = expr_from_value(&args[0])?;
364 let pattern = lit_as_string(&args[1])?;
365 let group_idx = lit_as_usize(&args[2])?;
366 let col_c = expr_to_column(col_expr);
367 return Ok(
368 crate::functions::regexp_extract(&col_c, &pattern, group_idx)
369 .into_expr(),
370 );
371 }
372 let left_v = obj.get("left").ok_or_else(|| {
373 PlanExprError("op 'regexp_extract' requires 'left'".to_string())
374 })?;
375 let col_expr = expr_from_value(left_v)?;
376 let pattern_v =
377 obj.get("pattern")
378 .or_else(|| obj.get("right"))
379 .ok_or_else(|| {
380 PlanExprError(
381 "op 'regexp_extract' requires 'pattern' or 'right'".to_string(),
382 )
383 })?;
384 let pattern = lit_as_string(pattern_v)?;
385 let group_idx = obj
386 .get("group")
387 .and_then(|v| lit_as_usize(v).ok())
388 .unwrap_or(0);
389 let col_c = expr_to_column(col_expr);
390 return Ok(
391 crate::functions::regexp_extract(&col_c, &pattern, group_idx).into_expr(),
392 );
393 }
394 "regexp_replace" => {
395 if let Some(args) = obj.get("args").and_then(Value::as_array) {
398 require_args_min("regexp_replace", args, 3)?;
399 let col_expr = expr_from_value(&args[0])?;
400 let pattern = lit_as_string(&args[1])?;
401 let replacement = lit_as_string(&args[2])?;
402 let col_c = expr_to_column(col_expr);
403 return Ok(crate::functions::regexp_replace(
404 &col_c,
405 &pattern,
406 &replacement,
407 )
408 .into_expr());
409 }
410 let left_v = obj.get("left").ok_or_else(|| {
411 PlanExprError("op 'regexp_replace' requires 'left'".to_string())
412 })?;
413 let col_expr = expr_from_value(left_v)?;
414 let pattern = lit_as_string(
415 obj.get("pattern")
416 .or_else(|| obj.get("right"))
417 .ok_or_else(|| {
418 PlanExprError(
419 "op 'regexp_replace' requires 'pattern' or 'right'".to_string(),
420 )
421 })?,
422 )?;
423 let replacement = lit_as_string(obj.get("replacement").ok_or_else(|| {
424 PlanExprError("op 'regexp_replace' requires 'replacement'".to_string())
425 })?)?;
426 let col_c = expr_to_column(col_expr);
427 return Ok(
428 crate::functions::regexp_replace(&col_c, &pattern, &replacement)
429 .into_expr(),
430 );
431 }
432 "create_map" | "createMap" => {
433 let args_arr = obj.get("args").and_then(Value::as_array).ok_or_else(|| {
435 PlanExprError(
436 "op 'create_map'/'createMap' requires 'args' array".to_string(),
437 )
438 })?;
439 let exprs: Result<Vec<Expr>, _> =
440 args_arr.iter().map(expr_from_value).collect();
441 let cols: Vec<crate::Column> = exprs?.into_iter().map(expr_to_column).collect();
442 let refs: Vec<&crate::Column> = cols.iter().collect();
443 return Ok(crate::functions::create_map(&refs)
444 .map_err(|e| PlanExprError(e.to_string()))?
445 .into_expr());
446 }
447 "add" | "+" => {
448 let left_v = obj
450 .get("left")
451 .ok_or_else(|| PlanExprError("op 'add' requires 'left'".to_string()))?;
452 let right_v = obj
453 .get("right")
454 .ok_or_else(|| PlanExprError("op 'add' requires 'right'".to_string()))?;
455 let l = expr_from_value(left_v)?;
456 let r = expr_from_value(right_v)?;
457 let a = expr_to_column(l);
458 let b = expr_to_column(r);
459 return Ok(a.add_pyspark(&b).into_expr());
460 }
461 "sub" | "minus" | "-" => {
462 let left_v = obj
465 .get("left")
466 .ok_or_else(|| PlanExprError("op 'sub' requires 'left'".to_string()))?;
467 let right_v = obj
468 .get("right")
469 .ok_or_else(|| PlanExprError("op 'sub' requires 'right'".to_string()))?;
470 let l = expr_from_value(left_v)?;
471 let r = expr_from_value(right_v)?;
472 let a = expr_to_column(l);
473 let b = expr_to_column(r);
474 return Ok(a.subtract_pyspark(&b).into_expr());
475 }
476 "mul" | "*" => {
477 let left_v = obj
480 .get("left")
481 .ok_or_else(|| PlanExprError("op 'mul' requires 'left'".to_string()))?;
482 let right_v = obj
483 .get("right")
484 .ok_or_else(|| PlanExprError("op 'mul' requires 'right'".to_string()))?;
485 let l = expr_from_value(left_v)?;
486 let r = expr_from_value(right_v)?;
487 let a = expr_to_column(l);
488 let b = expr_to_column(r);
489 return Ok(a.multiply_pyspark(&b).into_expr());
490 }
491 "div" | "/" | "divide" => {
492 let left_v = obj
494 .get("left")
495 .ok_or_else(|| PlanExprError("op 'div' requires 'left'".to_string()))?;
496 let right_v = obj
497 .get("right")
498 .ok_or_else(|| PlanExprError("op 'div' requires 'right'".to_string()))?;
499 let l = expr_from_value(left_v)?;
500 let r = expr_from_value(right_v)?;
501 let a = expr_to_column(l);
502 let b = expr_to_column(r);
503 return Ok(a.divide_pyspark(&b).into_expr());
504 }
505 "udf" => {
506 let udf_name = obj
508 .get("udf")
509 .or_else(|| obj.get("name"))
510 .and_then(Value::as_str)
511 .ok_or_else(|| {
512 PlanExprError("op 'udf' requires 'udf' or 'name'".to_string())
513 })?;
514 let args = obj.get("args").and_then(Value::as_array).ok_or_else(|| {
515 PlanExprError("op 'udf' requires 'args' array".to_string())
516 })?;
517 let col = column_from_udf_call(udf_name, args)?;
518 if col.udf_call.is_some() {
519 return Err(PlanExprError(
520 "Python/Vectorized UDFs are only supported in withColumn/select, not in filter/plan expressions"
521 .into(),
522 ));
523 }
524 return Ok(col.expr().clone());
525 }
526 "translate" | "substring_index" | "substringIndex" | "levenshtein" | "soundex"
528 | "crc32" | "xxhash64" | "get_json_object" | "getJsonObject" | "json_tuple"
529 | "jsonTuple" | "regexp_extract_all" | "regexpExtractAll" | "date_trunc"
530 | "dateTrunc" | "to_date" | "toDate" | "format_string" | "formatString" | "log"
531 | "explode" | "explode_outer" | "explodeOuter" | "concat" | "contains" => {
532 let args = obj
533 .get("args")
534 .and_then(Value::as_array)
535 .ok_or_else(|| PlanExprError(format!("op '{op}' requires 'args' array")))?;
536 let fn_name = match op {
537 "substringIndex" => "substring_index",
538 "getJsonObject" => "get_json_object",
539 "jsonTuple" => "json_tuple",
540 "regexpExtractAll" => "regexp_extract_all",
541 "dateTrunc" => "date_trunc",
542 "toDate" => "to_date",
543 "formatString" => "format_string",
544 "explodeOuter" => "explode_outer",
545 other => other,
546 };
547 return expr_from_fn(fn_name, args);
548 }
549 _ => {
550 return Err(PlanExprError(format!("unsupported expression op: {op}")));
551 }
552 }
553 }
554 }
555
556 if let Some(udf_name) = obj.get("udf").and_then(Value::as_str) {
558 let args = obj
559 .get("args")
560 .and_then(Value::as_array)
561 .ok_or_else(|| PlanExprError("udf requires 'args' array".to_string()))?;
562 let col = column_from_udf_call(udf_name, args)?;
563 if col.udf_call.is_some() {
564 return Err(PlanExprError(
565 "Python/Vectorized UDFs are only supported in withColumn/select, not in filter/plan expressions"
566 .into(),
567 ));
568 }
569 return Ok(col.expr().clone());
570 }
571
572 let fn_name = obj
575 .get("fn")
576 .or_else(|| obj.get("function"))
577 .or_else(|| {
578 obj.get("args").and_then(|_| obj.get("op"))
580 })
581 .and_then(Value::as_str);
582 if let Some(fn_name) = fn_name {
583 if let Some(window_val) = obj.get("window") {
584 return expr_from_window_fn(
585 fn_name,
586 window_val,
587 obj.get("args").and_then(Value::as_array),
588 );
589 }
590 let args = obj
591 .get("args")
592 .and_then(Value::as_array)
593 .ok_or_else(|| PlanExprError(format!("fn '{fn_name}' requires 'args' array")))?;
594 return expr_from_fn(fn_name, args);
595 }
596
597 if let Some(typ) = obj.get("type").and_then(Value::as_str) {
599 if typ == "window" {
600 let fn_name = obj
601 .get("fn")
602 .or_else(|| obj.get("function"))
603 .and_then(Value::as_str)
604 .ok_or_else(|| {
605 PlanExprError("type window requires 'fn' or 'function'".to_string())
606 })?;
607 let window_val = obj
608 .get("window")
609 .ok_or_else(|| PlanExprError("type window requires 'window'".to_string()))?;
610 let args = obj.get("args").and_then(Value::as_array);
611 return expr_from_window_fn(fn_name, window_val, args);
612 }
613 }
614
615 Err(PlanExprError(
616 "expression must have 'col', 'lit', 'op', 'fn', or 'type'".to_string(),
617 ))
618}
619
620fn window_col_from_value(x: &Value) -> Option<String> {
622 if let Some(s) = x.as_str() {
623 return Some(s.to_string());
624 }
625 if let Some(obj) = x.as_object() {
626 if let Some(name) = obj.get("col").and_then(Value::as_str) {
627 return Some(name.to_string());
628 }
629 }
630 None
631}
632
633fn parse_window_spec(v: &Value) -> Result<(Vec<String>, Vec<String>, bool), PlanExprError> {
638 let obj = v
639 .as_object()
640 .ok_or_else(|| PlanExprError("window spec must be object".to_string()))?;
641 let order_arr = obj.get("order_by").and_then(Value::as_array);
642 let part_arr = obj.get("partition_by").and_then(Value::as_array);
643 let order_by_explicitly_empty = order_arr.map(|a| a.is_empty()).unwrap_or(false);
644 let order_cols: Vec<String> = order_arr
645 .map(|a| a.iter().filter_map(window_col_from_value).collect())
646 .unwrap_or_default();
647 let part_cols: Vec<String> = part_arr
648 .map(|a| a.iter().filter_map(window_col_from_value).collect())
649 .unwrap_or_default();
650 Ok((order_cols, part_cols, order_by_explicitly_empty))
651}
652
653fn window_order_cols(order_cols: &[String], part_cols: &[String]) -> Vec<String> {
655 if order_cols.is_empty() {
656 part_cols.to_vec()
657 } else {
658 order_cols.to_vec()
659 }
660}
661
662fn expr_from_row_number_window(v: &Value) -> Result<Expr, PlanExprError> {
665 let (order_cols, part_cols, order_by_explicitly_empty) = parse_window_spec(v)?;
666 if order_by_explicitly_empty && order_cols.is_empty() && part_cols.is_empty() {
667 return Err(PlanExprError(
668 "At least one column must be specified for orderBy".to_string(),
669 ));
670 }
671 let part_refs: Vec<&str> = part_cols.iter().map(|s| s.as_str()).collect();
672 let effective_order = window_order_cols(&order_cols, &part_cols);
673 let order_col = if effective_order.is_empty() {
674 crate::Column::from_expr(lit(1i32), None)
675 } else {
676 crate::Column::new(effective_order[0].clone())
677 };
678 let rn = order_col.row_number(false).over(&part_refs);
679 Ok(rn.into_expr())
680}
681
682fn expr_from_window_fn(
685 fn_name: &str,
686 window_val: &Value,
687 args: Option<&Vec<Value>>,
688) -> Result<Expr, PlanExprError> {
689 use crate::Column;
690 let (order_cols, part_cols, order_by_explicitly_empty) = parse_window_spec(window_val)?;
691 if order_by_explicitly_empty && order_cols.is_empty() && part_cols.is_empty() {
692 return Err(PlanExprError(
693 "At least one column must be specified for orderBy".to_string(),
694 ));
695 }
696 let part_refs: Vec<&str> = part_cols.iter().map(|s| s.as_str()).collect();
697 let effective_order = window_order_cols(&order_cols, &part_cols);
698 let empty: &[Value] = &[];
699 let args: &[Value] = args.map_or(empty, |v| v);
700 let order_col = if effective_order.is_empty() {
701 Column::from_expr(lit(1i32), None)
702 } else {
703 Column::new(effective_order[0].clone())
704 };
705
706 match fn_name {
707 "row_number" => expr_from_row_number_window(window_val),
708 "rank" => {
709 let c = order_col.rank(false).over(&part_refs);
710 Ok(c.into_expr())
711 }
712 "dense_rank" => {
713 let c = order_col.dense_rank(false).over(&part_refs);
714 Ok(c.into_expr())
715 }
716 "percent_rank" => {
717 let c = order_col.percent_rank(&part_refs, false);
718 Ok(c.into_expr())
719 }
720 "ntile" => {
721 let n = args
722 .first()
723 .and_then(|v| v.get("lit").and_then(Value::as_i64))
724 .or_else(|| args.first().and_then(Value::as_i64))
725 .ok_or_else(|| {
726 PlanExprError("ntile window requires n (number of buckets)".to_string())
727 })? as u32;
728 let c = order_col.ntile(n.max(1), &part_refs, false);
729 Ok(c.into_expr())
730 }
731 "lag" => {
732 let n = args
733 .get(1)
734 .and_then(|v| v.get("lit").and_then(Value::as_i64))
735 .or_else(|| args.get(1).and_then(Value::as_i64))
736 .unwrap_or(1);
737 let col_expr =
738 expr_to_column(expr_from_value(args.first().ok_or_else(|| {
739 PlanExprError("lag window requires column arg".to_string())
740 })?)?);
741 let c = col_expr.lag(n).over(&part_refs);
742 Ok(c.into_expr())
743 }
744 "lead" => {
745 let n = args
746 .get(1)
747 .and_then(|v| v.get("lit").and_then(Value::as_i64))
748 .or_else(|| args.get(1).and_then(Value::as_i64))
749 .unwrap_or(1);
750 let col_expr =
751 expr_to_column(expr_from_value(args.first().ok_or_else(|| {
752 PlanExprError("lead window requires column arg".to_string())
753 })?)?);
754 let c = col_expr.lead(n).over(&part_refs);
755 Ok(c.into_expr())
756 }
757 "sum" => {
758 let col_expr =
759 expr_to_column(expr_from_value(args.first().ok_or_else(|| {
760 PlanExprError("sum window requires column arg".to_string())
761 })?)?);
762 let sum_expr = col_expr.expr().clone().sum();
763 let partition_exprs: Vec<Expr> = part_refs.iter().map(|s| col(*s)).collect();
764 Ok(sum_expr.over(partition_exprs))
765 }
766 "avg" | "mean" => {
767 let col_expr =
768 expr_to_column(expr_from_value(args.first().ok_or_else(|| {
769 PlanExprError("avg window requires column arg".to_string())
770 })?)?);
771 let mean_expr = col_expr.expr().clone().mean();
772 let partition_exprs: Vec<Expr> = part_refs.iter().map(|s| col(*s)).collect();
773 Ok(mean_expr.over(partition_exprs))
774 }
775 "approx_count_distinct" => {
776 let col_expr = expr_to_column(expr_from_value(args.first().ok_or_else(|| {
777 PlanExprError("approx_count_distinct window requires column arg".to_string())
778 })?)?);
779 let n_unique_expr = col_expr.expr().clone().n_unique().cast(DataType::Int64);
780 let partition_exprs: Vec<Expr> = part_refs.iter().map(|s| col(*s)).collect();
781 Ok(n_unique_expr.over(partition_exprs))
782 }
783 "cume_dist" => {
784 let c = order_col.cume_dist(&part_refs, false);
785 Ok(c.into_expr())
786 }
787 _ => Err(PlanExprError(format!(
788 "unsupported window fn '{fn_name}' (supported: row_number, rank, dense_rank, percent_rank, cume_dist, ntile, lag, lead, sum, avg, approx_count_distinct)"
789 ))),
790 }
791}
792
793fn lit_from_value(v: &Value) -> Result<Expr, PlanExprError> {
794 use polars::prelude::{NULL, lit};
795 if v.is_null() {
796 return Ok(lit(NULL));
797 }
798 if let Some(n) = v.as_i64() {
799 return Ok(lit(n));
800 }
801 if let Some(n) = v.as_f64() {
802 return Ok(lit(n));
803 }
804 if let Some(b) = v.as_bool() {
805 return Ok(lit(b));
806 }
807 if let Some(s) = v.as_str() {
808 return Ok(lit(s));
809 }
810 Err(PlanExprError("unsupported literal type".to_string()))
811}
812
813fn is_cast_to_string(v: &Value) -> bool {
814 let args = match v.get("args").and_then(|a| a.as_array()) {
815 Some(a) if a.len() >= 2 => a,
816 _ => return false,
817 };
818 if v.get("fn").and_then(|f| f.as_str()) != Some("cast") {
819 return false;
820 }
821 let type_val = &args[1];
822 type_val.as_str() == Some("string")
823 || type_val
824 .get("lit")
825 .and_then(|l| l.as_str())
826 .map(|s| s == "string")
827 .unwrap_or(false)
828}
829
830fn try_extract_regexp_replace_strip_fraction_source(
833 v: &Value,
834) -> Result<Option<crate::Column>, PlanExprError> {
835 fn value_as_str(val: &Value) -> Option<String> {
836 val.as_str()
837 .map(String::from)
838 .or_else(|| val.get("lit").and_then(|l| l.as_str()).map(String::from))
839 }
840 if !is_cast_to_string(v) {
841 return Ok(None);
842 }
843 let cast_args = match v.get("args").and_then(|a| a.as_array()) {
844 Some(a) if !a.is_empty() => a,
845 _ => return Ok(None),
846 };
847 let inner = match cast_args.first() {
848 Some(x) => x,
849 None => return Ok(None),
850 };
851 let obj = match inner.as_object() {
852 Some(o) => o,
853 None => return Ok(None),
854 };
855 let (source_val, pattern_opt, replacement_opt) =
856 if obj.get("fn").and_then(|f| f.as_str()) == Some("regexp_replace") {
857 let args = match obj.get("args").and_then(|a| a.as_array()) {
858 Some(a) if a.len() >= 3 => a,
859 _ => return Ok(None),
860 };
861 let pattern_opt = value_as_str(&args[1]);
862 let replacement_opt = value_as_str(&args[2]);
863 (args[0].clone(), pattern_opt, replacement_opt)
864 } else if obj.get("op").and_then(|o| o.as_str()) == Some("regexp_replace") {
865 let source_val = match obj.get("left") {
866 Some(s) => s.clone(),
867 None => return Ok(None),
868 };
869 let pattern_opt = obj
870 .get("pattern")
871 .or_else(|| obj.get("right"))
872 .and_then(value_as_str);
873 let replacement_opt = obj.get("replacement").and_then(value_as_str);
874 (source_val, pattern_opt, replacement_opt)
875 } else {
876 return Ok(None);
877 };
878 if pattern_opt.as_deref() != Some(r"\.\d+") || replacement_opt.as_deref() != Some("") {
879 return Ok(None);
880 }
881 let col = expr_to_column(expr_from_value(&source_val)?);
882 Ok(Some(col))
883}
884
885fn lit_as_string(v: &Value) -> Result<String, PlanExprError> {
888 let lit_val = v
889 .get("lit")
890 .ok_or_else(|| PlanExprError("expected literal".to_string()))?;
891 if lit_val.is_null() {
892 return Err(PlanExprError("literal string cannot be null".to_string()));
893 }
894 if let Some(s) = lit_val.as_str() {
895 return Ok(s.to_string());
896 }
897 if let Some(n) = lit_val.as_i64() {
898 return Ok(n.to_string());
899 }
900 if let Some(n) = lit_val.as_f64() {
901 return Ok(n.to_string());
902 }
903 if let Some(b) = lit_val.as_bool() {
904 return Ok(b.to_string());
905 }
906 Err(PlanExprError(
907 "literal must be string, number, or bool".to_string(),
908 ))
909}
910
911fn lit_as_i64(v: &Value) -> Result<i64, PlanExprError> {
912 let lit_val = v
913 .get("lit")
914 .ok_or_else(|| PlanExprError("expected literal".to_string()))?;
915 lit_val
916 .as_i64()
917 .ok_or_else(|| PlanExprError("literal must be integer".to_string()))
918}
919
920fn lit_as_i32(v: &Value) -> Result<i32, PlanExprError> {
921 let n = lit_as_i64(v)?;
922 n.try_into()
923 .map_err(|_| PlanExprError("literal out of i32 range".to_string()))
924}
925
926fn lit_as_u32(v: &Value) -> Result<u32, PlanExprError> {
927 let lit_val = v
928 .get("lit")
929 .ok_or_else(|| PlanExprError("expected literal".to_string()))?;
930 if let Some(n) = lit_val.as_u64() {
931 return n
932 .try_into()
933 .map_err(|_| PlanExprError("literal out of u32 range".to_string()));
934 }
935 if let Some(n) = lit_val.as_i64() {
936 return (n as u64)
937 .try_into()
938 .map_err(|_| PlanExprError("literal out of u32 range".to_string()));
939 }
940 Err(PlanExprError("literal must be number".to_string()))
941}
942
943fn lit_as_f64(v: &Value) -> Result<f64, PlanExprError> {
944 let lit_val = v
945 .get("lit")
946 .ok_or_else(|| PlanExprError("expected literal".to_string()))?;
947 if let Some(n) = lit_val.as_f64() {
948 return Ok(n);
949 }
950 if let Some(n) = lit_val.as_i64() {
951 return Ok(n as f64);
952 }
953 Err(PlanExprError("literal must be number".to_string()))
954}
955
956#[allow(dead_code)]
957fn lit_as_bool(v: &Value) -> Result<bool, PlanExprError> {
958 let lit_val = v
959 .get("lit")
960 .ok_or_else(|| PlanExprError("expected literal".to_string()))?;
961 lit_val
962 .as_bool()
963 .ok_or_else(|| PlanExprError("literal must be boolean".to_string()))
964}
965
966fn lit_as_usize(v: &Value) -> Result<usize, PlanExprError> {
967 let n = lit_as_i64(v)?;
968 if n < 0 {
969 return Err(PlanExprError(
970 "literal must be non-negative for usize".to_string(),
971 ));
972 }
973 n.try_into()
974 .map_err(|_| PlanExprError("literal out of usize range".to_string()))
975}
976
977fn try_values_for_isin(arr: &[Value]) -> Result<Option<Expr>, PlanExprError> {
983 if arr.is_empty() {
984 return Ok(None);
985 }
986 let mut str_vals: Vec<String> = Vec::new();
987 for v in arr {
988 let lit_val = if let Some(obj) = v.as_object() {
989 obj.get("lit").unwrap_or(v)
990 } else {
991 v
992 };
993 if lit_val.is_null() {
994 continue;
995 }
996 if let Some(s) = lit_val.as_str() {
997 str_vals.push(s.to_string());
998 } else if let Some(n) = lit_val.as_i64() {
999 str_vals.push(n.to_string());
1000 } else if let Some(n) = lit_val.as_f64() {
1001 str_vals.push(n.to_string());
1002 }
1003 }
1004 if str_vals.is_empty() {
1005 return Ok(None);
1006 }
1007 let s: Series = Series::from_iter(str_vals.iter().map(|x| x.as_str()));
1010 Ok(Some(lit(s)))
1011}
1012
1013fn try_values_from_plan_value(v: &Value) -> Result<Option<Expr>, PlanExprError> {
1015 if let Some(lit_val) = v.get("lit") {
1016 if let Some(arr) = lit_val.as_array() {
1017 return try_values_for_isin(arr);
1018 }
1019 #[allow(clippy::cloned_ref_to_slice_refs)]
1021 return try_values_for_isin(&[v.clone()]);
1022 }
1023 if let Some(arr) = v.as_array() {
1024 return try_values_for_isin(arr);
1025 }
1026 Err(PlanExprError(
1027 "isin right/values must be array or {lit: [...]}".to_string(),
1028 ))
1029}
1030
1031fn arg_lit_opt_str(args: &[Value], i: usize) -> Result<Option<String>, PlanExprError> {
1033 let v = match args.get(i) {
1034 Some(x) => x,
1035 None => return Ok(None),
1036 };
1037 if v.is_null() {
1038 return Ok(None);
1039 }
1040 if let Some(obj) = v.as_object() {
1041 if obj.get("lit").is_some() {
1042 return Ok(Some(lit_as_string(v)?));
1043 }
1044 }
1045 Ok(None)
1046}
1047
1048fn arg_expr(args: &[Value], i: usize) -> Result<Expr, PlanExprError> {
1049 let v = args
1050 .get(i)
1051 .ok_or_else(|| PlanExprError(format!("fn requires argument at index {i}")))?;
1052 expr_from_value(v)
1053}
1054
1055fn arg_lit_str(args: &[Value], i: usize) -> Result<String, PlanExprError> {
1057 let v = args
1058 .get(i)
1059 .ok_or_else(|| PlanExprError(format!("fn requires string literal at index {i}")))?;
1060 if let Some(s) = v.as_str() {
1061 return Ok(s.to_string());
1062 }
1063 lit_as_string(v)
1064}
1065
1066fn arg_lit_i64(args: &[Value], i: usize) -> Result<i64, PlanExprError> {
1067 let v = args
1068 .get(i)
1069 .ok_or_else(|| PlanExprError(format!("fn requires integer literal at index {i}")))?;
1070 lit_as_i64(v)
1071}
1072
1073fn arg_lit_i32(args: &[Value], i: usize) -> Result<i32, PlanExprError> {
1074 let v = args
1075 .get(i)
1076 .ok_or_else(|| PlanExprError(format!("fn requires integer literal at index {i}")))?;
1077 lit_as_i32(v)
1078}
1079
1080fn arg_lit_u32(args: &[Value], i: usize) -> Result<u32, PlanExprError> {
1081 let v = args
1082 .get(i)
1083 .ok_or_else(|| PlanExprError(format!("fn requires non-negative integer at index {i}")))?;
1084 lit_as_u32(v)
1085}
1086
1087fn arg_lit_f64(args: &[Value], i: usize) -> Result<f64, PlanExprError> {
1088 let v = args
1089 .get(i)
1090 .ok_or_else(|| PlanExprError(format!("fn requires number literal at index {i}")))?;
1091 lit_as_f64(v)
1092}
1093
1094fn arg_lit_usize(args: &[Value], i: usize) -> Result<usize, PlanExprError> {
1096 let v = args
1097 .get(i)
1098 .ok_or_else(|| PlanExprError(format!("fn requires non-negative integer at index {i}")))?;
1099 if let Some(n) = v.as_i64() {
1100 if n < 0 {
1101 return Err(PlanExprError(
1102 "literal must be non-negative for usize".to_string(),
1103 ));
1104 }
1105 return n
1106 .try_into()
1107 .map_err(|_| PlanExprError("literal out of usize range".to_string()));
1108 }
1109 if let Some(n) = v.as_u64() {
1110 return n
1111 .try_into()
1112 .map_err(|_| PlanExprError("literal out of usize range".to_string()));
1113 }
1114 lit_as_usize(v)
1115}
1116
1117fn opt_lit_i64(args: &[Value], i: usize) -> Option<i64> {
1119 let v = args.get(i)?;
1120 v.get("lit").and_then(Value::as_i64)
1121}
1122
1123#[allow(dead_code)]
1125fn opt_lit_u64(args: &[Value], i: usize) -> Option<u64> {
1126 let v = args.get(i)?;
1127 if let Some(n) = v.get("lit").and_then(Value::as_i64) {
1128 if n >= 0 {
1129 return Some(n as u64);
1130 }
1131 return Some((-n) as u64); }
1133 v.get("lit").and_then(Value::as_u64)
1134}
1135
1136fn expr_to_column(expr: Expr) -> crate::Column {
1137 crate::Column::from_expr(expr, None)
1138}
1139
1140fn eq_null_safe_expr(left: Expr, right: Expr) -> Result<Expr, PlanExprError> {
1143 use polars::prelude::*;
1144 let (left_c, right_c) = crate::type_coercion::coerce_for_pyspark_eq_null_safe(left, right)
1145 .map_err(|e| PlanExprError(e.to_string()))?;
1146 let left_null = left_c.clone().is_null();
1147 let right_null = right_c.clone().is_null();
1148 let both_null = left_null.clone().and(right_null.clone());
1149 let both_non_null = left_null.not().and(right_null.not());
1150 let eq_result = left_c.eq(right_c);
1151 Ok(when(both_null)
1152 .then(lit(true))
1153 .when(both_non_null)
1154 .then(eq_result)
1155 .otherwise(lit(false)))
1156}
1157
1158fn matching_paren(s: &str, start: usize) -> Option<usize> {
1160 if s.as_bytes().get(start) != Some(&b'(') {
1161 return None;
1162 }
1163 let mut depth = 1u32;
1164 for (i, b) in s.bytes().enumerate().skip(start + 1) {
1165 match b {
1166 b'(' => depth += 1,
1167 b')' => {
1168 depth -= 1;
1169 if depth == 0 {
1170 return Some(i);
1171 }
1172 }
1173 _ => {}
1174 }
1175 }
1176 None
1177}
1178
1179fn concat_part_to_expr(part: &str) -> Expr {
1181 let part = part.trim();
1182 if part.is_empty() {
1183 return lit("");
1184 }
1185 if (part.starts_with('"') && part.ends_with('"'))
1186 || (part.starts_with('\'') && part.ends_with('\''))
1187 {
1188 let inner = part[1..part.len() - 1].trim_matches(['\'', '"']);
1189 return lit(inner);
1190 }
1191 col(part)
1192}
1193
1194pub fn try_parse_concat_expr_from_string(s: &str) -> Option<Expr> {
1198 use polars::prelude::concat_str;
1199 let s = s.trim();
1200 if s.starts_with("concat(") {
1202 let close = matching_paren(s, 6)?; if close != s.len() - 1 {
1204 return None;
1205 }
1206 let inner = s[7..close].trim();
1207 let parts: Vec<&str> = inner.split(',').map(str::trim).collect();
1208 if parts.is_empty() {
1209 return None;
1210 }
1211 let exprs: Vec<Expr> = parts.iter().map(|p| concat_part_to_expr(p)).collect();
1212 return Some(concat_str(&exprs, "", false));
1213 }
1214 if s.starts_with("concat_ws(") {
1216 let close = matching_paren(s, 10)?; if close != s.len() - 1 {
1218 return None;
1219 }
1220 let inner = s[10..close].trim();
1221 let parts: Vec<&str> = inner.split(',').map(str::trim).collect();
1222 if parts.len() < 2 {
1223 return None;
1224 }
1225 let sep = parts[0].trim_matches(['\'', '"']);
1226 let exprs: Vec<Expr> = parts
1227 .iter()
1228 .skip(1)
1229 .map(|p| concat_part_to_expr(p))
1230 .collect();
1231 if exprs.is_empty() {
1232 return None;
1233 }
1234 return Some(concat_str(&exprs, sep, false));
1235 }
1236 None
1237}
1238
1239pub fn column_from_udf_call(
1242 udf_name: &str,
1243 args: &[Value],
1244) -> Result<crate::Column, PlanExprError> {
1245 use crate::Column;
1246 let cols: Vec<Column> = args
1247 .iter()
1248 .map(|v| expr_from_value(v).map(expr_to_column))
1249 .collect::<Result<Vec<_>, _>>()?;
1250 crate::functions::call_udf(udf_name, &cols).map_err(|e| PlanExprError(e.to_string()))
1251}
1252
1253pub fn try_column_from_udf_value(v: &Value) -> Option<Result<crate::Column, PlanExprError>> {
1256 let obj = v.as_object()?;
1257 let (udf_name, args) = if let Some(name) = obj.get("udf").and_then(Value::as_str) {
1258 let args = obj.get("args")?.as_array()?;
1259 (name.to_string(), args)
1260 } else if obj.get("fn").and_then(Value::as_str) == Some("call_udf") {
1261 let args = obj.get("args")?.as_array()?;
1262 if args.is_empty() {
1263 return Some(Err(PlanExprError(
1264 "call_udf requires at least name and one arg".into(),
1265 )));
1266 }
1267 let name = match lit_as_string(&args[0]) {
1268 Ok(n) => n,
1269 Err(e) => return Some(Err(e)),
1270 };
1271 let rest: &[Value] = &args[1..];
1272 return Some(column_from_udf_call(&name, rest));
1273 } else {
1274 return None;
1275 };
1276 Some(column_from_udf_call(&udf_name, args))
1277}
1278
1279fn expr_from_fn(name: &str, args: &[Value]) -> Result<Expr, PlanExprError> {
1280 use crate::Column;
1281 #[allow(unused_imports)]
1282 use crate::functions::{
1283 add_months, array_agg, array_append, array_compact, array_contains, array_distinct,
1284 array_except, array_insert, array_intersect, array_join, array_prepend, array_remove,
1285 array_slice, array_sort, array_sum, array_union, arrays_overlap, arrays_zip, ascii,
1286 assert_true, atan2, base64, bin, bit_and, bit_count, bit_get, bit_length, bit_or, bit_xor,
1287 bitwise_not, bround, btrim, cast, cbrt, ceiling, char as rs_char, chr, coalesce, concat,
1288 concat_ws, contains, conv, cos, cosh, cot, crc32, csc, curdate, current_catalog,
1289 current_database, current_date, current_schema, current_timestamp, current_timezone,
1290 current_user, date_add, date_diff, date_format, date_from_unix_date, date_part, date_sub,
1291 date_trunc, dateadd, datediff, datepart, day, dayname, dayofmonth, dayofweek, dayofyear,
1292 days, decode, degrees, e, element_at, elt, encode, endswith, equal_null, exp,
1293 explode_outer, extract, factorial, find_in_set, floor, format_number, format_string,
1294 from_unixtime, from_utc_timestamp, get, get_json_object, getbit, greatest, hash, hex, hour,
1295 hypot, ilike, initcap, input_file_name, instr, isnan, json_tuple, last_day, lcase, least,
1296 left, length, like, lit_str, ln, localtimestamp, locate, log, log1p, log2, log10, lower,
1297 lpad, make_date, make_interval, make_timestamp, make_timestamp_ntz, mask, md5, minute,
1298 monotonically_increasing_id, month, months_between, nanvl, negate, negative, next_day, now,
1299 nullif, nvl, nvl2, octet_length, overlay, parse_url, pi, pmod, positive, pow, power,
1300 quarter, radians, raise_error, rand, randn, regexp, regexp_count, regexp_extract,
1301 regexp_extract_all, regexp_instr, regexp_like, regexp_replace, regexp_substr, repeat,
1302 replace, reverse, right, rint, rlike, round, rpad, sec, second, sha1, sha2, shift_left,
1303 shift_right, signum, sin, sinh, size, soundex, spark_partition_id, split, split_part, sqrt,
1304 startswith, str_to_map, struct_, substr, substring, substring_index, tan, tanh,
1305 timestamp_micros, timestamp_millis, timestamp_seconds, timestampadd, timestampdiff,
1306 to_binary, to_char, to_date, to_degrees, to_radians, to_timestamp,
1307 to_timestamp_fused_strip_fraction, to_unix_timestamp, to_utc_timestamp, to_varchar,
1308 translate, trim, trunc, try_add, try_cast, try_divide, try_element_at, try_multiply,
1309 try_subtract, try_to_binary, try_to_number, try_to_timestamp, typeof_, ucase, unbase64,
1310 unhex, unix_date, unix_micros, unix_millis, unix_seconds, unix_timestamp,
1311 unix_timestamp_now, upper, url_decode, url_encode, user, version, weekday, weekofyear,
1312 when_then_otherwise_null, width_bucket, xxhash64, year,
1313 };
1314
1315 match name {
1316 "call_udf" => {
1317 if args.is_empty() {
1318 return Err(PlanExprError(
1319 "call_udf requires at least name and one arg".into(),
1320 ));
1321 }
1322 let udf_name = lit_as_string(&args[0])?;
1323 let col = column_from_udf_call(&udf_name, &args[1..])?;
1324 if col.udf_call.is_some() {
1325 return Err(PlanExprError(
1326 "Python/Vectorized UDFs are only supported in withColumn/select, not in filter/plan expressions"
1327 .into(),
1328 ));
1329 }
1330 Ok(col.expr().clone())
1331 }
1332 "upper" => {
1333 require_args(name, args, 1)?;
1334 let c = expr_to_column(arg_expr(args, 0)?);
1335 Ok(upper(&c).into_expr())
1336 }
1337 "lower" => {
1338 require_args(name, args, 1)?;
1339 let c = expr_to_column(arg_expr(args, 0)?);
1340 Ok(lower(&c).into_expr())
1341 }
1342 "coalesce" => {
1343 if args.is_empty() {
1344 return Err(PlanExprError(format!(
1345 "fn '{name}' requires at least one argument"
1346 )));
1347 }
1348 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
1349 let exprs = exprs?;
1350 Ok(polars::prelude::coalesce(&exprs))
1351 }
1352 "when" => {
1353 if args.len() != 2 {
1354 return Err(PlanExprError(format!(
1355 "fn '{name}' two-arg form requires [condition, then_expr]"
1356 )));
1357 }
1358 let cond_expr = crate::functions::expr_coerce_to_boolean(arg_expr(args, 0)?);
1360 let cond = expr_to_column(cond_expr);
1361 let then_val = expr_to_column(arg_expr(args, 1)?);
1362 Ok(when_then_otherwise_null(&cond, &then_val).into_expr())
1363 }
1364 "assert_true" => {
1365 require_args_min(name, args, 1)?;
1367 let cond_expr = crate::functions::expr_coerce_to_boolean(arg_expr(args, 0)?);
1368 let c = expr_to_column(cond_expr);
1369 let err_msg_opt: Option<String> = arg_lit_opt_str(args, 1)?;
1370 let err_msg = err_msg_opt.as_deref();
1371 Ok(assert_true(&c, err_msg).into_expr())
1372 }
1373 "length" | "char_length" | "character_length" => {
1375 require_args(name, args, 1)?;
1376 Ok(length(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1377 }
1378 "trim" => {
1379 require_args(name, args, 1)?;
1380 Ok(trim(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1381 }
1382 "ltrim" => {
1383 require_args(name, args, 1)?;
1384 Ok(crate::functions::ltrim(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1385 }
1386 "rtrim" => {
1387 require_args(name, args, 1)?;
1388 Ok(crate::functions::rtrim(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1389 }
1390 "btrim" => {
1391 require_args_min(name, args, 1)?;
1392 let c = expr_to_column(arg_expr(args, 0)?);
1393 let trim_str: Option<String> = arg_lit_opt_str(args, 1)?;
1394 Ok(btrim(&c, trim_str.as_deref()).into_expr())
1395 }
1396 "substring" | "substr" => {
1397 require_args_min(name, args, 2)?;
1398 let c = expr_to_column(arg_expr(args, 0)?);
1399 let start = arg_lit_i64(args, 1)?;
1400 let len = opt_lit_i64(args, 2);
1401 Ok(substring(&c, start, len).into_expr())
1402 }
1403 "concat" => {
1404 if args.is_empty() {
1405 return Err(PlanExprError(format!(
1406 "fn '{name}' requires at least one argument"
1407 )));
1408 }
1409 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
1410 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
1411 let refs: Vec<&Column> = cols.iter().collect();
1412 Ok(concat(&refs).into_expr())
1413 }
1414 "concat_ws" => {
1415 require_args_min(name, args, 2)?;
1416 let sep = arg_lit_str(args, 0)?;
1417 let exprs: Result<Vec<Expr>, _> = args.iter().skip(1).map(expr_from_value).collect();
1418 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
1419 let refs: Vec<&Column> = cols.iter().collect();
1420 Ok(concat_ws(&sep, &refs).into_expr())
1421 }
1422 "initcap" => {
1423 require_args(name, args, 1)?;
1424 Ok(initcap(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1425 }
1426 "repeat" => {
1427 require_args(name, args, 2)?;
1428 let c = expr_to_column(arg_expr(args, 0)?);
1429 let n = arg_lit_i32(args, 1)?;
1430 Ok(repeat(&c, n).into_expr())
1431 }
1432 "reverse" => {
1433 require_args(name, args, 1)?;
1434 Ok(reverse(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1435 }
1436 "instr" => {
1437 require_args(name, args, 2)?;
1438 let c = expr_to_column(arg_expr(args, 0)?);
1439 let substr = arg_lit_str(args, 1)?;
1440 Ok(instr(&c, &substr).into_expr())
1441 }
1442 "position" => {
1443 require_args_min(name, args, 2)?;
1444 let substr = arg_lit_str(args, 0)?;
1445 let c = expr_to_column(arg_expr(args, 1)?);
1446 let pos = opt_lit_i64(args, 2).unwrap_or(1);
1447 Ok(locate(&substr, &c, pos).into_expr())
1448 }
1449 "locate" => {
1450 require_args_min(name, args, 2)?;
1451 let substr = arg_lit_str(args, 0)?;
1452 let c = expr_to_column(arg_expr(args, 1)?);
1453 let pos = opt_lit_i64(args, 2).unwrap_or(1);
1454 Ok(locate(&substr, &c, pos).into_expr())
1455 }
1456 "ascii" => {
1457 require_args(name, args, 1)?;
1458 Ok(ascii(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1459 }
1460 "format_number" => {
1461 require_args(name, args, 2)?;
1462 let c = expr_to_column(arg_expr(args, 0)?);
1463 let decimals = arg_lit_u32(args, 1)?;
1464 Ok(format_number(&c, decimals).into_expr())
1465 }
1466 "overlay" => {
1467 require_args_min(name, args, 4)?;
1468 let c = expr_to_column(arg_expr(args, 0)?);
1469 let replace_str = arg_lit_str(args, 1)?;
1470 let pos = arg_lit_i64(args, 2)?;
1471 let len = arg_lit_i64(args, 3)?;
1472 Ok(overlay(&c, &replace_str, pos, len).into_expr())
1473 }
1474 "char" => {
1475 require_args(name, args, 1)?;
1476 Ok(rs_char(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1477 }
1478 "chr" => {
1479 require_args(name, args, 1)?;
1480 Ok(chr(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1481 }
1482 "base64" => {
1483 require_args(name, args, 1)?;
1484 Ok(base64(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1485 }
1486 "unbase64" => {
1487 require_args(name, args, 1)?;
1488 Ok(unbase64(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1489 }
1490 "sha1" => {
1491 require_args(name, args, 1)?;
1492 Ok(sha1(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1493 }
1494 "sha2" => {
1495 require_args(name, args, 2)?;
1496 let c = expr_to_column(arg_expr(args, 0)?);
1497 let bits = arg_lit_i32(args, 1)?;
1498 Ok(sha2(&c, bits).into_expr())
1499 }
1500 "md5" => {
1501 require_args(name, args, 1)?;
1502 Ok(md5(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1503 }
1504 "lpad" => {
1505 require_args(name, args, 3)?;
1506 let c = expr_to_column(arg_expr(args, 0)?);
1507 let len = arg_lit_i32(args, 1)?;
1508 let pad = arg_lit_str(args, 2)?;
1509 Ok(lpad(&c, len, &pad).into_expr())
1510 }
1511 "rpad" => {
1512 require_args(name, args, 3)?;
1513 let c = expr_to_column(arg_expr(args, 0)?);
1514 let len = arg_lit_i32(args, 1)?;
1515 let pad = arg_lit_str(args, 2)?;
1516 Ok(rpad(&c, len, &pad).into_expr())
1517 }
1518 "translate" => {
1519 require_args(name, args, 3)?;
1520 let c = expr_to_column(arg_expr(args, 0)?);
1521 let from_str = arg_lit_str(args, 1)?;
1522 let to_str = arg_lit_str(args, 2)?;
1523 Ok(translate(&c, &from_str, &to_str).into_expr())
1524 }
1525 "substring_index" => {
1526 require_args(name, args, 3)?;
1527 let c = expr_to_column(arg_expr(args, 0)?);
1528 let delim = arg_lit_str(args, 1)?;
1529 let count = arg_lit_i64(args, 2)?;
1530 Ok(substring_index(&c, &delim, count).into_expr())
1531 }
1532 "left" => {
1533 require_args(name, args, 2)?;
1534 let c = expr_to_column(arg_expr(args, 0)?);
1535 let n = arg_lit_i64(args, 1)?;
1536 Ok(left(&c, n).into_expr())
1537 }
1538 "right" => {
1539 require_args(name, args, 2)?;
1540 let c = expr_to_column(arg_expr(args, 0)?);
1541 let n = arg_lit_i64(args, 1)?;
1542 Ok(right(&c, n).into_expr())
1543 }
1544 "replace" => {
1545 require_args(name, args, 3)?;
1546 let c = expr_to_column(arg_expr(args, 0)?);
1547 let search = arg_lit_str(args, 1)?;
1548 let replacement = arg_lit_str(args, 2)?;
1549 Ok(replace(&c, &search, &replacement).into_expr())
1550 }
1551 "startswith" => {
1552 require_args(name, args, 2)?;
1553 let c = expr_to_column(arg_expr(args, 0)?);
1554 let prefix = arg_lit_str(args, 1)?;
1555 Ok(startswith(&c, &prefix).into_expr())
1556 }
1557 "endswith" => {
1558 require_args(name, args, 2)?;
1559 let c = expr_to_column(arg_expr(args, 0)?);
1560 let suffix = arg_lit_str(args, 1)?;
1561 Ok(endswith(&c, &suffix).into_expr())
1562 }
1563 "contains" => {
1564 require_args(name, args, 2)?;
1565 let c = expr_to_column(arg_expr(args, 0)?);
1566 let substring = arg_lit_str(args, 1)?;
1567 Ok(contains(&c, &substring).into_expr())
1568 }
1569 "like" => {
1570 require_args_min(name, args, 2)?;
1571 let c = expr_to_column(arg_expr(args, 0)?);
1572 let pattern = arg_lit_str(args, 1)?;
1573 let escape = arg_lit_opt_str(args, 2)?.and_then(|s| s.chars().next());
1574 Ok(like(&c, &pattern, escape).into_expr())
1575 }
1576 "ilike" => {
1577 require_args_min(name, args, 2)?;
1578 let c = expr_to_column(arg_expr(args, 0)?);
1579 let pattern = arg_lit_str(args, 1)?;
1580 let escape = arg_lit_opt_str(args, 2)?.and_then(|s| s.chars().next());
1581 Ok(ilike(&c, &pattern, escape).into_expr())
1582 }
1583 "rlike" | "regexp" => {
1584 require_args(name, args, 2)?;
1585 let c = expr_to_column(arg_expr(args, 0)?);
1586 let pattern = arg_lit_str(args, 1)?;
1587 Ok(rlike(&c, &pattern).into_expr())
1588 }
1589 "soundex" => {
1590 require_args(name, args, 1)?;
1591 Ok(soundex(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1592 }
1593 "levenshtein" => {
1594 require_args(name, args, 2)?;
1595 let a = expr_to_column(arg_expr(args, 0)?);
1596 let b = expr_to_column(arg_expr(args, 1)?);
1597 Ok(crate::functions::levenshtein(&a, &b).into_expr())
1598 }
1599 "crc32" => {
1600 require_args(name, args, 1)?;
1601 Ok(crc32(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1602 }
1603 "xxhash64" => {
1604 require_args(name, args, 1)?;
1605 Ok(xxhash64(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1606 }
1607 "regexp_extract" => {
1608 require_args(name, args, 3)?;
1610 let c = expr_to_column(arg_expr(args, 0)?);
1611 let pattern = arg_lit_str(args, 1).map_err(|_| {
1612 PlanExprError(
1613 "regexp_extract in plan requires literal pattern at arg 2 (column refs not supported)".into(),
1614 )
1615 })?;
1616 let group_index = arg_lit_usize(args, 2).map_err(|_| {
1617 PlanExprError(
1618 "regexp_extract in plan requires literal group index at arg 3 (column refs not supported)".into(),
1619 )
1620 })?;
1621 Ok(regexp_extract(&c, &pattern, group_index).into_expr())
1622 }
1623 "regexp_replace" => {
1624 require_args(name, args, 3)?;
1625 let c = expr_to_column(arg_expr(args, 0)?);
1626 let pattern = arg_lit_str(args, 1)?;
1627 let replacement = arg_lit_str(args, 2)?;
1628 Ok(regexp_replace(&c, &pattern, &replacement).into_expr())
1629 }
1630 "regexp_extract_all" => {
1631 require_args(name, args, 2)?;
1632 let c = expr_to_column(arg_expr(args, 0)?);
1633 let pattern = arg_lit_str(args, 1)?;
1634 Ok(regexp_extract_all(&c, &pattern).into_expr())
1635 }
1636 "regexp_like" => {
1637 require_args(name, args, 2)?;
1638 let c = expr_to_column(arg_expr(args, 0)?);
1639 let pattern = arg_lit_str(args, 1)?;
1640 Ok(regexp_like(&c, &pattern).into_expr())
1641 }
1642 "regexp_count" => {
1643 require_args(name, args, 2)?;
1644 let c = expr_to_column(arg_expr(args, 0)?);
1645 let pattern = arg_lit_str(args, 1)?;
1646 Ok(regexp_count(&c, &pattern).into_expr())
1647 }
1648 "regexp_substr" => {
1649 require_args(name, args, 2)?;
1650 let c = expr_to_column(arg_expr(args, 0)?);
1651 let pattern = arg_lit_str(args, 1)?;
1652 Ok(regexp_substr(&c, &pattern).into_expr())
1653 }
1654 "regexp_instr" => {
1655 require_args_min(name, args, 2)?;
1656 let c = expr_to_column(arg_expr(args, 0)?);
1657 let pattern = arg_lit_str(args, 1)?;
1658 let group_idx = args.get(2).and_then(|v| lit_as_usize(v).ok());
1659 Ok(regexp_instr(&c, &pattern, group_idx).into_expr())
1660 }
1661 "split" => {
1662 require_args_min(name, args, 2)?;
1663 if args.len() > 3 {
1664 return Err(PlanExprError("split takes at most 3 arguments".to_string()));
1665 }
1666 let c = expr_to_column(arg_expr(args, 0)?);
1667 let delimiter = arg_lit_str(args, 1)?;
1668 let limit = args
1669 .get(2)
1670 .and_then(|v| lit_as_i64(v).ok())
1671 .map(|n| n as i32);
1672 Ok(split(&c, &delimiter, limit).into_expr())
1673 }
1674 "split_part" => {
1675 require_args(name, args, 3)?;
1676 let c = expr_to_column(arg_expr(args, 0)?);
1677 let delimiter = arg_lit_str(args, 1)?;
1678 let part_num = arg_lit_i64(args, 2)?;
1679 Ok(split_part(&c, &delimiter, part_num).into_expr())
1680 }
1681 "find_in_set" => {
1682 require_args(name, args, 2)?;
1683 let str_col = expr_to_column(arg_expr(args, 0)?);
1684 let set_col = expr_to_column(arg_expr(args, 1)?);
1685 Ok(find_in_set(&str_col, &set_col).into_expr())
1686 }
1687 "format_string" | "printf" => {
1688 require_args_min(name, args, 2)?;
1689 let format_str = arg_lit_str(args, 0)?;
1690 let exprs: Result<Vec<Expr>, _> = args.iter().skip(1).map(expr_from_value).collect();
1691 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
1692 let refs: Vec<&Column> = cols.iter().collect();
1693 Ok(format_string(&format_str, &refs).into_expr())
1694 }
1695 "lcase" => {
1696 require_args(name, args, 1)?;
1697 Ok(lcase(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1698 }
1699 "ucase" => {
1700 require_args(name, args, 1)?;
1701 Ok(ucase(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1702 }
1703 "mask" => {
1704 require_args_min(name, args, 1)?;
1705 let c = expr_to_column(arg_expr(args, 0)?);
1706 let u = args
1707 .get(1)
1708 .and_then(|v| lit_as_string(v).ok())
1709 .and_then(|s| s.chars().next());
1710 let l = args
1711 .get(2)
1712 .and_then(|v| lit_as_string(v).ok())
1713 .and_then(|s| s.chars().next());
1714 let d = args
1715 .get(3)
1716 .and_then(|v| lit_as_string(v).ok())
1717 .and_then(|s| s.chars().next());
1718 let o = args
1719 .get(4)
1720 .and_then(|v| lit_as_string(v).ok())
1721 .and_then(|s| s.chars().next());
1722 Ok(mask(&c, u, l, d, o).into_expr())
1723 }
1724 "str_to_map" => {
1725 require_args_min(name, args, 1)?;
1726 let c = expr_to_column(arg_expr(args, 0)?);
1727 let pair_delim: Option<String> = arg_lit_opt_str(args, 1)?;
1728 let key_value_delim: Option<String> = arg_lit_opt_str(args, 2)?;
1729 Ok(str_to_map(&c, pair_delim.as_deref(), key_value_delim.as_deref()).into_expr())
1730 }
1731 "get_json_object" => {
1732 require_args(name, args, 2)?;
1733 let c = expr_to_column(arg_expr(args, 0)?);
1734 let path = arg_lit_str(args, 1)?;
1735 Ok(get_json_object(&c, &path).into_expr())
1736 }
1737 "json_tuple" => {
1738 require_args_min(name, args, 2)?;
1739 let c = expr_to_column(arg_expr(args, 0)?);
1740 let keys: Vec<String> = args[1..]
1741 .iter()
1742 .map(lit_as_string)
1743 .collect::<Result<Vec<_>, _>>()?;
1744 let key_refs: Vec<&str> = keys.iter().map(String::as_str).collect();
1745 Ok(json_tuple(&c, &key_refs).into_expr())
1746 }
1747 "isin" => {
1748 require_args_min(name, args, 1)?;
1752 let col_expr = arg_expr(args, 0)?;
1753 let values_opt = try_values_for_isin(&args[1..])?;
1754 Ok(match values_opt {
1755 None => lit(false),
1756 Some(values_expr) => {
1757 col_expr
1759 .cast(DataType::String)
1760 .is_in(values_expr.implode(), false)
1761 }
1762 })
1763 }
1764 _ => expr_from_fn_rest(name, args),
1765 }
1766}
1767
1768fn expr_from_fn_rest(name: &str, args: &[Value]) -> Result<Expr, PlanExprError> {
1769 use crate::Column;
1770 #[allow(unused_imports)]
1771 use crate::functions::{
1772 abs, acos, add_months, array, array_agg, array_append, array_compact, array_contains,
1773 array_distinct, array_except, array_insert, array_intersect, array_join, array_max,
1774 array_min, array_prepend, array_remove, array_size, array_slice, array_sort, array_sum,
1775 array_union, arrays_overlap, arrays_zip, asin, atan, atan2, bround, cast, cbrt, ceiling,
1776 cos, cosh, cot, create_map, csc, curdate, current_catalog, current_database, current_date,
1777 current_schema, current_timestamp, current_timezone, current_user, date_add, date_diff,
1778 date_format, date_from_unix_date, date_part, date_sub, date_trunc, dateadd, datediff,
1779 datepart, day, dayname, dayofmonth, dayofweek, dayofyear, days, decode, degrees, e,
1780 element_at, encode, equal_null, exp, explode, explode_outer, expm1, extract, factorial,
1781 floor, from_unixtime, from_utc_timestamp, get, get_json_object, greatest, grouping,
1782 grouping_id, hash, hour, hours, hypot, input_file_name, last_day, least, localtimestamp,
1783 log, log1p, log2, log10, make_date, make_interval, make_timestamp, make_timestamp_ntz,
1784 map_keys, map_values, minute, minutes, monotonically_increasing_id, month, months,
1785 months_between, negate, next_day, now, nullif, nvl, nvl2, parse_url, pi, pmod, positive,
1786 pow, quarter, radians, rint, round, sec, second, shift_left, shift_right, signum, sin,
1787 sinh, size, spark_partition_id, sqrt, tan, tanh, timestamp_micros, timestamp_millis,
1788 timestamp_seconds, timestampadd, timestampdiff, to_binary, to_char, to_date, to_degrees,
1789 to_number, to_radians, to_timestamp, to_timestamp_fused_strip_fraction, to_unix_timestamp,
1790 to_utc_timestamp, to_varchar, trunc, try_add, try_cast, try_divide, try_element_at,
1791 try_multiply, try_subtract, try_to_number, try_to_timestamp, typeof_, unix_date,
1792 unix_micros, unix_millis, unix_seconds, unix_timestamp, unix_timestamp_now, user, weekday,
1793 weekofyear, width_bucket, year, years,
1794 };
1795
1796 match name {
1798 "abs" => {
1799 require_args(name, args, 1)?;
1800 Ok(abs(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1801 }
1802 "ceil" | "ceiling" => {
1803 require_args(name, args, 1)?;
1804 Ok(ceiling(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1805 }
1806 "floor" => {
1807 require_args(name, args, 1)?;
1808 Ok(floor(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1809 }
1810 "round" => {
1811 require_args_min(name, args, 1)?;
1812 let c = expr_to_column(arg_expr(args, 0)?);
1813 let scale = opt_lit_i64(args, 1).unwrap_or(0) as i32;
1814 Ok(round(&c, scale).into_expr())
1815 }
1816 "bround" => {
1817 require_args_min(name, args, 1)?;
1818 let c = expr_to_column(arg_expr(args, 0)?);
1819 let scale = opt_lit_i64(args, 1).unwrap_or(0) as i32;
1820 Ok(bround(&c, scale).into_expr())
1821 }
1822 "negate" | "negative" => {
1823 require_args(name, args, 1)?;
1824 Ok(negate(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1825 }
1826 "positive" => {
1827 require_args(name, args, 1)?;
1828 Ok(positive(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1829 }
1830 "sqrt" => {
1831 require_args(name, args, 1)?;
1832 Ok(sqrt(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1833 }
1834 "pow" | "power" => {
1835 require_args(name, args, 2)?;
1836 let c = expr_to_column(arg_expr(args, 0)?);
1837 let exp_val = arg_lit_i64(args, 1)?;
1838 Ok(pow(&c, exp_val).into_expr())
1839 }
1840 "exp" => {
1841 require_args(name, args, 1)?;
1842 Ok(exp(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1843 }
1844 "log" | "ln" => {
1845 if args.len() == 1 {
1846 Ok(log(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1847 } else if args.len() == 2 {
1848 let col_expr = expr_to_column(arg_expr(args, 0)?);
1849 let base = match &args[1] {
1850 Value::Number(n) => n
1851 .as_f64()
1852 .ok_or_else(|| PlanExprError("log base must be a number".to_string()))?,
1853 _ => return Err(PlanExprError("log base must be a number".to_string())),
1854 };
1855 Ok(crate::functions::log_with_base(&col_expr, base).into_expr())
1856 } else {
1857 Err(PlanExprError(format!(
1858 "fn '{name}' requires 1 or 2 arguments"
1859 )))
1860 }
1861 }
1862 "sin" => {
1863 require_args(name, args, 1)?;
1864 Ok(sin(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1865 }
1866 "cos" => {
1867 require_args(name, args, 1)?;
1868 Ok(cos(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1869 }
1870 "tan" => {
1871 require_args(name, args, 1)?;
1872 Ok(tan(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1873 }
1874 "asin" => {
1875 require_args(name, args, 1)?;
1876 Ok(crate::functions::asin(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1877 }
1878 "acos" => {
1879 require_args(name, args, 1)?;
1880 Ok(crate::functions::acos(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1881 }
1882 "atan" => {
1883 require_args(name, args, 1)?;
1884 Ok(crate::functions::atan(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1885 }
1886 "atan2" => {
1887 require_args(name, args, 2)?;
1888 let y = expr_to_column(arg_expr(args, 0)?);
1889 let x = expr_to_column(arg_expr(args, 1)?);
1890 Ok(atan2(&y, &x).into_expr())
1891 }
1892 "degrees" => {
1893 require_args(name, args, 1)?;
1894 Ok(degrees(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1895 }
1896 "radians" => {
1897 require_args(name, args, 1)?;
1898 Ok(radians(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1899 }
1900 "signum" | "sign" => {
1901 require_args(name, args, 1)?;
1902 Ok(signum(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1903 }
1904 "cot" => {
1905 require_args(name, args, 1)?;
1906 Ok(cot(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1907 }
1908 "csc" => {
1909 require_args(name, args, 1)?;
1910 Ok(csc(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1911 }
1912 "sec" => {
1913 require_args(name, args, 1)?;
1914 Ok(sec(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1915 }
1916 "e" => {
1917 if !args.is_empty() {
1918 return Err(PlanExprError("fn 'e' takes no arguments".to_string()));
1919 }
1920 Ok(e().into_expr())
1921 }
1922 "pi" => {
1923 if !args.is_empty() {
1924 return Err(PlanExprError("fn 'pi' takes no arguments".to_string()));
1925 }
1926 Ok(pi().into_expr())
1927 }
1928 "pmod" => {
1929 require_args(name, args, 2)?;
1930 let a = expr_to_column(arg_expr(args, 0)?);
1931 let b = expr_to_column(arg_expr(args, 1)?);
1932 Ok(pmod(&a, &b).into_expr())
1933 }
1934 "factorial" => {
1935 require_args(name, args, 1)?;
1936 Ok(factorial(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1937 }
1938 "hypot" => {
1939 require_args(name, args, 2)?;
1940 let x = expr_to_column(arg_expr(args, 0)?);
1941 let y = expr_to_column(arg_expr(args, 1)?);
1942 Ok(hypot(&x, &y).into_expr())
1943 }
1944 "cosh" => {
1945 require_args(name, args, 1)?;
1946 Ok(cosh(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1947 }
1948 "sinh" => {
1949 require_args(name, args, 1)?;
1950 Ok(sinh(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1951 }
1952 "tanh" => {
1953 require_args(name, args, 1)?;
1954 Ok(tanh(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1955 }
1956 "cbrt" => {
1957 require_args(name, args, 1)?;
1958 Ok(cbrt(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1959 }
1960 "expm1" => {
1961 require_args(name, args, 1)?;
1962 Ok(crate::functions::expm1(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1963 }
1964 "log1p" => {
1965 require_args(name, args, 1)?;
1966 Ok(log1p(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1967 }
1968 "log10" => {
1969 require_args(name, args, 1)?;
1970 Ok(log10(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1971 }
1972 "log2" => {
1973 require_args(name, args, 1)?;
1974 Ok(log2(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1975 }
1976 "rint" => {
1977 require_args(name, args, 1)?;
1978 Ok(crate::functions::rint(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1979 }
1980 "to_degrees" => {
1981 require_args(name, args, 1)?;
1982 Ok(to_degrees(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1983 }
1984 "to_radians" => {
1985 require_args(name, args, 1)?;
1986 Ok(to_radians(&expr_to_column(arg_expr(args, 0)?)).into_expr())
1987 }
1988 "cast" => {
1990 require_args(name, args, 2)?;
1991 let c = expr_to_column(arg_expr(args, 0)?);
1992 let type_name = arg_lit_str(args, 1)?;
1993 Ok(cast(&c, &type_name).map_err(PlanExprError)?.into_expr())
1994 }
1995 "try_cast" => {
1996 require_args(name, args, 2)?;
1997 let c = expr_to_column(arg_expr(args, 0)?);
1998 let type_name = arg_lit_str(args, 1)?;
1999 Ok(try_cast(&c, &type_name).map_err(PlanExprError)?.into_expr())
2000 }
2001 "astype" => {
2003 require_args(name, args, 2)?;
2004 let c = expr_to_column(arg_expr(args, 0)?);
2005 let type_name = arg_lit_str(args, 1)?;
2006 Ok(try_cast(&c, &type_name).map_err(PlanExprError)?.into_expr())
2007 }
2008 "nvl" | "ifnull" => {
2009 require_args(name, args, 2)?;
2010 let a = expr_to_column(arg_expr(args, 0)?);
2011 let b = expr_to_column(arg_expr(args, 1)?);
2012 Ok(nvl(&a, &b).into_expr())
2013 }
2014 "nullif" => {
2015 require_args(name, args, 2)?;
2016 let a = expr_to_column(arg_expr(args, 0)?);
2017 let b = expr_to_column(arg_expr(args, 1)?);
2018 Ok(nullif(&a, &b).into_expr())
2019 }
2020 "greatest" => {
2021 require_args_min(name, args, 1)?;
2022 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
2023 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
2024 let refs: Vec<&Column> = cols.iter().collect();
2025 Ok(greatest(&refs).map_err(PlanExprError)?.into_expr())
2026 }
2027 "least" => {
2028 require_args_min(name, args, 1)?;
2029 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
2030 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
2031 let refs: Vec<&Column> = cols.iter().collect();
2032 Ok(least(&refs).map_err(PlanExprError)?.into_expr())
2033 }
2034 "typeof" => {
2035 require_args(name, args, 1)?;
2036 Ok(typeof_(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2037 }
2038 "try_divide" => {
2039 require_args(name, args, 2)?;
2040 let a = expr_to_column(arg_expr(args, 0)?);
2041 let b = expr_to_column(arg_expr(args, 1)?);
2042 Ok(try_divide(&a, &b).into_expr())
2043 }
2044 "add" | "+" => {
2046 require_args(name, args, 2)?;
2047 let a = expr_to_column(arg_expr(args, 0)?);
2048 let b = expr_to_column(arg_expr(args, 1)?);
2049 Ok(a.add_pyspark(&b).into_expr())
2050 }
2051 "subtract" | "-" => {
2052 require_args(name, args, 2)?;
2053 let a = expr_to_column(arg_expr(args, 0)?);
2054 let b = expr_to_column(arg_expr(args, 1)?);
2055 Ok(a.subtract_pyspark(&b).into_expr())
2056 }
2057 "multiply" | "*" => {
2058 require_args(name, args, 2)?;
2059 let a = expr_to_column(arg_expr(args, 0)?);
2060 let b = expr_to_column(arg_expr(args, 1)?);
2061 Ok(a.multiply_pyspark(&b).into_expr())
2062 }
2063 "divide" | "/" => {
2064 require_args(name, args, 2)?;
2065 let a = expr_to_column(arg_expr(args, 0)?);
2066 let b = expr_to_column(arg_expr(args, 1)?);
2067 Ok(a.divide_pyspark(&b).into_expr())
2068 }
2069 "mod" | "remainder" | "%" => {
2070 require_args(name, args, 2)?;
2071 let a = expr_to_column(arg_expr(args, 0)?);
2072 let b = expr_to_column(arg_expr(args, 1)?);
2073 Ok(a.mod_pyspark(&b).into_expr())
2074 }
2075 "try_add" => {
2076 require_args(name, args, 2)?;
2077 let a = expr_to_column(arg_expr(args, 0)?);
2078 let b = expr_to_column(arg_expr(args, 1)?);
2079 Ok(try_add(&a, &b).into_expr())
2080 }
2081 "try_subtract" => {
2082 require_args(name, args, 2)?;
2083 let a = expr_to_column(arg_expr(args, 0)?);
2084 let b = expr_to_column(arg_expr(args, 1)?);
2085 Ok(try_subtract(&a, &b).into_expr())
2086 }
2087 "try_multiply" => {
2088 require_args(name, args, 2)?;
2089 let a = expr_to_column(arg_expr(args, 0)?);
2090 let b = expr_to_column(arg_expr(args, 1)?);
2091 Ok(try_multiply(&a, &b).into_expr())
2092 }
2093 "width_bucket" => {
2094 require_args(name, args, 4)?;
2095 let val = expr_to_column(arg_expr(args, 0)?);
2096 let min_val = arg_lit_f64(args, 1)?;
2097 let max_val = arg_lit_f64(args, 2)?;
2098 let num_bucket = arg_lit_i64(args, 3)?;
2099 if num_bucket <= 0 {
2100 return Err(PlanExprError(
2101 "width_bucket: num_bucket must be positive".into(),
2102 ));
2103 }
2104 Ok(width_bucket(&val, min_val, max_val, num_bucket).into_expr())
2105 }
2106 "equal_null" => {
2107 require_args(name, args, 2)?;
2108 let a = expr_to_column(arg_expr(args, 0)?);
2109 let b = expr_to_column(arg_expr(args, 1)?);
2110 Ok(equal_null(&a, &b).into_expr())
2111 }
2112 "year" => {
2114 require_args(name, args, 1)?;
2115 Ok(year(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2116 }
2117 "month" => {
2118 require_args(name, args, 1)?;
2119 Ok(month(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2120 }
2121 "day" | "dayofmonth" => {
2122 require_args(name, args, 1)?;
2123 Ok(day(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2124 }
2125 "hour" => {
2126 require_args(name, args, 1)?;
2127 Ok(hour(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2128 }
2129 "minute" => {
2130 require_args(name, args, 1)?;
2131 Ok(minute(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2132 }
2133 "second" => {
2134 require_args(name, args, 1)?;
2135 Ok(second(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2136 }
2137 "quarter" => {
2138 require_args(name, args, 1)?;
2139 Ok(quarter(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2140 }
2141 "weekofyear" => {
2142 require_args(name, args, 1)?;
2143 Ok(weekofyear(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2144 }
2145 "dayofweek" => {
2146 require_args(name, args, 1)?;
2147 Ok(dayofweek(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2148 }
2149 "dayofyear" => {
2150 require_args(name, args, 1)?;
2151 Ok(dayofyear(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2152 }
2153 "to_date" => {
2154 require_args_min(name, args, 1)?;
2155 if args.len() > 2 {
2156 return Err(PlanExprError(format!(
2157 "fn '{name}' takes at most 2 argument(s)"
2158 )));
2159 }
2160 let col = expr_to_column(arg_expr(args, 0)?);
2161 let format_str = if args.len() == 2 {
2162 Some(arg_lit_str(args, 1)?)
2163 } else {
2164 None
2165 };
2166 to_date(&col, format_str.as_deref())
2167 .map_err(PlanExprError)
2168 .map(|c| c.into_expr())
2169 }
2170 "date_format" => {
2171 require_args(name, args, 2)?;
2172 let c = expr_to_column(arg_expr(args, 0)?);
2173 let format = arg_lit_str(args, 1)?;
2174 Ok(date_format(&c, &format).into_expr())
2175 }
2176 "date_add" => {
2177 require_args(name, args, 2)?;
2178 let c = expr_to_column(arg_expr(args, 0)?);
2179 let n = arg_lit_i32(args, 1)?;
2180 Ok(date_add(&c, n).into_expr())
2181 }
2182 "date_sub" => {
2183 require_args(name, args, 2)?;
2184 let c = expr_to_column(arg_expr(args, 0)?);
2185 let n = arg_lit_i32(args, 1)?;
2186 Ok(date_sub(&c, n).into_expr())
2187 }
2188 "datediff" | "date_diff" => {
2189 require_args(name, args, 2)?;
2190 let end = expr_to_column(arg_expr(args, 0)?);
2191 let start = expr_to_column(arg_expr(args, 1)?);
2192 Ok(datediff(&end, &start).into_expr())
2193 }
2194 "last_day" => {
2195 require_args(name, args, 1)?;
2196 Ok(last_day(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2197 }
2198 "trunc" => {
2199 require_args(name, args, 2)?;
2200 let c = expr_to_column(arg_expr(args, 0)?);
2201 let format = arg_lit_str(args, 1)?;
2202 Ok(trunc(&c, &format).into_expr())
2203 }
2204 "date_trunc" => {
2205 require_args(name, args, 2)?;
2206 let format = arg_lit_str(args, 0)?;
2207 let c = expr_to_column(arg_expr(args, 1)?);
2208 Ok(date_trunc(&format, &c).into_expr())
2209 }
2210 "add_months" => {
2211 require_args(name, args, 2)?;
2212 let c = expr_to_column(arg_expr(args, 0)?);
2213 let n = arg_lit_i32(args, 1)?;
2214 Ok(add_months(&c, n).into_expr())
2215 }
2216 "months_between" => {
2217 require_args_min(name, args, 2)?;
2218 let end = expr_to_column(arg_expr(args, 0)?);
2219 let start = expr_to_column(arg_expr(args, 1)?);
2220 let round_off = args
2221 .get(2)
2222 .and_then(|v| v.get("lit").and_then(Value::as_bool))
2223 .unwrap_or(true);
2224 Ok(months_between(&end, &start, round_off).into_expr())
2225 }
2226 "next_day" => {
2227 require_args(name, args, 2)?;
2228 let c = expr_to_column(arg_expr(args, 0)?);
2229 let day_of_week = arg_lit_str(args, 1)?;
2230 Ok(next_day(&c, &day_of_week).into_expr())
2231 }
2232 "unix_timestamp" => {
2233 if args.is_empty() {
2234 Ok(unix_timestamp_now().into_expr())
2235 } else {
2236 require_args_min(name, args, 1)?;
2237 let c = expr_to_column(arg_expr(args, 0)?);
2238 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2239 Ok(unix_timestamp(&c, format.as_deref()).into_expr())
2240 }
2241 }
2242 "from_unixtime" => {
2243 require_args_min(name, args, 1)?;
2244 let c = expr_to_column(arg_expr(args, 0)?);
2245 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2246 Ok(from_unixtime(&c, format.as_deref()).into_expr())
2247 }
2248 "to_unix_timestamp" => {
2249 require_args_min(name, args, 1)?;
2250 let c = expr_to_column(arg_expr(args, 0)?);
2251 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2252 Ok(to_unix_timestamp(&c, format.as_deref()).into_expr())
2253 }
2254 "make_date" => {
2255 require_args(name, args, 3)?;
2256 let y = expr_to_column(arg_expr(args, 0)?);
2257 let m = expr_to_column(arg_expr(args, 1)?);
2258 let d = expr_to_column(arg_expr(args, 2)?);
2259 Ok(make_date(&y, &m, &d).into_expr())
2260 }
2261 "make_timestamp" => {
2262 require_args_min(name, args, 6)?;
2263 let y = expr_to_column(arg_expr(args, 0)?);
2264 let mo = expr_to_column(arg_expr(args, 1)?);
2265 let d = expr_to_column(arg_expr(args, 2)?);
2266 let h = expr_to_column(arg_expr(args, 3)?);
2267 let mi = expr_to_column(arg_expr(args, 4)?);
2268 let s = expr_to_column(arg_expr(args, 5)?);
2269 let tz: Option<String> = arg_lit_opt_str(args, 6)?;
2270 Ok(make_timestamp(&y, &mo, &d, &h, &mi, &s, tz.as_deref()).into_expr())
2271 }
2272 "make_timestamp_ntz" => {
2273 require_args(name, args, 6)?;
2274 let y = expr_to_column(arg_expr(args, 0)?);
2275 let mo = expr_to_column(arg_expr(args, 1)?);
2276 let d = expr_to_column(arg_expr(args, 2)?);
2277 let h = expr_to_column(arg_expr(args, 3)?);
2278 let mi = expr_to_column(arg_expr(args, 4)?);
2279 let s = expr_to_column(arg_expr(args, 5)?);
2280 Ok(make_timestamp_ntz(&y, &mo, &d, &h, &mi, &s).into_expr())
2281 }
2282 "timestampadd" => {
2283 require_args(name, args, 3)?;
2284 let unit = arg_lit_str(args, 0)?;
2285 let amount = expr_to_column(arg_expr(args, 1)?);
2286 let ts = expr_to_column(arg_expr(args, 2)?);
2287 Ok(timestampadd(&unit, &amount, &ts).into_expr())
2288 }
2289 "timestampdiff" => {
2290 require_args(name, args, 3)?;
2291 let unit = arg_lit_str(args, 0)?;
2292 let start = expr_to_column(arg_expr(args, 1)?);
2293 let end = expr_to_column(arg_expr(args, 2)?);
2294 Ok(timestampdiff(&unit, &start, &end).into_expr())
2295 }
2296 "days" => {
2297 require_args(name, args, 1)?;
2298 let n = arg_lit_i64(args, 0)?;
2299 Ok(days(n).into_expr())
2300 }
2301 "hours" => {
2302 require_args(name, args, 1)?;
2303 let n = arg_lit_i64(args, 0)?;
2304 Ok(hours(n).into_expr())
2305 }
2306 "minutes" => {
2307 require_args(name, args, 1)?;
2308 let n = arg_lit_i64(args, 0)?;
2309 Ok(minutes(n).into_expr())
2310 }
2311 "months" => {
2312 require_args(name, args, 1)?;
2313 let n = arg_lit_i64(args, 0)?;
2314 Ok(months(n).into_expr())
2315 }
2316 "years" => {
2317 require_args(name, args, 1)?;
2318 let n = arg_lit_i64(args, 0)?;
2319 Ok(years(n).into_expr())
2320 }
2321 "from_utc_timestamp" => {
2322 require_args(name, args, 2)?;
2323 let c = expr_to_column(arg_expr(args, 0)?);
2324 let tz = arg_lit_str(args, 1)?;
2325 Ok(from_utc_timestamp(&c, &tz).into_expr())
2326 }
2327 "to_utc_timestamp" => {
2328 require_args(name, args, 2)?;
2329 let c = expr_to_column(arg_expr(args, 0)?);
2330 let tz = arg_lit_str(args, 1)?;
2331 Ok(to_utc_timestamp(&c, &tz).into_expr())
2332 }
2333 "convert_timezone" => {
2334 require_args(name, args, 3)?;
2335 let source_tz = arg_lit_str(args, 0)?;
2336 let target_tz = arg_lit_str(args, 1)?;
2337 let c = expr_to_column(arg_expr(args, 2)?);
2338 Ok(crate::functions::convert_timezone(&source_tz, &target_tz, &c).into_expr())
2339 }
2340 "current_date" | "curdate" => {
2341 if !args.is_empty() {
2342 return Err(PlanExprError(format!("fn '{name}' takes no arguments")));
2343 }
2344 Ok(current_date().into_expr())
2345 }
2346 "current_timestamp" | "now" => {
2347 if !args.is_empty() {
2348 return Err(PlanExprError(format!("fn '{name}' takes no arguments")));
2349 }
2350 Ok(current_timestamp().into_expr())
2351 }
2352 "localtimestamp" => {
2353 if !args.is_empty() {
2354 return Err(PlanExprError(
2355 "fn 'localtimestamp' takes no arguments".to_string(),
2356 ));
2357 }
2358 Ok(localtimestamp().into_expr())
2359 }
2360 "extract" | "date_part" | "datepart" => {
2361 require_args(name, args, 2)?;
2362 let c = expr_to_column(arg_expr(args, 0)?);
2363 let field = arg_lit_str(args, 1)?;
2364 Ok(extract(&c, &field).into_expr())
2365 }
2366 "dateadd" => {
2367 require_args(name, args, 2)?;
2368 let c = expr_to_column(arg_expr(args, 0)?);
2369 let n = arg_lit_i32(args, 1)?;
2370 Ok(dateadd(&c, n).into_expr())
2371 }
2372 "unix_micros" | "unix_millis" | "unix_seconds" => {
2373 require_args(name, args, 1)?;
2374 let c = expr_to_column(arg_expr(args, 0)?);
2375 let out = match name {
2376 "unix_micros" => unix_micros(&c),
2377 "unix_millis" => unix_millis(&c),
2378 _ => unix_seconds(&c),
2379 };
2380 Ok(out.into_expr())
2381 }
2382 "dayname" => {
2383 require_args(name, args, 1)?;
2384 Ok(dayname(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2385 }
2386 "weekday" => {
2387 require_args(name, args, 1)?;
2388 Ok(weekday(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2389 }
2390 "timestamp_seconds" | "timestamp_millis" | "timestamp_micros" => {
2391 require_args(name, args, 1)?;
2392 let c = expr_to_column(arg_expr(args, 0)?);
2393 let out = match name {
2394 "timestamp_seconds" => timestamp_seconds(&c),
2395 "timestamp_millis" => timestamp_millis(&c),
2396 _ => timestamp_micros(&c),
2397 };
2398 Ok(out.into_expr())
2399 }
2400 "unix_date" => {
2401 require_args(name, args, 1)?;
2402 Ok(unix_date(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2403 }
2404 "date_from_unix_date" => {
2405 require_args(name, args, 1)?;
2406 Ok(date_from_unix_date(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2407 }
2408 "to_char" | "to_varchar" => {
2409 require_args_min(name, args, 1)?;
2410 let c = expr_to_column(arg_expr(args, 0)?);
2411 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2412 Ok(to_char(&c, format.as_deref())
2413 .map_err(PlanExprError)?
2414 .into_expr())
2415 }
2416 "to_timestamp" => {
2417 require_args_min(name, args, 1)?;
2418 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2419 let col_expr = if format.as_deref() == Some("yyyy-MM-dd'T'HH:mm:ss") {
2422 match try_extract_regexp_replace_strip_fraction_source(&args[0])? {
2423 Some(source_col) => {
2424 return Ok(to_timestamp_fused_strip_fraction(
2425 &source_col,
2426 "yyyy-MM-dd'T'HH:mm:ss",
2427 )
2428 .map_err(PlanExprError)?
2429 .into_expr());
2430 }
2431 None => expr_to_column(arg_expr(args, 0)?),
2432 }
2433 } else {
2434 expr_to_column(arg_expr(args, 0)?)
2435 };
2436 Ok(to_timestamp(&col_expr, format.as_deref())
2437 .map_err(PlanExprError)?
2438 .into_expr())
2439 }
2440 "try_to_timestamp" => {
2441 require_args_min(name, args, 1)?;
2442 let c = expr_to_column(arg_expr(args, 0)?);
2443 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2444 Ok(try_to_timestamp(&c, format.as_deref())
2445 .map_err(PlanExprError)?
2446 .into_expr())
2447 }
2448 "to_number" | "try_to_number" => {
2449 require_args_min(name, args, 1)?;
2450 let c = expr_to_column(arg_expr(args, 0)?);
2451 let format: Option<String> = arg_lit_opt_str(args, 1)?;
2452 let out = if name == "to_number" {
2453 to_number(&c, format.as_deref()).map_err(PlanExprError)?
2454 } else {
2455 try_to_number(&c, format.as_deref()).map_err(PlanExprError)?
2456 };
2457 Ok(out.into_expr())
2458 }
2459 "current_timezone" => {
2460 if !args.is_empty() {
2461 return Err(PlanExprError(
2462 "fn 'current_timezone' takes no arguments".to_string(),
2463 ));
2464 }
2465 Ok(current_timezone().into_expr())
2466 }
2467 "spark_partition_id"
2469 | "input_file_name"
2470 | "monotonically_increasing_id"
2471 | "current_catalog"
2472 | "current_database"
2473 | "current_schema"
2474 | "current_user"
2475 | "user" => {
2476 if !args.is_empty() {
2477 return Err(PlanExprError(format!("fn '{name}' takes no arguments")));
2478 }
2479 let out = match name {
2480 "spark_partition_id" => spark_partition_id(),
2481 "input_file_name" => input_file_name(),
2482 "monotonically_increasing_id" => monotonically_increasing_id(),
2483 "current_catalog" => current_catalog(),
2484 "current_database" => current_database(),
2485 "current_schema" => current_schema(),
2486 "current_user" => current_user(),
2487 "user" => user(),
2488 _ => current_catalog(), };
2490 Ok(out.into_expr())
2491 }
2492 "hash" => {
2493 require_args_min(name, args, 1)?;
2494 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
2495 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
2496 let refs: Vec<&Column> = cols.iter().collect();
2497 Ok(crate::functions::hash(&refs).into_expr())
2498 }
2499 "shift_left" => {
2500 require_args(name, args, 2)?;
2501 let c = expr_to_column(arg_expr(args, 0)?);
2502 let n = arg_lit_i32(args, 1)?;
2503 Ok(shift_left(&c, n).into_expr())
2504 }
2505 "shift_right" => {
2506 require_args(name, args, 2)?;
2507 let c = expr_to_column(arg_expr(args, 0)?);
2508 let n = arg_lit_i32(args, 1)?;
2509 Ok(shift_right(&c, n).into_expr())
2510 }
2511 "version" => {
2512 if !args.is_empty() {
2513 return Err(PlanExprError("fn 'version' takes no arguments".to_string()));
2514 }
2515 Ok(crate::functions::version().into_expr())
2516 }
2517 "array" => {
2519 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
2520 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
2521 let refs: Vec<&Column> = cols.iter().collect();
2522 Ok(array(&refs)
2523 .map_err(|e| PlanExprError(e.to_string()))?
2524 .into_expr())
2525 }
2526 "array_max" => {
2527 require_args(name, args, 1)?;
2528 Ok(crate::functions::array_max(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2529 }
2530 "array_min" => {
2531 require_args(name, args, 1)?;
2532 Ok(crate::functions::array_min(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2533 }
2534 "array_size" | "size" | "cardinality" => {
2535 require_args(name, args, 1)?;
2536 let c = expr_to_column(arg_expr(args, 0)?);
2537 Ok(array_size(&c).into_expr())
2538 }
2539 "element_at" => {
2540 require_args(name, args, 2)?;
2541 let c = expr_to_column(arg_expr(args, 0)?);
2542 let idx = arg_lit_i64(args, 1)?;
2543 Ok(element_at(&c, idx).into_expr())
2544 }
2545 "try_element_at" => {
2546 require_args(name, args, 2)?;
2547 let c = expr_to_column(arg_expr(args, 0)?);
2548 let idx = arg_lit_i64(args, 1)?;
2549 Ok(try_element_at(&c, idx).into_expr())
2550 }
2551 "array_contains" => {
2552 require_args(name, args, 2)?;
2553 let arr = expr_to_column(arg_expr(args, 0)?);
2554 let val = expr_to_column(arg_expr(args, 1)?);
2555 Ok(array_contains(&arr, &val).into_expr())
2556 }
2557 "array_join" => {
2558 require_args(name, args, 2)?;
2559 let c = expr_to_column(arg_expr(args, 0)?);
2560 let sep = arg_lit_str(args, 1)?;
2561 Ok(array_join(&c, &sep).into_expr())
2562 }
2563 "array_sort" => {
2564 require_args(name, args, 1)?;
2565 Ok(array_sort(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2566 }
2567 "array_distinct" => {
2568 require_args(name, args, 1)?;
2569 Ok(array_distinct(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2570 }
2571 "array_slice" => {
2572 require_args_min(name, args, 2)?;
2573 let c = expr_to_column(arg_expr(args, 0)?);
2574 let start = arg_lit_i64(args, 1)?;
2575 let length = opt_lit_i64(args, 2);
2576 Ok(array_slice(&c, start, length).into_expr())
2577 }
2578 "array_compact" => {
2579 require_args(name, args, 1)?;
2580 Ok(array_compact(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2581 }
2582 "array_remove" => {
2583 require_args(name, args, 2)?;
2584 let arr = expr_to_column(arg_expr(args, 0)?);
2585 let val = expr_to_column(arg_expr(args, 1)?);
2586 Ok(array_remove(&arr, &val).into_expr())
2587 }
2588 "explode" => {
2589 require_args(name, args, 1)?;
2590 Ok(explode(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2591 }
2592 "explode_outer" => {
2593 require_args(name, args, 1)?;
2594 Ok(explode_outer(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2595 }
2596 "inline" => {
2597 require_args(name, args, 1)?;
2598 Ok(crate::functions::inline(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2599 }
2600 "inline_outer" => {
2601 require_args(name, args, 1)?;
2602 Ok(crate::functions::inline_outer(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2603 }
2604 "sequence" => {
2605 require_args_min(name, args, 2)?;
2606 let start = expr_to_column(arg_expr(args, 0)?);
2607 let stop = expr_to_column(arg_expr(args, 1)?);
2608 let step = if args.len() > 2 {
2609 Some(expr_to_column(arg_expr(args, 2)?))
2610 } else {
2611 None
2612 };
2613 Ok(crate::functions::sequence(&start, &stop, step.as_ref()).into_expr())
2614 }
2615 "shuffle" => {
2616 require_args(name, args, 1)?;
2617 Ok(crate::functions::shuffle(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2618 }
2619 "array_position" => {
2620 require_args(name, args, 2)?;
2621 let arr = expr_to_column(arg_expr(args, 0)?);
2622 let val = expr_to_column(arg_expr(args, 1)?);
2623 Ok(crate::functions::array_position(&arr, &val).into_expr())
2624 }
2625 "array_append" => {
2626 require_args(name, args, 2)?;
2627 let arr = expr_to_column(arg_expr(args, 0)?);
2628 let elem = expr_to_column(arg_expr(args, 1)?);
2629 Ok(array_append(&arr, &elem).into_expr())
2630 }
2631 "array_prepend" => {
2632 require_args(name, args, 2)?;
2633 let arr = expr_to_column(arg_expr(args, 0)?);
2634 let elem = expr_to_column(arg_expr(args, 1)?);
2635 Ok(array_prepend(&arr, &elem).into_expr())
2636 }
2637 "array_insert" => {
2638 require_args(name, args, 3)?;
2639 let arr = expr_to_column(arg_expr(args, 0)?);
2640 let pos = expr_to_column(arg_expr(args, 1)?);
2641 let elem = expr_to_column(arg_expr(args, 2)?);
2642 Ok(array_insert(&arr, &pos, &elem).into_expr())
2643 }
2644 "array_except" => {
2645 require_args(name, args, 2)?;
2646 let a = expr_to_column(arg_expr(args, 0)?);
2647 let b = expr_to_column(arg_expr(args, 1)?);
2648 Ok(array_except(&a, &b).into_expr())
2649 }
2650 "array_intersect" => {
2651 require_args(name, args, 2)?;
2652 let a = expr_to_column(arg_expr(args, 0)?);
2653 let b = expr_to_column(arg_expr(args, 1)?);
2654 Ok(array_intersect(&a, &b).into_expr())
2655 }
2656 "array_union" => {
2657 require_args(name, args, 2)?;
2658 let a = expr_to_column(arg_expr(args, 0)?);
2659 let b = expr_to_column(arg_expr(args, 1)?);
2660 Ok(array_union(&a, &b).into_expr())
2661 }
2662 "arrays_overlap" => {
2663 require_args(name, args, 2)?;
2664 let a = expr_to_column(arg_expr(args, 0)?);
2665 let b = expr_to_column(arg_expr(args, 1)?);
2666 Ok(arrays_overlap(&a, &b).into_expr())
2667 }
2668 "arrays_zip" => {
2669 require_args(name, args, 2)?;
2670 let a = expr_to_column(arg_expr(args, 0)?);
2671 let b = expr_to_column(arg_expr(args, 1)?);
2672 Ok(arrays_zip(&a, &b).into_expr())
2673 }
2674 "array_agg" => {
2675 require_args(name, args, 1)?;
2676 Ok(array_agg(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2677 }
2678 "array_sum" => {
2679 require_args(name, args, 1)?;
2680 Ok(array_sum(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2681 }
2682 "create_map" | "createMap" => {
2684 let exprs: Result<Vec<Expr>, _> = args.iter().map(expr_from_value).collect();
2686 let cols: Vec<Column> = exprs?.into_iter().map(expr_to_column).collect();
2687 let refs: Vec<&Column> = cols.iter().collect();
2688 Ok(create_map(&refs)
2689 .map_err(|e| PlanExprError(e.to_string()))?
2690 .into_expr())
2691 }
2692 "map_keys" | "keys" => {
2693 require_args(name, args, 1)?;
2694 Ok(map_keys(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2695 }
2696 "map_values" => {
2697 require_args(name, args, 1)?;
2698 Ok(map_values(&expr_to_column(arg_expr(args, 0)?)).into_expr())
2699 }
2700 "get" => {
2701 require_args(name, args, 2)?;
2702 let map_col = expr_to_column(arg_expr(args, 0)?);
2703 let key = expr_to_column(arg_expr(args, 1)?);
2704 Ok(get(&map_col, &key).into_expr())
2705 }
2706 "get_field" | "getField" => {
2707 require_args(name, args, 2)?;
2709 let struct_col = expr_to_column(arg_expr(args, 0)?);
2710 let field_name = lit_as_string(&args[1])?;
2711 Ok(struct_col.get_field(&field_name).into_expr())
2712 }
2713 "get_item" => {
2714 require_args(name, args, 2)?;
2716 let col_c = expr_to_column(arg_expr(args, 0)?);
2717 let second = &args[1];
2718 if let Some(idx) = second.get("lit").and_then(|v| v.as_i64()) {
2719 Ok(col_c.get_item(idx).into_expr())
2720 } else {
2721 let key = expr_to_column(arg_expr(args, 1)?);
2722 Ok(get(&col_c, &key).into_expr())
2723 }
2724 }
2725 "struct" => {
2726 require_args_min(name, args, 1)?;
2728 let cols: Vec<crate::Column> = (0..args.len())
2729 .map(|i| arg_expr(args, i).map(expr_to_column))
2730 .collect::<Result<Vec<_>, _>>()?;
2731 let refs: Vec<&crate::Column> = cols.iter().collect();
2732 Ok(crate::functions::struct_(&refs).into_expr())
2733 }
2734 "named_struct" => {
2735 require_args_min(name, args, 2)?;
2737 if !args.len().is_multiple_of(2) {
2738 return Err(PlanExprError(
2739 "named_struct requires even number of args (name, value pairs)".into(),
2740 ));
2741 }
2742 let mut names: Vec<String> = Vec::new();
2743 let mut cols: Vec<crate::Column> = Vec::new();
2744 for i in (0..args.len()).step_by(2) {
2745 names.push(lit_as_string(&args[i])?);
2746 cols.push(expr_to_column(arg_expr(args, i + 1)?));
2747 }
2748 let refs: Vec<(&str, &crate::Column)> =
2749 names.iter().map(|s| s.as_str()).zip(cols.iter()).collect();
2750 Ok(crate::functions::named_struct(&refs).into_expr())
2751 }
2752 "with_field" | "withField" => {
2753 require_args(name, args, 3)?;
2755 let struct_col = expr_to_column(arg_expr(args, 0)?);
2756 let field_name = lit_as_string(&args[1])?;
2757 let value_col = expr_to_column(arg_expr(args, 2)?);
2758 let out = struct_col
2759 .try_with_field(&field_name, &value_col)
2760 .map_err(|e| PlanExprError(format!("with_field: {e}")))?;
2761 Ok(out.into_expr())
2762 }
2763 "nvl2" => {
2764 require_args(name, args, 3)?;
2765 let col1 = expr_to_column(arg_expr(args, 0)?);
2766 let col2 = expr_to_column(arg_expr(args, 1)?);
2767 let col3 = expr_to_column(arg_expr(args, 2)?);
2768 Ok(nvl2(&col1, &col2, &col3).into_expr())
2769 }
2770 _ => Err(PlanExprError(format!("unsupported function: {name}"))),
2771 }
2772}
2773
2774fn require_args(name: &str, args: &[Value], n: usize) -> Result<(), PlanExprError> {
2775 if args.len() != n {
2776 return Err(PlanExprError(format!(
2777 "fn '{name}' requires exactly {n} argument(s)"
2778 )));
2779 }
2780 Ok(())
2781}
2782
2783fn require_args_min(name: &str, args: &[Value], n: usize) -> Result<(), PlanExprError> {
2784 if args.len() < n {
2785 return Err(PlanExprError(format!(
2786 "fn '{name}' requires at least {n} argument(s)"
2787 )));
2788 }
2789 Ok(())
2790}
2791
2792#[cfg(test)]
2793mod tests {
2794 use super::*;
2795 use serde_json::json;
2796
2797 #[test]
2798 fn test_bare_string_column_ref() {
2799 let v = json!("age");
2801 let e = expr_from_value(&v).unwrap();
2802 assert!(matches!(e, polars::prelude::Expr::Column(_)));
2803 }
2804
2805 #[test]
2806 fn test_col() {
2807 let v = json!({"col": "age"});
2808 let _e = expr_from_value(&v).unwrap();
2809 }
2810
2811 #[test]
2813 fn test_column_key_as_col_ref() {
2814 let v = json!({"column": "age"});
2815 let e = expr_from_value(&v).unwrap();
2816 assert!(matches!(e, polars::prelude::Expr::Column(_)));
2817 }
2818
2819 #[test]
2820 fn test_lit_i64() {
2821 let v = json!({"lit": 30});
2822 let _ = expr_from_value(&v).unwrap();
2823 }
2824
2825 #[test]
2826 fn test_gt() {
2827 let v = json!({
2828 "op": "gt",
2829 "left": {"col": "age"},
2830 "right": {"lit": 30}
2831 });
2832 let _ = expr_from_value(&v).unwrap();
2833 }
2834
2835 #[test]
2836 fn test_and() {
2837 let v = json!({
2838 "op": "and",
2839 "left": {"op": "gt", "left": {"col": "a"}, "right": {"lit": 1}},
2840 "right": {"op": "lt", "left": {"col": "b"}, "right": {"lit": 10}}
2841 });
2842 let _ = expr_from_value(&v).unwrap();
2843 }
2844
2845 #[test]
2846 fn test_upper() {
2847 let v = json!({"fn": "upper", "args": [{"col": "name"}]});
2848 let _ = expr_from_value(&v).unwrap();
2849 }
2850
2851 #[test]
2852 fn test_length() {
2853 let v = json!({"fn": "length", "args": [{"col": "name"}]});
2854 let _ = expr_from_value(&v).unwrap();
2855 }
2856
2857 #[test]
2858 fn test_substring() {
2859 let v = json!({
2860 "fn": "substring",
2861 "args": [{"col": "s"}, {"lit": 1}, {"lit": 3}]
2862 });
2863 let _ = expr_from_value(&v).unwrap();
2864 }
2865
2866 #[test]
2867 fn test_year() {
2868 let v = json!({"fn": "year", "args": [{"col": "ts"}]});
2869 let _ = expr_from_value(&v).unwrap();
2870 }
2871
2872 #[test]
2873 fn test_cast() {
2874 let v = json!({
2875 "fn": "cast",
2876 "args": [{"col": "x"}, {"lit": "string"}]
2877 });
2878 let _ = expr_from_value(&v).unwrap();
2879 }
2880
2881 #[test]
2882 fn test_isin_op() {
2883 let v = json!({
2884 "op": "isin",
2885 "left": {"col": "id"},
2886 "right": {"lit": [1, 3]}
2887 });
2888 let _ = expr_from_value(&v).unwrap();
2889 }
2890
2891 #[test]
2892 fn test_isin_fn() {
2893 let v = json!({
2894 "fn": "isin",
2895 "args": [{"col": "id"}, {"lit": 1}, {"lit": 3}]
2896 });
2897 let _ = expr_from_value(&v).unwrap();
2898 }
2899
2900 #[test]
2902 fn test_isin_op_empty() {
2903 let v = json!({
2904 "op": "isin",
2905 "left": {"col": "id"},
2906 "right": {"lit": []}
2907 });
2908 let expr = expr_from_value(&v).unwrap();
2909 assert!(matches!(expr, Expr::Literal(_)));
2911 }
2912
2913 #[test]
2915 fn test_isin_fn_empty() {
2916 let v = json!({
2917 "fn": "isin",
2918 "args": [{"col": "id"}]
2919 });
2920 let expr = expr_from_value(&v).unwrap();
2921 assert!(matches!(expr, Expr::Literal(_)));
2922 let v2 = json!({
2923 "fn": "isin",
2924 "args": [{"col": "id"}, {"lit": null}]
2925 });
2926 let expr2 = expr_from_value(&v2).unwrap();
2927 assert!(matches!(expr2, Expr::Literal(_)));
2928 }
2929
2930 #[test]
2931 fn test_struct_named_struct_fn() {
2932 let v = json!({"fn": "struct", "args": [{"col": "a"}, {"col": "b"}]});
2933 let _ = expr_from_value(&v).unwrap();
2934 let v2 = json!({
2935 "fn": "named_struct",
2936 "args": [{"lit": "x"}, {"col": "a"}, {"lit": "y"}, {"col": "b"}]
2937 });
2938 let _ = expr_from_value(&v2).unwrap();
2939 }
2940
2941 #[test]
2942 fn test_get_item_fn() {
2943 let v = json!({"fn": "get_item", "args": [{"col": "arr"}, {"lit": 0}]});
2944 let _ = expr_from_value(&v).unwrap();
2945 let v2 = json!({"fn": "get_item", "args": [{"col": "m"}, {"lit": "key"}]});
2946 let _ = expr_from_value(&v2).unwrap();
2947 }
2948
2949 #[test]
2950 fn test_get_item_op() {
2951 let v = json!({"op": "getItem", "left": {"col": "arr"}, "right": {"lit": 1}});
2952 let _ = expr_from_value(&v).unwrap();
2953 }
2954
2955 #[test]
2956 fn test_startswith_op() {
2957 let v = json!({
2958 "op": "startswith",
2959 "left": {"col": "name"},
2960 "right": {"lit": "A"}
2961 });
2962 let _ = expr_from_value(&v).unwrap();
2963 }
2964
2965 #[test]
2966 fn test_is_null_op() {
2967 let v = json!({"op": "is_null", "arg": {"col": "x"}});
2968 let _ = expr_from_value(&v).unwrap();
2969 }
2970
2971 #[test]
2972 fn test_is_not_null_op() {
2973 let v = json!({"op": "is_not_null", "arg": {"col": "x"}});
2974 let _ = expr_from_value(&v).unwrap();
2975 }
2976
2977 #[test]
2978 fn test_regexp_extract_op() {
2979 let v = json!({
2980 "op": "regexp_extract",
2981 "left": {"col": "s"},
2982 "pattern": {"lit": r"(\w+)"},
2983 "group": {"lit": 1}
2984 });
2985 let _ = expr_from_value(&v).unwrap();
2986 }
2987
2988 #[test]
2990 fn test_regexp_extract_fn_bare_literals() {
2991 let v = json!({
2992 "fn": "regexp_extract",
2993 "args": [{"col": "s"}, r"(\w+)", 1]
2994 });
2995 let _ = expr_from_value(&v).unwrap();
2996 }
2997
2998 #[test]
2999 fn test_regexp_replace_op() {
3000 let v = json!({
3001 "op": "regexp_replace",
3002 "left": {"col": "str"},
3003 "pattern": {"lit": r"\d"},
3004 "replacement": {"lit": "X"}
3005 });
3006 let _ = expr_from_value(&v).unwrap();
3007 let v2 = json!({
3008 "op": "regexp_replace",
3009 "args": [{"col": "str"}, {"lit": r"\d"}, {"lit": "X"}]
3010 });
3011 let _ = expr_from_value(&v2).unwrap();
3012 }
3013
3014 #[test]
3015 fn test_create_map_op() {
3016 let v = json!({
3017 "op": "create_map",
3018 "args": [{"lit": "k"}, {"col": "a"}]
3019 });
3020 let _ = expr_from_value(&v).unwrap();
3021 }
3022
3023 #[test]
3024 fn test_create_map_fn_empty() {
3025 let v = json!({"fn": "create_map", "args": []});
3027 let _ = expr_from_value(&v).unwrap();
3028 }
3029
3030 #[test]
3031 fn test_type_window_row_number_order_by() {
3032 let v = json!({
3033 "type": "window",
3034 "fn": "row_number",
3035 "window": {"order_by": ["val"]}
3036 });
3037 let _ = expr_from_value(&v).unwrap();
3038 }
3039
3040 #[test]
3042 fn test_window_row_number_sparkless_format() {
3043 let v = json!({
3044 "fn": "row_number",
3045 "args": [],
3046 "window": {
3047 "partition_by": ["dept"],
3048 "order_by": [{"col": "salary", "asc": true}]
3049 }
3050 });
3051 let _ = expr_from_value(&v).unwrap();
3052 }
3053
3054 #[test]
3056 fn test_row_number_window_empty() {
3057 let v = json!({
3058 "type": "window",
3059 "fn": "row_number",
3060 "window": {}
3061 });
3062 let _ = expr_from_value(&v).unwrap();
3063 }
3064
3065 #[test]
3067 fn test_window_order_by_empty_list_error() {
3068 let v = json!({
3069 "fn": "row_number",
3070 "args": [],
3071 "window": {"partition_by": [], "order_by": []}
3072 });
3073 let res = expr_from_value(&v);
3074 let err = res.unwrap_err();
3075 let msg = err.to_string();
3076 assert!(
3077 msg.contains("At least one column must be specified")
3078 || msg.contains("must be specified"),
3079 "expected error message to contain 'At least one column must be specified' or 'must be specified', got: {}",
3080 msg
3081 );
3082 }
3083
3084 #[test]
3086 fn test_type_window_function_key() {
3087 let v = json!({
3088 "type": "window",
3089 "function": "row_number",
3090 "window": {"partition_by": ["dept"]}
3091 });
3092 let _ = expr_from_value(&v).unwrap();
3093 }
3094
3095 #[test]
3097 fn test_window_rank_dense_rank() {
3098 let v = json!({
3099 "fn": "rank",
3100 "args": [],
3101 "window": {"partition_by": ["dept"], "order_by": ["salary"]}
3102 });
3103 let _ = expr_from_value(&v).unwrap();
3104 let v2 = json!({
3105 "type": "window",
3106 "fn": "dense_rank",
3107 "window": {"order_by": ["val"]}
3108 });
3109 let _ = expr_from_value(&v2).unwrap();
3110 }
3111
3112 #[test]
3113 fn test_window_plus_literal_op() {
3114 let v = json!({
3116 "op": "add",
3117 "left": {"type": "window", "fn": "row_number", "window": {"order_by": ["val"]}},
3118 "right": {"lit": 10}
3119 });
3120 let _ = expr_from_value(&v).unwrap();
3121 }
3122
3123 #[test]
3124 fn test_when_two_arg() {
3125 let v = json!({
3126 "fn": "when",
3127 "args": [
3128 {"op": "gt", "left": {"col": "a"}, "right": {"lit": 0}},
3129 {"lit": "positive"}
3130 ]
3131 });
3132 let _ = expr_from_value(&v).unwrap();
3133 }
3134
3135 #[test]
3136 fn test_concat() {
3137 let v = json!({
3138 "fn": "concat",
3139 "args": [{"col": "first"}, {"lit": " "}, {"col": "last"}]
3140 });
3141 let _ = expr_from_value(&v).unwrap();
3142 }
3143
3144 #[test]
3146 fn test_concat_op() {
3147 let v = json!({
3148 "op": "concat",
3149 "args": [{"col": "a"}, {"col": "b"}]
3150 });
3151 let _ = expr_from_value(&v).unwrap();
3152 }
3153
3154 #[test]
3156 fn test_contains_op() {
3157 let v = json!({
3158 "op": "contains",
3159 "args": [{"col": "name"}, {"lit": "lic"}]
3160 });
3161 let _ = expr_from_value(&v).unwrap();
3162 }
3163
3164 #[test]
3165 fn test_greatest() {
3166 let v = json!({
3167 "fn": "greatest",
3168 "args": [{"col": "a"}, {"col": "b"}, {"lit": 0}]
3169 });
3170 let _ = expr_from_value(&v).unwrap();
3171 }
3172
3173 #[test]
3174 fn test_array_size() {
3175 let v = json!({"fn": "array_size", "args": [{"col": "arr"}]});
3176 let _ = expr_from_value(&v).unwrap();
3177 }
3178
3179 #[test]
3180 fn test_element_at() {
3181 let v = json!({"fn": "element_at", "args": [{"col": "arr"}, {"lit": 1}]});
3182 let _ = expr_from_value(&v).unwrap();
3183 }
3184
3185 #[test]
3186 fn test_coalesce() {
3187 let v = json!({
3188 "fn": "coalesce",
3189 "args": [{"col": "a"}, {"col": "b"}, {"lit": 0}]
3190 });
3191 let _ = expr_from_value(&v).unwrap();
3192 }
3193
3194 #[test]
3196 fn test_coalesce_bare_literal_arg() {
3197 let v = json!({
3198 "fn": "coalesce",
3199 "args": [{"col": "a"}, {"col": "b"}, 4.5]
3200 });
3201 let _ = expr_from_value(&v).unwrap();
3202 }
3203
3204 #[test]
3206 fn test_coalesce_op_args_form() {
3207 let v = json!({
3208 "op": "coalesce",
3209 "args": [{"col": "x"}, {"lit": "default"}]
3210 });
3211 let _ = expr_from_value(&v).unwrap();
3212 }
3213
3214 #[test]
3216 fn test_op_div_parses() {
3217 let v = json!({
3218 "op": "div",
3219 "left": {"col": "a"},
3220 "right": {"col": "b"}
3221 });
3222 let expr = expr_from_value(&v).unwrap();
3223 let _ = expr;
3224 }
3225
3226 #[test]
3228 fn test_op_not_parses() {
3229 let v = json!({"op": "not", "arg": {"col": "flag"}});
3230 let expr = expr_from_value(&v).unwrap();
3231 let _ = expr;
3232 }
3233
3234 #[test]
3236 fn test_between_string_column_numeric_bounds() {
3237 let v = json!({
3238 "op": "between",
3239 "left": {"col": "val"},
3240 "lower": {"lit": 1},
3241 "upper": {"lit": 10}
3242 });
3243 let expr = expr_from_value(&v).unwrap();
3244 let _ = expr;
3246 }
3247}