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 catalog::TableReference,
155 common::{Column, ScalarValue},
156 logical_expr::{expr::Placeholder, Cast},
157 };
158 use proof_of_sql::base::{
159 database::{ColumnRef, ColumnType, LiteralValue, TableRef},
160 math::decimal::Precision,
161 };
162
163 #[expect(non_snake_case)]
164 fn COLUMN_INT() -> DynProofExpr {
165 DynProofExpr::new_column(ColumnRef::new(
166 TableRef::from_names(Some("namespace"), "table_name"),
167 "column".into(),
168 ColumnType::Int,
169 ))
170 }
171
172 #[expect(non_snake_case)]
173 fn COLUMN1_SMALLINT() -> DynProofExpr {
174 DynProofExpr::new_column(ColumnRef::new(
175 TableRef::from_names(Some("namespace"), "table_name"),
176 "column1".into(),
177 ColumnType::SmallInt,
178 ))
179 }
180
181 #[expect(non_snake_case)]
182 fn COLUMN2_BIGINT() -> DynProofExpr {
183 DynProofExpr::new_column(ColumnRef::new(
184 TableRef::from_names(Some("namespace"), "table_name"),
185 "column2".into(),
186 ColumnType::BigInt,
187 ))
188 }
189
190 #[expect(non_snake_case)]
191 fn COLUMN1_BOOLEAN() -> DynProofExpr {
192 DynProofExpr::new_column(ColumnRef::new(
193 TableRef::from_names(Some("namespace"), "table_name"),
194 "column1".into(),
195 ColumnType::Boolean,
196 ))
197 }
198
199 #[expect(non_snake_case)]
200 fn COLUMN2_BOOLEAN() -> DynProofExpr {
201 DynProofExpr::new_column(ColumnRef::new(
202 TableRef::from_names(Some("namespace"), "table_name"),
203 "column2".into(),
204 ColumnType::Boolean,
205 ))
206 }
207
208 #[expect(non_snake_case)]
209 fn COLUMN3_DECIMAL_75_5() -> DynProofExpr {
210 DynProofExpr::new_column(ColumnRef::new(
211 TableRef::from_names(Some("namespace"), "table_name"),
212 "column3".into(),
213 ColumnType::Decimal75(
214 Precision::new(75).expect("Precision is definitely valid"),
215 5,
216 ),
217 ))
218 }
219
220 #[expect(non_snake_case)]
221 fn COLUMN2_DECIMAL_25_5() -> DynProofExpr {
222 DynProofExpr::new_column(ColumnRef::new(
223 TableRef::from_names(Some("namespace"), "table_name"),
224 "column2".into(),
225 ColumnType::Decimal75(
226 Precision::new(25).expect("Precision is definitely valid"),
227 5,
228 ),
229 ))
230 }
231
232 #[test]
234 fn we_can_convert_alias_to_proof_expr() {
235 let expr = df_column("namespace.table_name", "column").alias("alias");
237 let schema = vec![("column".into(), ColumnType::Int)];
238 assert_eq!(expr_to_proof_expr(&expr, &schema).unwrap(), COLUMN_INT());
239 }
240
241 #[test]
243 fn we_can_convert_column_expr_to_proof_expr() {
244 let expr = df_column("namespace.table_name", "column");
246 let schema = vec![("column".into(), ColumnType::Int)];
247 assert_eq!(expr_to_proof_expr(&expr, &schema).unwrap(), COLUMN_INT());
248 }
249
250 #[test]
252 fn we_can_convert_comparison_binary_expr_to_proof_expr() {
253 let schema = vec![
254 ("column1".into(), ColumnType::SmallInt),
255 ("column2".into(), ColumnType::BigInt),
256 ];
257
258 let expr = df_column("namespace.table_name", "column1")
260 .eq(df_column("namespace.table_name", "column2"));
261 assert_eq!(
262 expr_to_proof_expr(&expr, &schema).unwrap(),
263 DynProofExpr::try_new_equals(COLUMN1_SMALLINT(), COLUMN2_BIGINT()).unwrap()
264 );
265
266 let expr = df_column("namespace.table_name", "column1")
268 .lt(df_column("namespace.table_name", "column2"));
269 assert_eq!(
270 expr_to_proof_expr(&expr, &schema).unwrap(),
271 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), true).unwrap()
272 );
273
274 let expr = df_column("namespace.table_name", "column1")
276 .gt(df_column("namespace.table_name", "column2"));
277 assert_eq!(
278 expr_to_proof_expr(&expr, &schema).unwrap(),
279 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), false).unwrap()
280 );
281
282 let expr = df_column("namespace.table_name", "column1")
284 .lt_eq(df_column("namespace.table_name", "column2"));
285 assert_eq!(
286 expr_to_proof_expr(&expr, &schema).unwrap(),
287 DynProofExpr::try_new_not(
288 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), false)
289 .unwrap()
290 )
291 .unwrap()
292 );
293
294 let expr = df_column("namespace.table_name", "column1")
296 .gt_eq(df_column("namespace.table_name", "column2"));
297 assert_eq!(
298 expr_to_proof_expr(&expr, &schema).unwrap(),
299 DynProofExpr::try_new_not(
300 DynProofExpr::try_new_inequality(COLUMN1_SMALLINT(), COLUMN2_BIGINT(), true)
301 .unwrap()
302 )
303 .unwrap()
304 );
305 }
306
307 #[expect(clippy::too_many_lines)]
308 #[test]
309 fn we_can_convert_comparison_binary_expr_to_proof_expr_with_scale_cast() {
310 let schema = vec![
311 ("column1".into(), ColumnType::SmallInt),
312 (
313 "column2".into(),
314 ColumnType::Decimal75(Precision::new(25).unwrap(), 5),
315 ),
316 (
317 "column3".into(),
318 ColumnType::Decimal75(Precision::new(75).unwrap(), 5),
319 ),
320 ];
321
322 let expr = df_column("namespace.table_name", "column1")
324 .eq(df_column("namespace.table_name", "column3"));
325 assert_eq!(
326 expr_to_proof_expr(&expr, &schema).unwrap(),
327 DynProofExpr::try_new_equals(
328 DynProofExpr::try_new_scaling_cast(
329 COLUMN1_SMALLINT(),
330 ColumnType::Decimal75(
331 Precision::new(10).expect("Precision is definitely valid"),
332 5
333 )
334 )
335 .unwrap(),
336 COLUMN3_DECIMAL_75_5()
337 )
338 .unwrap()
339 );
340
341 let expr = df_column("namespace.table_name", "column1")
343 .lt(df_column("namespace.table_name", "column2"));
344 assert_eq!(
345 expr_to_proof_expr(&expr, &schema).unwrap(),
346 DynProofExpr::try_new_inequality(
347 DynProofExpr::try_new_scaling_cast(
348 COLUMN1_SMALLINT(),
349 ColumnType::Decimal75(
350 Precision::new(10).expect("Precision is definitely valid"),
351 5
352 )
353 )
354 .unwrap(),
355 COLUMN2_DECIMAL_25_5(),
356 true
357 )
358 .unwrap()
359 );
360
361 let expr = df_column("namespace.table_name", "column1")
363 .gt(df_column("namespace.table_name", "column2"));
364 assert_eq!(
365 expr_to_proof_expr(&expr, &schema).unwrap(),
366 DynProofExpr::try_new_inequality(
367 DynProofExpr::try_new_scaling_cast(
368 COLUMN1_SMALLINT(),
369 ColumnType::Decimal75(
370 Precision::new(10).expect("Precision is definitely valid"),
371 5
372 )
373 )
374 .unwrap(),
375 COLUMN2_DECIMAL_25_5(),
376 false
377 )
378 .unwrap()
379 );
380
381 let expr = df_column("namespace.table_name", "column1")
383 .lt_eq(df_column("namespace.table_name", "column2"));
384 assert_eq!(
385 expr_to_proof_expr(&expr, &schema).unwrap(),
386 DynProofExpr::try_new_not(
387 DynProofExpr::try_new_inequality(
388 DynProofExpr::try_new_scaling_cast(
389 COLUMN1_SMALLINT(),
390 ColumnType::Decimal75(
391 Precision::new(10).expect("Precision is definitely valid"),
392 5
393 )
394 )
395 .unwrap(),
396 COLUMN2_DECIMAL_25_5(),
397 false
398 )
399 .unwrap()
400 )
401 .unwrap()
402 );
403
404 let expr = df_column("namespace.table_name", "column1")
406 .gt_eq(df_column("namespace.table_name", "column2"));
407 assert_eq!(
408 expr_to_proof_expr(&expr, &schema).unwrap(),
409 DynProofExpr::try_new_not(
410 DynProofExpr::try_new_inequality(
411 DynProofExpr::try_new_scaling_cast(
412 COLUMN1_SMALLINT(),
413 ColumnType::Decimal75(
414 Precision::new(10).expect("Precision is definitely valid"),
415 5
416 )
417 )
418 .unwrap(),
419 COLUMN2_DECIMAL_25_5(),
420 true
421 )
422 .unwrap()
423 )
424 .unwrap()
425 );
426 }
427
428 #[test]
429 fn we_can_convert_arithmetic_binary_expr_to_proof_expr() {
430 let schema = vec![
431 ("column1".into(), ColumnType::SmallInt),
432 ("column2".into(), ColumnType::BigInt),
433 ];
434
435 let expr = Expr::BinaryExpr(BinaryExpr {
437 left: Box::new(df_column("namespace.table_name", "column1")),
438 right: Box::new(df_column("namespace.table_name", "column2")),
439 op: Operator::Plus,
440 });
441 assert_eq!(
442 expr_to_proof_expr(&expr, &schema).unwrap(),
443 DynProofExpr::try_new_add(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
444 );
445
446 let expr = Expr::BinaryExpr(BinaryExpr {
448 left: Box::new(df_column("namespace.table_name", "column1")),
449 right: Box::new(df_column("namespace.table_name", "column2")),
450 op: Operator::Minus,
451 });
452 assert_eq!(
453 expr_to_proof_expr(&expr, &schema).unwrap(),
454 DynProofExpr::try_new_subtract(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
455 );
456
457 let expr = Expr::BinaryExpr(BinaryExpr {
459 left: Box::new(df_column("namespace.table_name", "column1")),
460 right: Box::new(df_column("namespace.table_name", "column2")),
461 op: Operator::Multiply,
462 });
463 assert_eq!(
464 expr_to_proof_expr(&expr, &schema).unwrap(),
465 DynProofExpr::try_new_multiply(COLUMN1_SMALLINT(), COLUMN2_BIGINT(),).unwrap()
466 );
467 }
468
469 #[test]
470 fn we_can_convert_arithmetic_binary_expr_to_proof_expr_with_scale_cast() {
471 let schema = vec![
472 ("column1".into(), ColumnType::SmallInt),
473 (
474 "column2".into(),
475 ColumnType::Decimal75(Precision::new(25).unwrap(), 5),
476 ),
477 (
478 "column3".into(),
479 ColumnType::Decimal75(Precision::new(75).unwrap(), 5),
480 ),
481 ];
482
483 let expr = df_column("namespace.table_name", "column1")
485 .add(df_column("namespace.table_name", "column2"));
486 assert_eq!(
487 expr_to_proof_expr(&expr, &schema).unwrap(),
488 DynProofExpr::try_new_add(
489 DynProofExpr::try_new_scaling_cast(
490 COLUMN1_SMALLINT(),
491 ColumnType::Decimal75(
492 Precision::new(10).expect("Precision is definitely valid"),
493 5
494 )
495 )
496 .unwrap(),
497 COLUMN2_DECIMAL_25_5()
498 )
499 .unwrap()
500 );
501
502 let expr = df_column("namespace.table_name", "column1")
504 .sub(df_column("namespace.table_name", "column2"));
505 assert_eq!(
506 expr_to_proof_expr(&expr, &schema).unwrap(),
507 DynProofExpr::try_new_subtract(
508 DynProofExpr::try_new_scaling_cast(
509 COLUMN1_SMALLINT(),
510 ColumnType::Decimal75(
511 Precision::new(10).expect("Precision is definitely valid"),
512 5
513 )
514 )
515 .unwrap(),
516 COLUMN2_DECIMAL_25_5()
517 )
518 .unwrap()
519 );
520
521 let expr = df_column("namespace.table_name", "column1")
523 .mul(df_column("namespace.table_name", "column2"));
524 assert_eq!(
525 expr_to_proof_expr(&expr, &schema).unwrap(),
526 DynProofExpr::try_new_multiply(COLUMN1_SMALLINT(), COLUMN2_DECIMAL_25_5()).unwrap()
527 );
528 }
529
530 #[test]
531 fn we_can_convert_logical_binary_expr_to_proof_expr() {
532 let schema = vec![
533 ("column1".into(), ColumnType::Boolean),
534 ("column2".into(), ColumnType::Boolean),
535 ];
536
537 let expr = df_column("namespace.table_name", "column1")
539 .and(df_column("namespace.table_name", "column2"));
540 assert_eq!(
541 expr_to_proof_expr(&expr, &schema).unwrap(),
542 DynProofExpr::try_new_and(COLUMN1_BOOLEAN(), COLUMN2_BOOLEAN()).unwrap()
543 );
544
545 let expr = df_column("namespace.table_name", "column1")
547 .or(df_column("namespace.table_name", "column2"));
548 assert_eq!(
549 expr_to_proof_expr(&expr, &schema).unwrap(),
550 DynProofExpr::try_new_or(COLUMN1_BOOLEAN(), COLUMN2_BOOLEAN()).unwrap()
551 );
552 }
553
554 #[test]
555 fn we_can_convert_logical_not_eq_to_proof_expr() {
556 let schema = vec![
557 ("column1".into(), ColumnType::BigInt),
558 ("column2".into(), ColumnType::BigInt),
559 ];
560
561 let expr = df_column("namespace.table_name", "column1")
562 .not_eq(df_column("namespace.table_name", "column2"));
563 assert_eq!(
564 expr_to_proof_expr(&expr, &schema).unwrap(),
565 DynProofExpr::try_new_not(
566 DynProofExpr::try_new_equals(
567 DynProofExpr::new_column(ColumnRef::new(
568 TableRef::from_names(Some("namespace"), "table_name"),
569 "column1".into(),
570 ColumnType::BigInt,
571 )),
572 DynProofExpr::new_column(ColumnRef::new(
573 TableRef::from_names(Some("namespace"), "table_name"),
574 "column2".into(),
575 ColumnType::BigInt,
576 ))
577 )
578 .unwrap()
579 )
580 .unwrap()
581 );
582 }
583
584 #[test]
585 fn we_cannot_convert_unsupported_binary_expr_to_proof_expr() {
586 let expr = Expr::BinaryExpr(BinaryExpr {
588 left: Box::new(df_column("namespace.table_name", "column1")),
589 right: Box::new(df_column("namespace.table_name", "column2")),
590 op: Operator::AtArrow,
591 });
592 let schema = vec![
593 ("column1".into(), ColumnType::Boolean),
594 ("column2".into(), ColumnType::Boolean),
595 ];
596 assert!(matches!(
597 expr_to_proof_expr(&expr, &schema),
598 Err(PlannerError::UnsupportedBinaryOperator { .. })
599 ));
600 }
601
602 #[test]
604 fn we_can_convert_literal_expr_to_proof_expr() {
605 let expr = Expr::Literal(ScalarValue::Int32(Some(1)));
606 assert_eq!(
607 expr_to_proof_expr(&expr, &Vec::new()).unwrap(),
608 DynProofExpr::new_literal(LiteralValue::Int(1))
609 );
610 }
611
612 #[test]
614 fn we_can_convert_not_expr_to_proof_expr() {
615 let expr = Expr::Not(Box::new(df_column("table_name", "column")));
616 let schema = vec![("column".into(), ColumnType::Boolean)];
617 assert_eq!(
618 expr_to_proof_expr(&expr, &schema).unwrap(),
619 DynProofExpr::try_new_not(DynProofExpr::new_column(ColumnRef::new(
620 TableRef::from_names(None, "table_name"),
621 "column".into(),
622 ColumnType::Boolean
623 )))
624 .unwrap()
625 );
626 }
627
628 #[test]
630 fn we_can_convert_cast_expr_to_proof_expr() {
631 let expr = Expr::Cast(Cast::new(
632 Box::new(Expr::Literal(ScalarValue::Boolean(Some(true)))),
633 DataType::Int32,
634 ));
635 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
636 assert_eq!(
637 expression,
638 DynProofExpr::try_new_cast(
639 DynProofExpr::new_literal(LiteralValue::Boolean(true)),
640 ColumnType::Int
641 )
642 .unwrap()
643 );
644 }
645
646 #[test]
647 fn we_cannot_convert_cast_expr_to_proof_expr_when_inner_expr_to_proof_expr_fails() {
648 let expr = Expr::Cast(Cast::new(
650 Box::new(Expr::Literal(ScalarValue::UInt64(Some(100)))),
651 DataType::Int16,
652 ));
653 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
654 assert!(matches!(
655 expression,
656 PlannerError::UnsupportedDataType { data_type: _ }
657 ));
658 }
659
660 #[test]
661 fn we_cannot_convert_cast_expr_to_proof_expr_for_unsupported_datatypes() {
662 let expr = Expr::Cast(Cast::new(
664 Box::new(Expr::Literal(ScalarValue::Boolean(Some(true)))),
665 DataType::UInt16,
666 ));
667 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
668 assert!(matches!(
669 expression,
670 PlannerError::UnsupportedDataType { data_type: _ }
671 ));
672 }
673
674 #[test]
675 fn we_cannot_convert_cast_expr_to_proof_expr_for_datatypes_for_which_casting_is_not_supported()
676 {
677 let expr = Expr::Cast(Cast::new(
679 Box::new(Expr::Literal(ScalarValue::Int16(Some(100)))),
680 DataType::Boolean,
681 ));
682 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap_err();
683 assert!(matches!(
684 expression,
685 PlannerError::AnalyzeError { source: _ }
686 ));
687 }
688
689 #[test]
691 fn we_can_convert_placeholder_to_proof_expr() {
692 let expr = Expr::Placeholder(Placeholder {
693 id: "$1".to_string(),
694 data_type: Some(DataType::Int32),
695 });
696 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
697 assert_eq!(
698 expression,
699 DynProofExpr::try_new_placeholder(1, ColumnType::Int).unwrap()
700 );
701 }
702
703 #[test]
705 fn we_can_convert_placeholder_with_data_type_specified_by_cast_to_proof_expr() {
706 let expr = Expr::Cast(Cast::new(
707 Box::new(Expr::Placeholder(Placeholder {
708 id: "$1".to_string(),
709 data_type: None,
710 })),
711 DataType::Int32,
712 ));
713 let expression = expr_to_proof_expr(&expr, &Vec::new()).unwrap();
714 assert_eq!(
715 expression,
716 DynProofExpr::try_new_placeholder(1, ColumnType::Int).unwrap()
717 );
718 }
719
720 #[test]
722 fn we_cannot_convert_unsupported_expr_to_proof_expr() {
723 let expr = Expr::OuterReferenceColumn(
724 DataType::Int32,
725 Column::new(None::<TableReference>, "column"),
726 );
727 assert!(matches!(
728 expr_to_proof_expr(&expr, &Vec::new()),
729 Err(PlannerError::UnsupportedLogicalExpression { .. })
730 ));
731 }
732
733 #[test]
734 fn we_can_get_proof_expr_for_timestamps_of_different_scale() {
735 let lhs = Expr::Literal(ScalarValue::TimestampSecond(Some(1), None));
736 let rhs = Expr::Literal(ScalarValue::TimestampNanosecond(Some(1), None));
737 binary_expr_to_proof_expr(&lhs, &rhs, Operator::Gt, &Vec::new()).unwrap();
738 }
739}