1use super::{
2 column_to_column_ref, placeholder_to_placeholder_expr, scalar_value_to_literal_value,
3 PlannerError, PlannerResult,
4};
5use datafusion::logical_expr::{
6 expr::{Alias, Placeholder},
7 BinaryExpr, Expr, Operator,
8};
9use proof_of_sql::{
10 base::database::ColumnType,
11 sql::{proof_exprs::DynProofExpr, scale_cast_binary_op},
12};
13use sqlparser::ast::Ident;
14
15#[expect(
17 clippy::missing_panics_doc,
18 reason = "Output of comparisons is always boolean"
19)]
20fn binary_expr_to_proof_expr(
21 left: &Expr,
22 right: &Expr,
23 op: Operator,
24 schema: &[(Ident, ColumnType)],
25) -> PlannerResult<DynProofExpr> {
26 let left_proof_expr = expr_to_proof_expr(left, schema)?;
27 let right_proof_expr = expr_to_proof_expr(right, schema)?;
28
29 let (left_proof_expr, right_proof_expr) = match op {
30 Operator::Eq
31 | Operator::NotEq
32 | Operator::Lt
33 | Operator::Gt
34 | Operator::LtEq
35 | Operator::GtEq
36 | Operator::Plus
37 | Operator::Minus => scale_cast_binary_op(left_proof_expr, right_proof_expr)?,
38 _ => (left_proof_expr, right_proof_expr),
39 };
40
41 match op {
42 Operator::And => Ok(DynProofExpr::try_new_and(
43 left_proof_expr,
44 right_proof_expr,
45 )?),
46 Operator::Or => Ok(DynProofExpr::try_new_or(left_proof_expr, right_proof_expr)?),
47 Operator::Multiply => Ok(DynProofExpr::try_new_multiply(
48 left_proof_expr,
49 right_proof_expr,
50 )?),
51 Operator::Eq => Ok(DynProofExpr::try_new_equals(
52 left_proof_expr,
53 right_proof_expr,
54 )?),
55 Operator::NotEq => Ok(DynProofExpr::try_new_not(DynProofExpr::try_new_equals(
56 left_proof_expr,
57 right_proof_expr,
58 )?)
59 .expect("An equality expression must have a boolean data type...")),
60 Operator::Lt => Ok(DynProofExpr::try_new_inequality(
61 left_proof_expr,
62 right_proof_expr,
63 true,
64 )?),
65 Operator::Gt => Ok(DynProofExpr::try_new_inequality(
66 left_proof_expr,
67 right_proof_expr,
68 false,
69 )?),
70 Operator::LtEq => Ok(DynProofExpr::try_new_not(DynProofExpr::try_new_inequality(
71 left_proof_expr,
72 right_proof_expr,
73 false,
74 )?)
75 .expect("An inequality expression must have a boolean data type...")),
76 Operator::GtEq => Ok(DynProofExpr::try_new_not(DynProofExpr::try_new_inequality(
77 left_proof_expr,
78 right_proof_expr,
79 true,
80 )?)
81 .expect("An inequality expression must have a boolean data type...")),
82 Operator::Plus => Ok(DynProofExpr::try_new_add(
83 left_proof_expr,
84 right_proof_expr,
85 )?),
86 Operator::Minus => Ok(DynProofExpr::try_new_subtract(
87 left_proof_expr,
88 right_proof_expr,
89 )?),
90 _ => Err(PlannerError::UnsupportedBinaryOperator { op }),
92 }
93}
94
95pub fn expr_to_proof_expr(
100 expr: &Expr,
101 schema: &[(Ident, ColumnType)],
102) -> PlannerResult<DynProofExpr> {
103 match expr {
104 Expr::Alias(Alias { expr, .. }) => expr_to_proof_expr(expr, schema),
105 Expr::Column(col) => Ok(DynProofExpr::new_column(column_to_column_ref(col, schema)?)),
106 Expr::Placeholder(placeholder) => placeholder_to_placeholder_expr(placeholder),
107 Expr::BinaryExpr(BinaryExpr { left, right, op }) => {
108 binary_expr_to_proof_expr(left, right, *op, schema)
109 }
110 Expr::Literal(val) => Ok(DynProofExpr::new_literal(scalar_value_to_literal_value(
111 val.clone(),
112 )?)),
113 Expr::Not(expr) => {
114 let proof_expr = expr_to_proof_expr(expr, schema)?;
115 Ok(DynProofExpr::try_new_not(proof_expr)?)
116 }
117 Expr::Cast(cast) => {
118 match &*cast.expr {
119 Expr::Placeholder(placeholder) if placeholder.data_type.is_none() => {
121 let typed_placeholder =
122 Placeholder::new(placeholder.id.clone(), Some(cast.data_type.clone()));
123 placeholder_to_placeholder_expr(&typed_placeholder)
124 }
125 _ => {
126 let from_expr = expr_to_proof_expr(&cast.expr, schema)?;
127 let to_type = cast.data_type.clone().try_into().map_err(|_| {
128 PlannerError::UnsupportedDataType {
129 data_type: cast.data_type.clone(),
130 }
131 })?;
132 Ok(
133 DynProofExpr::try_new_cast(from_expr.clone(), to_type).map_or_else(
134 |_| DynProofExpr::try_new_scaling_cast(from_expr, to_type),
135 Ok,
136 )?,
137 )
138 }
139 }
140 }
141 _ => Err(PlannerError::UnsupportedLogicalExpression {
142 expr: Box::new(expr.clone()),
143 }),
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use crate::df_util::*;
151 use arrow::datatypes::DataType;
152 use core::ops::{Add, Mul, Sub};
153 use datafusion::{
154 common::ScalarValue,
155 logical_expr::{
156 expr::{Placeholder, Unnest},
157 Cast,
158 },
159 };
160 use proof_of_sql::base::{
161 database::{ColumnRef, ColumnType, LiteralValue, TableRef},
162 math::decimal::Precision,
163 };
164
165 #[expect(non_snake_case)]
166 fn COLUMN_INT() -> DynProofExpr {
167 DynProofExpr::new_column(ColumnRef::new(
168 TableRef::from_names(Some("namespace"), "table_name"),
169 "column".into(),
170 ColumnType::Int,
171 ))
172 }
173
174 #[expect(non_snake_case)]
175 fn COLUMN1_SMALLINT() -> DynProofExpr {
176 DynProofExpr::new_column(ColumnRef::new(
177 TableRef::from_names(Some("namespace"), "table_name"),
178 "column1".into(),
179 ColumnType::SmallInt,
180 ))
181 }
182
183 #[expect(non_snake_case)]
184 fn COLUMN2_BIGINT() -> DynProofExpr {
185 DynProofExpr::new_column(ColumnRef::new(
186 TableRef::from_names(Some("namespace"), "table_name"),
187 "column2".into(),
188 ColumnType::BigInt,
189 ))
190 }
191
192 #[expect(non_snake_case)]
193 fn COLUMN1_BOOLEAN() -> DynProofExpr {
194 DynProofExpr::new_column(ColumnRef::new(
195 TableRef::from_names(Some("namespace"), "table_name"),
196 "column1".into(),
197 ColumnType::Boolean,
198 ))
199 }
200
201 #[expect(non_snake_case)]
202 fn COLUMN2_BOOLEAN() -> DynProofExpr {
203 DynProofExpr::new_column(ColumnRef::new(
204 TableRef::from_names(Some("namespace"), "table_name"),
205 "column2".into(),
206 ColumnType::Boolean,
207 ))
208 }
209
210 #[expect(non_snake_case)]
211 fn COLUMN3_DECIMAL_75_5() -> DynProofExpr {
212 DynProofExpr::new_column(ColumnRef::new(
213 TableRef::from_names(Some("namespace"), "table_name"),
214 "column3".into(),
215 ColumnType::Decimal75(
216 Precision::new(75).expect("Precision is definitely valid"),
217 5,
218 ),
219 ))
220 }
221
222 #[expect(non_snake_case)]
223 fn COLUMN2_DECIMAL_25_5() -> DynProofExpr {
224 DynProofExpr::new_column(ColumnRef::new(
225 TableRef::from_names(Some("namespace"), "table_name"),
226 "column2".into(),
227 ColumnType::Decimal75(
228 Precision::new(25).expect("Precision is definitely valid"),
229 5,
230 ),
231 ))
232 }
233
234 #[test]
236 fn we_can_convert_alias_to_proof_expr() {
237 let expr = df_column("namespace.table_name", "column").alias("alias");
239 let schema = vec![("column".into(), ColumnType::Int)];
240 assert_eq!(expr_to_proof_expr(&expr, &schema).unwrap(), COLUMN_INT());
241 }
242
243 #[test]
245 fn we_can_convert_column_expr_to_proof_expr() {
246 let expr = df_column("namespace.table_name", "column");
248 let schema = vec![("column".into(), ColumnType::Int)];
249 assert_eq!(expr_to_proof_expr(&expr, &schema).unwrap(), COLUMN_INT());
250 }
251
252 #[test]
254 fn we_can_convert_comparison_binary_expr_to_proof_expr() {
255 let schema = vec![
256 ("column1".into(), ColumnType::SmallInt),
257 ("column2".into(), ColumnType::BigInt),
258 ];
259
260 let expr = df_column("namespace.table_name", "column1")
262 .eq(df_column("namespace.table_name", "column2"));
263 assert_eq!(
264 expr_to_proof_expr(&expr, &schema).unwrap(),
265 DynProofExpr::try_new_equals(COLUMN1_SMALLINT(), COLUMN2_BIGINT()).unwrap()
266 );
267
268 let expr = df_column("namespace.table_name", "column1")
270 .lt(df_column("namespace.table_name", "column2"));
271 assert_eq!(
272 expr_to_proof_expr(&expr, &schema).unwrap(),
273 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), true).unwrap()
274 );
275
276 let expr = df_column("namespace.table_name", "column1")
278 .gt(df_column("namespace.table_name", "column2"));
279 assert_eq!(
280 expr_to_proof_expr(&expr, &schema).unwrap(),
281 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), false).unwrap()
282 );
283
284 let expr = df_column("namespace.table_name", "column1")
286 .lt_eq(df_column("namespace.table_name", "column2"));
287 assert_eq!(
288 expr_to_proof_expr(&expr, &schema).unwrap(),
289 DynProofExpr::try_new_not(
290 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), false)
291 .unwrap()
292 )
293 .unwrap()
294 );
295
296 let expr = df_column("namespace.table_name", "column1")
298 .gt_eq(df_column("namespace.table_name", "column2"));
299 assert_eq!(
300 expr_to_proof_expr(&expr, &schema).unwrap(),
301 DynProofExpr::try_new_not(
302 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), true)
303 .unwrap()
304 )
305 .unwrap()
306 );
307 }
308
309 #[expect(clippy::too_many_lines)]
310 #[test]
311 fn we_can_convert_comparison_binary_expr_to_proof_expr_with_scale_cast() {
312 let schema = vec![
313 ("column1".into(), ColumnType::SmallInt),
314 (
315 "column2".into(),
316 ColumnType::Decimal75(Precision::new(25).unwrap(), 5),
317 ),
318 (
319 "column3".into(),
320 ColumnType::Decimal75(Precision::new(75).unwrap(), 5),
321 ),
322 ];
323
324 let expr = df_column("namespace.table_name", "column1")
326 .eq(df_column("namespace.table_name", "column3"));
327 assert_eq!(
328 expr_to_proof_expr(&expr, &schema).unwrap(),
329 DynProofExpr::try_new_equals(
330 DynProofExpr::try_new_scaling_cast(
331 COLUMN1_SMALLINT(),
332 ColumnType::Decimal75(
333 Precision::new(10).expect("Precision is definitely valid"),
334 5
335 )
336 )
337 .unwrap(),
338 COLUMN3_DECIMAL_75_5()
339 )
340 .unwrap()
341 );
342
343 let expr = df_column("namespace.table_name", "column1")
345 .lt(df_column("namespace.table_name", "column2"));
346 assert_eq!(
347 expr_to_proof_expr(&expr, &schema).unwrap(),
348 DynProofExpr::try_new_inequality(
349 DynProofExpr::try_new_scaling_cast(
350 COLUMN1_SMALLINT(),
351 ColumnType::Decimal75(
352 Precision::new(10).expect("Precision is definitely valid"),
353 5
354 )
355 )
356 .unwrap(),
357 COLUMN2_DECIMAL_25_5(),
358 true
359 )
360 .unwrap()
361 );
362
363 let expr = df_column("namespace.table_name", "column1")
365 .gt(df_column("namespace.table_name", "column2"));
366 assert_eq!(
367 expr_to_proof_expr(&expr, &schema).unwrap(),
368 DynProofExpr::try_new_inequality(
369 DynProofExpr::try_new_scaling_cast(
370 COLUMN1_SMALLINT(),
371 ColumnType::Decimal75(
372 Precision::new(10).expect("Precision is definitely valid"),
373 5
374 )
375 )
376 .unwrap(),
377 COLUMN2_DECIMAL_25_5(),
378 false
379 )
380 .unwrap()
381 );
382
383 let expr = df_column("namespace.table_name", "column1")
385 .lt_eq(df_column("namespace.table_name", "column2"));
386 assert_eq!(
387 expr_to_proof_expr(&expr, &schema).unwrap(),
388 DynProofExpr::try_new_not(
389 DynProofExpr::try_new_inequality(
390 DynProofExpr::try_new_scaling_cast(
391 COLUMN1_SMALLINT(),
392 ColumnType::Decimal75(
393 Precision::new(10).expect("Precision is definitely valid"),
394 5
395 )
396 )
397 .unwrap(),
398 COLUMN2_DECIMAL_25_5(),
399 false
400 )
401 .unwrap()
402 )
403 .unwrap()
404 );
405
406 let expr = df_column("namespace.table_name", "column1")
408 .gt_eq(df_column("namespace.table_name", "column2"));
409 assert_eq!(
410 expr_to_proof_expr(&expr, &schema).unwrap(),
411 DynProofExpr::try_new_not(
412 DynProofExpr::try_new_inequality(
413 DynProofExpr::try_new_scaling_cast(
414 COLUMN1_SMALLINT(),
415 ColumnType::Decimal75(
416 Precision::new(10).expect("Precision is definitely valid"),
417 5
418 )
419 )
420 .unwrap(),
421 COLUMN2_DECIMAL_25_5(),
422 true
423 )
424 .unwrap()
425 )
426 .unwrap()
427 );
428 }
429
430 #[test]
431 fn we_can_convert_arithmetic_binary_expr_to_proof_expr() {
432 let schema = vec![
433 ("column1".into(), ColumnType::SmallInt),
434 ("column2".into(), ColumnType::BigInt),
435 ];
436
437 let expr = Expr::BinaryExpr(BinaryExpr {
439 left: Box::new(df_column("namespace.table_name", "column1")),
440 right: Box::new(df_column("namespace.table_name", "column2")),
441 op: Operator::Plus,
442 });
443 assert_eq!(
444 expr_to_proof_expr(&expr, &schema).unwrap(),
445 DynProofExpr::try_new_add(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
446 );
447
448 let expr = Expr::BinaryExpr(BinaryExpr {
450 left: Box::new(df_column("namespace.table_name", "column1")),
451 right: Box::new(df_column("namespace.table_name", "column2")),
452 op: Operator::Minus,
453 });
454 assert_eq!(
455 expr_to_proof_expr(&expr, &schema).unwrap(),
456 DynProofExpr::try_new_subtract(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
457 );
458
459 let expr = Expr::BinaryExpr(BinaryExpr {
461 left: Box::new(df_column("namespace.table_name", "column1")),
462 right: Box::new(df_column("namespace.table_name", "column2")),
463 op: Operator::Multiply,
464 });
465 assert_eq!(
466 expr_to_proof_expr(&expr, &schema).unwrap(),
467 DynProofExpr::try_new_multiply(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
468 );
469 }
470
471 #[test]
472 fn we_can_convert_arithmetic_binary_expr_to_proof_expr_with_scale_cast() {
473 let schema = vec![
474 ("column1".into(), ColumnType::SmallInt),
475 (
476 "column2".into(),
477 ColumnType::Decimal75(Precision::new(25).unwrap(), 5),
478 ),
479 (
480 "column3".into(),
481 ColumnType::Decimal75(Precision::new(75).unwrap(), 5),
482 ),
483 ];
484
485 let expr = df_column("namespace.table_name", "column1")
487 .add(df_column("namespace.table_name", "column2"));
488 assert_eq!(
489 expr_to_proof_expr(&expr, &schema).unwrap(),
490 DynProofExpr::try_new_add(
491 DynProofExpr::try_new_scaling_cast(
492 COLUMN1_SMALLINT(),
493 ColumnType::Decimal75(
494 Precision::new(10).expect("Precision is definitely valid"),
495 5
496 )
497 )
498 .unwrap(),
499 COLUMN2_DECIMAL_25_5()
500 )
501 .unwrap()
502 );
503
504 let expr = df_column("namespace.table_name", "column1")
506 .sub(df_column("namespace.table_name", "column2"));
507 assert_eq!(
508 expr_to_proof_expr(&expr, &schema).unwrap(),
509 DynProofExpr::try_new_subtract(
510 DynProofExpr::try_new_scaling_cast(
511 COLUMN1_SMALLINT(),
512 ColumnType::Decimal75(
513 Precision::new(10).expect("Precision is definitely valid"),
514 5
515 )
516 )
517 .unwrap(),
518 COLUMN2_DECIMAL_25_5()
519 )
520 .unwrap()
521 );
522
523 let expr = df_column("namespace.table_name", "column1")
525 .mul(df_column("namespace.table_name", "column2"));
526 assert_eq!(
527 expr_to_proof_expr(&expr, &schema).unwrap(),
528 DynProofExpr::try_new_multiply(COLUMN1_SMALLINT(), COLUMN2_DECIMAL_25_5()).unwrap()
529 );
530 }
531
532 #[test]
533 fn we_can_convert_logical_binary_expr_to_proof_expr() {
534 let schema = vec![
535 ("column1".into(), ColumnType::Boolean),
536 ("column2".into(), ColumnType::Boolean),
537 ];
538
539 let expr = df_column("namespace.table_name", "column1")
541 .and(df_column("namespace.table_name", "column2"));
542 assert_eq!(
543 expr_to_proof_expr(&expr, &schema).unwrap(),
544 DynProofExpr::try_new_and(COLUMN1_BOOLEAN(), COLUMN2_BOOLEAN()).unwrap()
545 );
546
547 let expr = df_column("namespace.table_name", "column1")
549 .or(df_column("namespace.table_name", "column2"));
550 assert_eq!(
551 expr_to_proof_expr(&expr, &schema).unwrap(),
552 DynProofExpr::try_new_or(COLUMN1_BOOLEAN(), COLUMN2_BOOLEAN()).unwrap()
553 );
554 }
555
556 #[test]
557 fn we_can_convert_logical_not_eq_to_proof_expr() {
558 let schema = vec![
559 ("column1".into(), ColumnType::BigInt),
560 ("column2".into(), ColumnType::BigInt),
561 ];
562
563 let expr = df_column("namespace.table_name", "column1")
564 .not_eq(df_column("namespace.table_name", "column2"));
565 assert_eq!(
566 expr_to_proof_expr(&expr, &schema).unwrap(),
567 DynProofExpr::try_new_not(
568 DynProofExpr::try_new_equals(
569 DynProofExpr::new_column(ColumnRef::new(
570 TableRef::from_names(Some("namespace"), "table_name"),
571 "column1".into(),
572 ColumnType::BigInt,
573 )),
574 DynProofExpr::new_column(ColumnRef::new(
575 TableRef::from_names(Some("namespace"), "table_name"),
576 "column2".into(),
577 ColumnType::BigInt,
578 ))
579 )
580 .unwrap()
581 )
582 .unwrap()
583 );
584 }
585
586 #[test]
587 fn we_cannot_convert_unsupported_binary_expr_to_proof_expr() {
588 let expr = Expr::BinaryExpr(BinaryExpr {
590 left: Box::new(df_column("namespace.table_name", "column1")),
591 right: Box::new(df_column("namespace.table_name", "column2")),
592 op: Operator::AtArrow,
593 });
594 let schema = vec![
595 ("column1".into(), ColumnType::Boolean),
596 ("column2".into(), ColumnType::Boolean),
597 ];
598 assert!(matches!(
599 expr_to_proof_expr(&expr, &schema),
600 Err(PlannerError::UnsupportedBinaryOperator { .. })
601 ));
602 }
603
604 #[test]
606 fn we_can_convert_literal_expr_to_proof_expr() {
607 let expr = Expr::Literal(ScalarValue::Int32(Some(1)));
608 assert_eq!(
609 expr_to_proof_expr(&expr, &Vec::new()).unwrap(),
610 DynProofExpr::new_literal(LiteralValue::Int(1))
611 );
612 }
613
614 #[test]
616 fn we_can_convert_not_expr_to_proof_expr() {
617 let expr = Expr::Not(Box::new(df_column("table_name", "column")));
618 let schema = vec![("column".into(), ColumnType::Boolean)];
619 assert_eq!(
620 expr_to_proof_expr(&expr, &schema).unwrap(),
621 DynProofExpr::try_new_not(DynProofExpr::new_column(ColumnRef::new(
622 TableRef::from_names(None, "table_name"),
623 "column".into(),
624 ColumnType::Boolean
625 )))
626 .unwrap()
627 );
628 }
629
630 #[test]
632 fn we_can_convert_cast_expr_to_proof_expr() {
633 let expr = Expr::Cast(Cast::new(
634 Box::new(Expr::Literal(ScalarValue::Boolean(Some(true)))),
635 DataType::Int32,
636 ));
637 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
638 assert_eq!(
639 expression,
640 DynProofExpr::try_new_cast(
641 DynProofExpr::new_literal(LiteralValue::Boolean(true)),
642 ColumnType::Int
643 )
644 .unwrap()
645 );
646 }
647
648 #[test]
649 fn we_cannot_convert_cast_expr_to_proof_expr_when_inner_expr_to_proof_expr_fails() {
650 let expr = Expr::Cast(Cast::new(
652 Box::new(Expr::Literal(ScalarValue::UInt64(Some(100)))),
653 DataType::Int16,
654 ));
655 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
656 assert!(matches!(
657 expression,
658 PlannerError::UnsupportedDataType { data_type: _ }
659 ));
660 }
661
662 #[test]
663 fn we_cannot_convert_cast_expr_to_proof_expr_for_unsupported_datatypes() {
664 let expr = Expr::Cast(Cast::new(
666 Box::new(Expr::Literal(ScalarValue::Boolean(Some(true)))),
667 DataType::UInt16,
668 ));
669 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
670 assert!(matches!(
671 expression,
672 PlannerError::UnsupportedDataType { data_type: _ }
673 ));
674 }
675
676 #[test]
677 fn we_cannot_convert_cast_expr_to_proof_expr_for_datatypes_for_which_casting_is_not_supported()
678 {
679 let expr = Expr::Cast(Cast::new(
681 Box::new(Expr::Literal(ScalarValue::Int16(Some(100)))),
682 DataType::Boolean,
683 ));
684 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
685 assert!(matches!(
686 expression,
687 PlannerError::AnalyzeError { source: _ }
688 ));
689 }
690
691 #[test]
693 fn we_can_convert_placeholder_to_proof_expr() {
694 let expr = Expr::Placeholder(Placeholder {
695 id: "$1".to_string(),
696 data_type: Some(DataType::Int32),
697 });
698 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
699 assert_eq!(
700 expression,
701 DynProofExpr::try_new_placeholder(1, ColumnType::Int).unwrap()
702 );
703 }
704
705 #[test]
707 fn we_can_convert_placeholder_with_data_type_specified_by_cast_to_proof_expr() {
708 let expr = Expr::Cast(Cast::new(
709 Box::new(Expr::Placeholder(Placeholder {
710 id: "$1".to_string(),
711 data_type: None,
712 })),
713 DataType::Int32,
714 ));
715 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
716 assert_eq!(
717 expression,
718 DynProofExpr::try_new_placeholder(1, ColumnType::Int).unwrap()
719 );
720 }
721
722 #[test]
724 fn we_cannot_convert_unsupported_expr_to_proof_expr() {
725 let expr = Expr::Unnest(Unnest::new(Expr::Literal(ScalarValue::Int32(Some(100)))));
726 assert!(matches!(
727 expr_to_proof_expr(&expr, &Vec::new()),
728 Err(PlannerError::UnsupportedLogicalExpression { .. })
729 ));
730 }
731
732 #[test]
733 fn we_can_get_proof_expr_for_timestamps_of_different_scale() {
734 let lhs = Expr::Literal(ScalarValue::TimestampSecond(Some(1), None));
735 let rhs = Expr::Literal(ScalarValue::TimestampNanosecond(Some(1), None));
736 binary_expr_to_proof_expr(&lhs, &rhs, Operator::Gt, &Vec::new()).unwrap();
737 }
738}