1use crate::expr::{
21 AggregateFunction, BinaryExpr, Cast, Exists, GroupingSet, InList, InSubquery, Lambda,
22 LambdaVariable, NullTreatment, Placeholder, TryCast, Unnest, WildcardOptions,
23 WindowFunction,
24};
25use crate::function::{
26 AccumulatorArgs, AccumulatorFactoryFunction, PartitionEvaluatorFactory,
27 StateFieldsArgs,
28};
29use crate::ptr_eq::PtrEq;
30use crate::select_expr::SelectExpr;
31use crate::{
32 AggregateUDF, Expr, LimitEffect, LogicalPlan, Operator, PartitionEvaluator,
33 ScalarFunctionArgs, ScalarFunctionImplementation, ScalarUDF, Signature, Volatility,
34 conditional_expressions::CaseBuilder, expr::Sort, logical_plan::Subquery,
35};
36use crate::{
37 AggregateUDFImpl, ColumnarValue, ScalarUDFImpl, WindowFrame, WindowUDF, WindowUDFImpl,
38};
39use arrow::compute::kernels::cast_utils::{
40 parse_interval_day_time, parse_interval_month_day_nano, parse_interval_year_month,
41};
42use arrow::datatypes::{DataType, Field, FieldRef};
43use datafusion_common::{Column, Result, ScalarValue, Spans, TableReference, plan_err};
44use datafusion_functions_window_common::field::WindowUDFFieldArgs;
45use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
46use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
47use std::collections::HashMap;
48use std::fmt::Debug;
49use std::hash::Hash;
50use std::ops::Not;
51use std::sync::Arc;
52
53pub fn col(ident: impl Into<Column>) -> Expr {
69 Expr::Column(ident.into())
70}
71
72pub fn out_ref_col(dt: DataType, ident: impl Into<Column>) -> Expr {
77 out_ref_col_with_metadata(dt, HashMap::new(), ident)
78}
79
80pub fn out_ref_col_with_metadata(
82 dt: DataType,
83 metadata: HashMap<String, String>,
84 ident: impl Into<Column>,
85) -> Expr {
86 let column = ident.into();
87 let field: FieldRef =
88 Arc::new(Field::new(column.name(), dt, true).with_metadata(metadata));
89 Expr::OuterReferenceColumn(field, column)
90}
91
92pub fn ident(name: impl Into<String>) -> Expr {
111 Expr::Column(Column::from_name(name))
112}
113
114pub fn placeholder(id: impl Into<String>) -> Expr {
126 Expr::Placeholder(Placeholder {
127 id: id.into(),
128 field: None,
129 })
130}
131
132pub fn wildcard() -> SelectExpr {
142 SelectExpr::Wildcard(WildcardOptions::default())
143}
144
145pub fn wildcard_with_options(options: WildcardOptions) -> SelectExpr {
147 SelectExpr::Wildcard(options)
148}
149
150pub fn qualified_wildcard(qualifier: impl Into<TableReference>) -> SelectExpr {
161 SelectExpr::QualifiedWildcard(qualifier.into(), WildcardOptions::default())
162}
163
164pub fn qualified_wildcard_with_options(
166 qualifier: impl Into<TableReference>,
167 options: WildcardOptions,
168) -> SelectExpr {
169 SelectExpr::QualifiedWildcard(qualifier.into(), options)
170}
171
172pub fn binary_expr(left: Expr, op: Operator, right: Expr) -> Expr {
174 Expr::BinaryExpr(BinaryExpr::new(Box::new(left), op, Box::new(right)))
175}
176
177pub fn and(left: Expr, right: Expr) -> Expr {
179 Expr::BinaryExpr(BinaryExpr::new(
180 Box::new(left),
181 Operator::And,
182 Box::new(right),
183 ))
184}
185
186pub fn or(left: Expr, right: Expr) -> Expr {
188 Expr::BinaryExpr(BinaryExpr::new(
189 Box::new(left),
190 Operator::Or,
191 Box::new(right),
192 ))
193}
194
195pub fn not(expr: Expr) -> Expr {
197 expr.not()
198}
199
200pub fn bitwise_and(left: Expr, right: Expr) -> Expr {
202 Expr::BinaryExpr(BinaryExpr::new(
203 Box::new(left),
204 Operator::BitwiseAnd,
205 Box::new(right),
206 ))
207}
208
209pub fn bitwise_or(left: Expr, right: Expr) -> Expr {
211 Expr::BinaryExpr(BinaryExpr::new(
212 Box::new(left),
213 Operator::BitwiseOr,
214 Box::new(right),
215 ))
216}
217
218pub fn bitwise_xor(left: Expr, right: Expr) -> Expr {
220 Expr::BinaryExpr(BinaryExpr::new(
221 Box::new(left),
222 Operator::BitwiseXor,
223 Box::new(right),
224 ))
225}
226
227pub fn bitwise_shift_right(left: Expr, right: Expr) -> Expr {
229 Expr::BinaryExpr(BinaryExpr::new(
230 Box::new(left),
231 Operator::BitwiseShiftRight,
232 Box::new(right),
233 ))
234}
235
236pub fn bitwise_shift_left(left: Expr, right: Expr) -> Expr {
238 Expr::BinaryExpr(BinaryExpr::new(
239 Box::new(left),
240 Operator::BitwiseShiftLeft,
241 Box::new(right),
242 ))
243}
244
245pub fn in_list(expr: Expr, list: Vec<Expr>, negated: bool) -> Expr {
247 Expr::InList(InList::new(Box::new(expr), list, negated))
248}
249
250pub fn exists(subquery: Arc<LogicalPlan>) -> Expr {
252 let outer_ref_columns = subquery.all_out_ref_exprs();
253 Expr::Exists(Exists {
254 subquery: Subquery {
255 subquery,
256 outer_ref_columns,
257 spans: Spans::new(),
258 },
259 negated: false,
260 })
261}
262
263pub fn not_exists(subquery: Arc<LogicalPlan>) -> Expr {
265 let outer_ref_columns = subquery.all_out_ref_exprs();
266 Expr::Exists(Exists {
267 subquery: Subquery {
268 subquery,
269 outer_ref_columns,
270 spans: Spans::new(),
271 },
272 negated: true,
273 })
274}
275
276pub fn in_subquery(expr: Expr, subquery: Arc<LogicalPlan>) -> Expr {
278 let outer_ref_columns = subquery.all_out_ref_exprs();
279 Expr::InSubquery(InSubquery::new(
280 Box::new(expr),
281 Subquery {
282 subquery,
283 outer_ref_columns,
284 spans: Spans::new(),
285 },
286 false,
287 ))
288}
289
290pub fn not_in_subquery(expr: Expr, subquery: Arc<LogicalPlan>) -> Expr {
292 let outer_ref_columns = subquery.all_out_ref_exprs();
293 Expr::InSubquery(InSubquery::new(
294 Box::new(expr),
295 Subquery {
296 subquery,
297 outer_ref_columns,
298 spans: Spans::new(),
299 },
300 true,
301 ))
302}
303
304pub fn scalar_subquery(subquery: Arc<LogicalPlan>) -> Expr {
306 let outer_ref_columns = subquery.all_out_ref_exprs();
307 Expr::ScalarSubquery(Subquery {
308 subquery,
309 outer_ref_columns,
310 spans: Spans::new(),
311 })
312}
313
314pub fn grouping_set(exprs: Vec<Vec<Expr>>) -> Expr {
316 Expr::GroupingSet(GroupingSet::GroupingSets(exprs))
317}
318
319pub fn cube(exprs: Vec<Expr>) -> Expr {
321 Expr::GroupingSet(GroupingSet::Cube(exprs))
322}
323
324pub fn rollup(exprs: Vec<Expr>) -> Expr {
326 Expr::GroupingSet(GroupingSet::Rollup(exprs))
327}
328
329pub fn cast(expr: Expr, data_type: DataType) -> Expr {
331 Expr::Cast(Cast::new(Box::new(expr), data_type))
332}
333
334pub fn try_cast(expr: Expr, data_type: DataType) -> Expr {
336 Expr::TryCast(TryCast::new(Box::new(expr), data_type))
337}
338
339pub fn is_null(expr: Expr) -> Expr {
341 Expr::IsNull(Box::new(expr))
342}
343
344pub fn is_not_null(expr: Expr) -> Expr {
346 Expr::IsNotNull(Box::new(expr))
347}
348
349pub fn is_true(expr: Expr) -> Expr {
351 Expr::IsTrue(Box::new(expr))
352}
353
354pub fn is_not_true(expr: Expr) -> Expr {
356 Expr::IsNotTrue(Box::new(expr))
357}
358
359pub fn is_false(expr: Expr) -> Expr {
361 Expr::IsFalse(Box::new(expr))
362}
363
364pub fn is_not_false(expr: Expr) -> Expr {
366 Expr::IsNotFalse(Box::new(expr))
367}
368
369pub fn is_unknown(expr: Expr) -> Expr {
371 Expr::IsUnknown(Box::new(expr))
372}
373
374pub fn is_not_unknown(expr: Expr) -> Expr {
376 Expr::IsNotUnknown(Box::new(expr))
377}
378
379pub fn case(expr: Expr) -> CaseBuilder {
381 CaseBuilder::new(Some(Box::new(expr)), vec![], vec![], None)
382}
383
384pub fn when(when: Expr, then: Expr) -> CaseBuilder {
386 CaseBuilder::new(None, vec![when], vec![then], None)
387}
388
389pub fn unnest(expr: Expr) -> Expr {
391 Expr::Unnest(Unnest {
392 expr: Box::new(expr),
393 })
394}
395
396pub fn create_udf(
409 name: &str,
410 input_types: Vec<DataType>,
411 return_type: DataType,
412 volatility: Volatility,
413 fun: ScalarFunctionImplementation,
414) -> ScalarUDF {
415 ScalarUDF::from(SimpleScalarUDF::new(
416 name,
417 input_types,
418 return_type,
419 volatility,
420 fun,
421 ))
422}
423
424#[derive(PartialEq, Eq, Hash)]
427pub struct SimpleScalarUDF {
428 name: String,
429 signature: Signature,
430 return_type: DataType,
431 fun: PtrEq<ScalarFunctionImplementation>,
432}
433
434impl Debug for SimpleScalarUDF {
435 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
436 f.debug_struct("SimpleScalarUDF")
437 .field("name", &self.name)
438 .field("signature", &self.signature)
439 .field("return_type", &self.return_type)
440 .field("fun", &"<FUNC>")
441 .finish()
442 }
443}
444
445impl SimpleScalarUDF {
446 pub fn new(
449 name: impl Into<String>,
450 input_types: Vec<DataType>,
451 return_type: DataType,
452 volatility: Volatility,
453 fun: ScalarFunctionImplementation,
454 ) -> Self {
455 Self::new_with_signature(
456 name,
457 Signature::exact(input_types, volatility),
458 return_type,
459 fun,
460 )
461 }
462
463 pub fn new_with_signature(
466 name: impl Into<String>,
467 signature: Signature,
468 return_type: DataType,
469 fun: ScalarFunctionImplementation,
470 ) -> Self {
471 Self {
472 name: name.into(),
473 signature,
474 return_type,
475 fun: fun.into(),
476 }
477 }
478}
479
480impl ScalarUDFImpl for SimpleScalarUDF {
481 fn name(&self) -> &str {
482 &self.name
483 }
484
485 fn signature(&self) -> &Signature {
486 &self.signature
487 }
488
489 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
490 Ok(self.return_type.clone())
491 }
492
493 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
494 (self.fun)(&args.args)
495 }
496}
497
498pub fn create_udaf(
501 name: &str,
502 input_type: Vec<DataType>,
503 return_type: Arc<DataType>,
504 volatility: Volatility,
505 accumulator: AccumulatorFactoryFunction,
506 state_type: Arc<Vec<DataType>>,
507) -> AggregateUDF {
508 let return_type = Arc::unwrap_or_clone(return_type);
509 let state_type = Arc::unwrap_or_clone(state_type);
510 let state_fields = state_type
511 .into_iter()
512 .enumerate()
513 .map(|(i, t)| Field::new(format!("{i}"), t, true))
514 .map(Arc::new)
515 .collect::<Vec<_>>();
516 AggregateUDF::from(SimpleAggregateUDF::new(
517 name,
518 input_type,
519 return_type,
520 volatility,
521 accumulator,
522 state_fields,
523 ))
524}
525
526#[derive(PartialEq, Eq, Hash)]
529pub struct SimpleAggregateUDF {
530 name: String,
531 signature: Signature,
532 return_type: DataType,
533 accumulator: PtrEq<AccumulatorFactoryFunction>,
534 state_fields: Vec<FieldRef>,
535}
536
537impl Debug for SimpleAggregateUDF {
538 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
539 f.debug_struct("SimpleAggregateUDF")
540 .field("name", &self.name)
541 .field("signature", &self.signature)
542 .field("return_type", &self.return_type)
543 .field("fun", &"<FUNC>")
544 .finish()
545 }
546}
547
548impl SimpleAggregateUDF {
549 pub fn new(
552 name: impl Into<String>,
553 input_type: Vec<DataType>,
554 return_type: DataType,
555 volatility: Volatility,
556 accumulator: AccumulatorFactoryFunction,
557 state_fields: Vec<FieldRef>,
558 ) -> Self {
559 let name = name.into();
560 let signature = Signature::exact(input_type, volatility);
561 Self {
562 name,
563 signature,
564 return_type,
565 accumulator: accumulator.into(),
566 state_fields,
567 }
568 }
569
570 pub fn new_with_signature(
573 name: impl Into<String>,
574 signature: Signature,
575 return_type: DataType,
576 accumulator: AccumulatorFactoryFunction,
577 state_fields: Vec<FieldRef>,
578 ) -> Self {
579 let name = name.into();
580 Self {
581 name,
582 signature,
583 return_type,
584 accumulator: accumulator.into(),
585 state_fields,
586 }
587 }
588}
589
590impl AggregateUDFImpl for SimpleAggregateUDF {
591 fn name(&self) -> &str {
592 &self.name
593 }
594
595 fn signature(&self) -> &Signature {
596 &self.signature
597 }
598
599 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
600 Ok(self.return_type.clone())
601 }
602
603 fn accumulator(
604 &self,
605 acc_args: AccumulatorArgs,
606 ) -> Result<Box<dyn crate::Accumulator>> {
607 (self.accumulator)(acc_args)
608 }
609
610 fn state_fields(&self, _args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
611 Ok(self.state_fields.clone())
612 }
613}
614
615pub fn create_udwf(
621 name: &str,
622 input_type: DataType,
623 return_type: Arc<DataType>,
624 volatility: Volatility,
625 partition_evaluator_factory: PartitionEvaluatorFactory,
626) -> WindowUDF {
627 let return_type = Arc::unwrap_or_clone(return_type);
628 WindowUDF::from(SimpleWindowUDF::new(
629 name,
630 input_type,
631 return_type,
632 volatility,
633 partition_evaluator_factory,
634 ))
635}
636
637#[derive(PartialEq, Eq, Hash)]
640pub struct SimpleWindowUDF {
641 name: String,
642 signature: Signature,
643 return_type: DataType,
644 partition_evaluator_factory: PtrEq<PartitionEvaluatorFactory>,
645}
646
647impl Debug for SimpleWindowUDF {
648 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
649 f.debug_struct("WindowUDF")
650 .field("name", &self.name)
651 .field("signature", &self.signature)
652 .field("return_type", &"<func>")
653 .field("partition_evaluator_factory", &"<FUNC>")
654 .finish()
655 }
656}
657
658impl SimpleWindowUDF {
659 pub fn new(
662 name: impl Into<String>,
663 input_type: DataType,
664 return_type: DataType,
665 volatility: Volatility,
666 partition_evaluator_factory: PartitionEvaluatorFactory,
667 ) -> Self {
668 let name = name.into();
669 let signature = Signature::exact([input_type].to_vec(), volatility);
670 Self {
671 name,
672 signature,
673 return_type,
674 partition_evaluator_factory: partition_evaluator_factory.into(),
675 }
676 }
677}
678
679impl WindowUDFImpl for SimpleWindowUDF {
680 fn name(&self) -> &str {
681 &self.name
682 }
683
684 fn signature(&self) -> &Signature {
685 &self.signature
686 }
687
688 fn partition_evaluator(
689 &self,
690 _partition_evaluator_args: PartitionEvaluatorArgs,
691 ) -> Result<Box<dyn PartitionEvaluator>> {
692 (self.partition_evaluator_factory)()
693 }
694
695 fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
696 Ok(Arc::new(Field::new(
697 field_args.name(),
698 self.return_type.clone(),
699 true,
700 )))
701 }
702
703 fn limit_effect(&self, _args: &[Arc<dyn PhysicalExpr>]) -> LimitEffect {
704 LimitEffect::Unknown
705 }
706}
707
708pub fn interval_year_month_lit(value: &str) -> Expr {
709 let interval = parse_interval_year_month(value).ok();
710 Expr::Literal(ScalarValue::IntervalYearMonth(interval), None)
711}
712
713pub fn interval_datetime_lit(value: &str) -> Expr {
714 let interval = parse_interval_day_time(value).ok();
715 Expr::Literal(ScalarValue::IntervalDayTime(interval), None)
716}
717
718pub fn interval_month_day_nano_lit(value: &str) -> Expr {
719 let interval = parse_interval_month_day_nano(value).ok();
720 Expr::Literal(ScalarValue::IntervalMonthDayNano(interval), None)
721}
722
723pub fn lambda(params: impl IntoIterator<Item = impl Into<String>>, body: Expr) -> Expr {
725 Expr::Lambda(Lambda::new(
726 params.into_iter().map(Into::into).collect(),
727 body,
728 ))
729}
730
731pub fn lambda_var(name: impl Into<String>) -> Expr {
739 Expr::LambdaVariable(LambdaVariable::new(name.into(), None))
740}
741
742pub trait ExprFunctionExt {
784 fn order_by(self, order_by: Vec<Sort>) -> ExprFuncBuilder;
786 fn filter(self, filter: Expr) -> ExprFuncBuilder;
788 fn distinct(self) -> ExprFuncBuilder;
790 fn null_treatment(
792 self,
793 null_treatment: impl Into<Option<NullTreatment>>,
794 ) -> ExprFuncBuilder;
795 fn partition_by(self, partition_by: Vec<Expr>) -> ExprFuncBuilder;
797 fn window_frame(self, window_frame: WindowFrame) -> ExprFuncBuilder;
799}
800
801#[derive(Debug, Clone)]
802pub enum ExprFuncKind {
803 Aggregate(AggregateFunction),
804 Window(Box<WindowFunction>),
805}
806
807#[derive(Debug, Clone)]
811pub struct ExprFuncBuilder {
812 fun: Option<ExprFuncKind>,
813 order_by: Option<Vec<Sort>>,
814 filter: Option<Expr>,
815 distinct: bool,
816 null_treatment: Option<NullTreatment>,
817 partition_by: Option<Vec<Expr>>,
818 window_frame: Option<WindowFrame>,
819}
820
821impl ExprFuncBuilder {
822 fn new(fun: Option<ExprFuncKind>) -> Self {
824 Self {
825 fun,
826 order_by: None,
827 filter: None,
828 distinct: false,
829 null_treatment: None,
830 partition_by: None,
831 window_frame: None,
832 }
833 }
834
835 pub fn build(self) -> Result<Expr> {
842 let Self {
843 fun,
844 order_by,
845 filter,
846 distinct,
847 null_treatment,
848 partition_by,
849 window_frame,
850 } = self;
851
852 let Some(fun) = fun else {
853 return plan_err!(
854 "ExprFunctionExt can only be used with Expr::AggregateFunction or Expr::WindowFunction"
855 );
856 };
857
858 let fun_expr = match fun {
859 ExprFuncKind::Aggregate(mut udaf) => {
860 udaf.params.order_by = order_by.unwrap_or_default();
861 udaf.params.filter = filter.map(Box::new);
862 udaf.params.distinct = distinct;
863 udaf.params.null_treatment = null_treatment;
864 Expr::AggregateFunction(udaf)
865 }
866 ExprFuncKind::Window(mut udwf) => {
867 let has_order_by = order_by.as_ref().map(|o| !o.is_empty());
868 udwf.params.partition_by = partition_by.unwrap_or_default();
869 udwf.params.order_by = order_by.unwrap_or_default();
870 udwf.params.window_frame =
871 window_frame.unwrap_or_else(|| WindowFrame::new(has_order_by));
872 udwf.params.filter = filter.map(Box::new);
873 udwf.params.null_treatment = null_treatment;
874 udwf.params.distinct = distinct;
875 Expr::WindowFunction(udwf)
876 }
877 };
878
879 Ok(fun_expr)
880 }
881}
882
883impl ExprFunctionExt for ExprFuncBuilder {
884 fn order_by(mut self, order_by: Vec<Sort>) -> ExprFuncBuilder {
886 self.order_by = Some(order_by);
887 self
888 }
889
890 fn filter(mut self, filter: Expr) -> ExprFuncBuilder {
892 self.filter = Some(filter);
893 self
894 }
895
896 fn distinct(mut self) -> ExprFuncBuilder {
898 self.distinct = true;
899 self
900 }
901
902 fn null_treatment(
904 mut self,
905 null_treatment: impl Into<Option<NullTreatment>>,
906 ) -> ExprFuncBuilder {
907 self.null_treatment = null_treatment.into();
908 self
909 }
910
911 fn partition_by(mut self, partition_by: Vec<Expr>) -> ExprFuncBuilder {
912 self.partition_by = Some(partition_by);
913 self
914 }
915
916 fn window_frame(mut self, window_frame: WindowFrame) -> ExprFuncBuilder {
917 self.window_frame = Some(window_frame);
918 self
919 }
920}
921
922impl ExprFunctionExt for Expr {
923 fn order_by(self, order_by: Vec<Sort>) -> ExprFuncBuilder {
924 let mut builder = match self {
925 Expr::AggregateFunction(udaf) => {
926 ExprFuncBuilder::new(Some(ExprFuncKind::Aggregate(udaf)))
927 }
928 Expr::WindowFunction(udwf) => {
929 ExprFuncBuilder::new(Some(ExprFuncKind::Window(udwf)))
930 }
931 _ => ExprFuncBuilder::new(None),
932 };
933 if builder.fun.is_some() {
934 builder.order_by = Some(order_by);
935 }
936 builder
937 }
938 fn filter(self, filter: Expr) -> ExprFuncBuilder {
939 match self {
940 Expr::AggregateFunction(udaf) => {
941 let mut builder =
942 ExprFuncBuilder::new(Some(ExprFuncKind::Aggregate(udaf)));
943 builder.filter = Some(filter);
944 builder
945 }
946 _ => ExprFuncBuilder::new(None),
947 }
948 }
949 fn distinct(self) -> ExprFuncBuilder {
950 match self {
951 Expr::AggregateFunction(udaf) => {
952 let mut builder =
953 ExprFuncBuilder::new(Some(ExprFuncKind::Aggregate(udaf)));
954 builder.distinct = true;
955 builder
956 }
957 _ => ExprFuncBuilder::new(None),
958 }
959 }
960 fn null_treatment(
961 self,
962 null_treatment: impl Into<Option<NullTreatment>>,
963 ) -> ExprFuncBuilder {
964 let mut builder = match self {
965 Expr::AggregateFunction(udaf) => {
966 ExprFuncBuilder::new(Some(ExprFuncKind::Aggregate(udaf)))
967 }
968 Expr::WindowFunction(udwf) => {
969 ExprFuncBuilder::new(Some(ExprFuncKind::Window(udwf)))
970 }
971 _ => ExprFuncBuilder::new(None),
972 };
973 if builder.fun.is_some() {
974 builder.null_treatment = null_treatment.into();
975 }
976 builder
977 }
978
979 fn partition_by(self, partition_by: Vec<Expr>) -> ExprFuncBuilder {
980 match self {
981 Expr::WindowFunction(udwf) => {
982 let mut builder = ExprFuncBuilder::new(Some(ExprFuncKind::Window(udwf)));
983 builder.partition_by = Some(partition_by);
984 builder
985 }
986 _ => ExprFuncBuilder::new(None),
987 }
988 }
989
990 fn window_frame(self, window_frame: WindowFrame) -> ExprFuncBuilder {
991 match self {
992 Expr::WindowFunction(udwf) => {
993 let mut builder = ExprFuncBuilder::new(Some(ExprFuncKind::Window(udwf)));
994 builder.window_frame = Some(window_frame);
995 builder
996 }
997 _ => ExprFuncBuilder::new(None),
998 }
999 }
1000}
1001
1002#[cfg(test)]
1003mod test {
1004 use super::*;
1005
1006 #[test]
1007 fn filter_is_null_and_is_not_null() {
1008 let col_null = col("col1");
1009 let col_not_null = ident("col2");
1010 assert_eq!(format!("{}", col_null.is_null()), "col1 IS NULL");
1011 assert_eq!(
1012 format!("{}", col_not_null.is_not_null()),
1013 "col2 IS NOT NULL"
1014 );
1015 }
1016}