datafusion_substrait/logical_plan/consumer/expr/
lambda.rs1use datafusion::{
19 common::{DFSchema, substrait_err},
20 prelude::{Expr, lambda},
21};
22use substrait::proto;
23
24use crate::logical_plan::consumer::SubstraitConsumer;
25
26pub async fn from_lambda(
27 consumer: &impl SubstraitConsumer,
28 expr: &proto::expression::Lambda,
29 input_schema: &DFSchema,
30) -> datafusion::common::Result<Expr> {
31 let Some(parameters) = expr.parameters.as_ref() else {
32 return substrait_err!("Lambda expression without parameters is not allowed");
33 };
34
35 let names = consumer.push_lambda_parameters(¶meters.types, input_schema)?;
36
37 let Some(body) = expr.body.as_ref() else {
38 return substrait_err!("Lambda expression without body is not allowed");
39 };
40
41 let body = consumer.consume_expression(body, input_schema).await?;
42
43 consumer.pop_lambda_parameters();
44
45 Ok(lambda(names, body))
46}
47
48#[cfg(test)]
49mod tests {
50 use datafusion::{
51 common::{DFSchema, assert_contains},
52 prelude::SessionContext,
53 };
54 use substrait::proto::{self, Expression, r#type::Struct};
55
56 use crate::{
57 extensions::Extensions,
58 logical_plan::consumer::{DefaultSubstraitConsumer, from_lambda},
59 };
60
61 #[tokio::test]
62 async fn test_lambda_without_body() {
63 let lambda = proto::expression::Lambda {
64 parameters: Some(Struct::default()),
65 body: None,
66 };
67
68 let extensions = Extensions::default();
69 let session_state = SessionContext::new().state();
70 let consumer = DefaultSubstraitConsumer::new(&extensions, &session_state);
71
72 let err = from_lambda(&consumer, &lambda, DFSchema::empty_ref())
73 .await
74 .unwrap_err();
75
76 assert_contains!(
77 err.to_string(),
78 "Lambda expression without body is not allowed"
79 );
80 }
81
82 #[tokio::test]
83 async fn test_lambda_without_parameters() {
84 let lambda = proto::expression::Lambda {
85 parameters: None,
86 body: Some(Box::new(Expression::default())),
87 };
88
89 let extensions = Extensions::default();
90 let session_state = SessionContext::new().state();
91 let consumer = DefaultSubstraitConsumer::new(&extensions, &session_state);
92
93 let err = from_lambda(&consumer, &lambda, DFSchema::empty_ref())
94 .await
95 .unwrap_err();
96
97 assert_contains!(
98 err.to_string(),
99 "Lambda expression without parameters is not allowed"
100 );
101 }
102}