1use std::sync::Arc;
7
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_panic;
11use vortex_utils::iter::ReduceBalancedIterExt;
12
13use crate::aggregate_fn::NumericalAggregateOpts;
14use crate::dtype::DType;
15use crate::dtype::FieldName;
16use crate::dtype::FieldNames;
17use crate::dtype::Nullability;
18use crate::expr::BoundExpression;
19use crate::expr::Expression;
20use crate::scalar::Scalar;
21use crate::scalar::ScalarValue;
22use crate::scalar_fn::EmptyOptions;
23use crate::scalar_fn::ScalarFnVTableExt;
24use crate::scalar_fn::fns::between::Between;
25use crate::scalar_fn::fns::between::BetweenOptions;
26use crate::scalar_fn::fns::binary::Binary;
27use crate::scalar_fn::fns::byte_length::ByteLength;
28use crate::scalar_fn::fns::case_when::CaseWhen;
29use crate::scalar_fn::fns::case_when::CaseWhenOptions;
30use crate::scalar_fn::fns::cast::Cast;
31use crate::scalar_fn::fns::dynamic::DynamicComparison;
32use crate::scalar_fn::fns::dynamic::DynamicComparisonExpr;
33use crate::scalar_fn::fns::dynamic::Rhs;
34use crate::scalar_fn::fns::ext_storage::ExtStorage;
35use crate::scalar_fn::fns::fill_null::FillNull;
36use crate::scalar_fn::fns::get_item::GetItem;
37use crate::scalar_fn::fns::is_not_null::IsNotNull;
38use crate::scalar_fn::fns::is_null::IsNull;
39use crate::scalar_fn::fns::like::Like;
40use crate::scalar_fn::fns::like::LikeOptions;
41use crate::scalar_fn::fns::list_contains::ListContains;
42use crate::scalar_fn::fns::list_length::ListLength;
43use crate::scalar_fn::fns::list_sum::ListSum;
44use crate::scalar_fn::fns::literal::Literal;
45use crate::scalar_fn::fns::mask::Mask;
46use crate::scalar_fn::fns::merge::DuplicateHandling;
47use crate::scalar_fn::fns::merge::Merge;
48use crate::scalar_fn::fns::not::Not;
49use crate::scalar_fn::fns::operators::CompareOperator;
50use crate::scalar_fn::fns::operators::Operator;
51use crate::scalar_fn::fns::pack::Pack;
52use crate::scalar_fn::fns::pack::PackOptions;
53use crate::scalar_fn::fns::select::FieldSelection;
54use crate::scalar_fn::fns::select::Select;
55use crate::scalar_fn::fns::variant_get::VariantGet;
56use crate::scalar_fn::fns::variant_get::VariantGetOptions;
57use crate::scalar_fn::fns::variant_get::VariantPath;
58use crate::scalar_fn::fns::zip::Zip;
59
60pub fn root() -> Expression {
65 Expression::Root
66}
67
68pub fn bound_root(dtype: DType) -> BoundExpression {
70 BoundExpression::new_root(dtype)
71}
72
73pub fn is_root(expr: &Expression) -> bool {
75 expr.is_root()
76}
77
78pub fn lit(value: impl Into<Scalar>) -> Expression {
98 Literal.new_expr(value.into(), [])
99}
100
101pub fn bound_lit(value: impl Into<Scalar>) -> BoundExpression {
103 Literal
104 .try_new_bound_expr(value.into(), [])
105 .vortex_expect("literal expressions are always well-typed")
106}
107
108pub fn col(field: impl Into<FieldName>) -> Expression {
119 GetItem.new_expr(field.into(), vec![root()])
120}
121
122pub fn bound_col(field: impl Into<FieldName>, scope: DType) -> BoundExpression {
124 bound_get_item(field, bound_root(scope))
125}
126
127pub fn get_item(field: impl Into<FieldName>, child: Expression) -> Expression {
136 GetItem.new_expr(field.into(), vec![child])
137}
138
139pub fn bound_get_item(field: impl Into<FieldName>, child: BoundExpression) -> BoundExpression {
141 GetItem
142 .try_new_bound_expr(field.into(), [child])
143 .vortex_expect("get-item expressions must reference a field in the child dtype")
144}
145
146pub fn variant_get(
153 child: Expression,
154 path: impl Into<VariantPath>,
155 dtype: Option<DType>,
156) -> Expression {
157 VariantGet.new_expr(VariantGetOptions::new(path.into(), dtype), vec![child])
158}
159
160pub fn bound_variant_get(
162 child: BoundExpression,
163 path: impl Into<VariantPath>,
164 dtype: Option<DType>,
165) -> BoundExpression {
166 VariantGet
167 .try_new_bound_expr(VariantGetOptions::new(path.into(), dtype), [child])
168 .vortex_expect("variant-get expressions require a Variant child")
169}
170
171pub fn case_when(
175 condition: Expression,
176 then_value: Expression,
177 else_value: Expression,
178) -> Expression {
179 let options = CaseWhenOptions {
180 num_when_then_pairs: 1,
181 has_else: true,
182 };
183 CaseWhen.new_expr(options, [condition, then_value, else_value])
184}
185
186pub fn bound_case_when(
188 condition: BoundExpression,
189 then_value: BoundExpression,
190 else_value: BoundExpression,
191) -> BoundExpression {
192 let options = CaseWhenOptions {
193 num_when_then_pairs: 1,
194 has_else: true,
195 };
196 CaseWhen
197 .try_new_bound_expr(options, [condition, then_value, else_value])
198 .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
199}
200
201pub fn case_when_no_else(condition: Expression, then_value: Expression) -> Expression {
203 let options = CaseWhenOptions {
204 num_when_then_pairs: 1,
205 has_else: false,
206 };
207 CaseWhen.new_expr(options, [condition, then_value])
208}
209
210pub fn bound_case_when_no_else(
212 condition: BoundExpression,
213 then_value: BoundExpression,
214) -> BoundExpression {
215 let options = CaseWhenOptions {
216 num_when_then_pairs: 1,
217 has_else: false,
218 };
219 CaseWhen
220 .try_new_bound_expr(options, [condition, then_value])
221 .vortex_expect("case expressions must have boolean conditions")
222}
223
224pub fn nested_case_when(
226 when_then_pairs: Vec<(Expression, Expression)>,
227 else_value: Option<Expression>,
228) -> Expression {
229 assert!(
230 !when_then_pairs.is_empty(),
231 "nested_case_when requires at least one when/then pair"
232 );
233
234 let has_else = else_value.is_some();
235 let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
236 for (condition, then_value) in &when_then_pairs {
237 children.push(condition.clone());
238 children.push(then_value.clone());
239 }
240 if let Some(else_expr) = else_value {
241 children.push(else_expr);
242 }
243
244 let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
245 vortex_panic!("nested_case_when has too many when/then pairs");
246 };
247 let options = CaseWhenOptions {
248 num_when_then_pairs,
249 has_else,
250 };
251 CaseWhen.new_expr(options, children)
252}
253
254pub fn bound_nested_case_when(
256 when_then_pairs: Vec<(BoundExpression, BoundExpression)>,
257 else_value: Option<BoundExpression>,
258) -> BoundExpression {
259 assert!(
260 !when_then_pairs.is_empty(),
261 "nested_case_when requires at least one when/then pair"
262 );
263
264 let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
265 vortex_panic!("nested_case_when has too many when/then pairs");
266 };
267 let has_else = else_value.is_some();
268 let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
269 for (condition, then_value) in when_then_pairs {
270 children.push(condition);
271 children.push(then_value);
272 }
273 if let Some(else_expr) = else_value {
274 children.push(else_expr);
275 }
276
277 let options = CaseWhenOptions {
278 num_when_then_pairs,
279 has_else,
280 };
281 CaseWhen
282 .try_new_bound_expr(options, children)
283 .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
284}
285
286pub fn binary(operator: Operator, lhs: Expression, rhs: Expression) -> Expression {
290 Binary
291 .try_new_expr(operator, [lhs, rhs])
292 .vortex_expect("Failed to create binary expression")
293}
294
295pub fn bound_binary(
297 operator: Operator,
298 lhs: BoundExpression,
299 rhs: BoundExpression,
300) -> BoundExpression {
301 Binary
302 .try_new_bound_expr(operator, [lhs, rhs])
303 .vortex_expect("binary expressions must have compatible operand dtypes")
304}
305
306pub fn eq(lhs: Expression, rhs: Expression) -> Expression {
328 Binary
329 .try_new_expr(Operator::Eq, [lhs, rhs])
330 .vortex_expect("Failed to create Eq binary expression")
331}
332
333pub fn bound_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
335 bound_binary(Operator::Eq, lhs, rhs)
336}
337
338pub fn not_eq(lhs: Expression, rhs: Expression) -> Expression {
360 Binary
361 .try_new_expr(Operator::NotEq, [lhs, rhs])
362 .vortex_expect("Failed to create NotEq binary expression")
363}
364
365pub fn bound_not_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
367 bound_binary(Operator::NotEq, lhs, rhs)
368}
369
370pub fn gt_eq(lhs: Expression, rhs: Expression) -> Expression {
392 Binary
393 .try_new_expr(Operator::Gte, [lhs, rhs])
394 .vortex_expect("Failed to create Gte binary expression")
395}
396
397pub fn bound_gt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
399 bound_binary(Operator::Gte, lhs, rhs)
400}
401
402pub fn gt(lhs: Expression, rhs: Expression) -> Expression {
424 Binary
425 .try_new_expr(Operator::Gt, [lhs, rhs])
426 .vortex_expect("Failed to create Gt binary expression")
427}
428
429pub fn bound_gt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
431 bound_binary(Operator::Gt, lhs, rhs)
432}
433
434pub fn lt_eq(lhs: Expression, rhs: Expression) -> Expression {
456 Binary
457 .try_new_expr(Operator::Lte, [lhs, rhs])
458 .vortex_expect("Failed to create Lte binary expression")
459}
460
461pub fn bound_lt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
463 bound_binary(Operator::Lte, lhs, rhs)
464}
465
466pub fn lt(lhs: Expression, rhs: Expression) -> Expression {
488 Binary
489 .try_new_expr(Operator::Lt, [lhs, rhs])
490 .vortex_expect("Failed to create Lt binary expression")
491}
492
493pub fn bound_lt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
495 bound_binary(Operator::Lt, lhs, rhs)
496}
497
498pub fn or(lhs: Expression, rhs: Expression) -> Expression {
518 Binary
519 .try_new_expr(Operator::Or, [lhs, rhs])
520 .vortex_expect("Failed to create Or binary expression")
521}
522
523pub fn bound_or(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
525 bound_binary(Operator::Or, lhs, rhs)
526}
527
528pub fn or_collect<I>(iter: I) -> Option<Expression>
535where
536 I: IntoIterator<Item = Expression>,
537{
538 iter.into_iter().reduce_balanced(or)
539}
540
541pub fn bound_or_collect<I>(iter: I) -> Option<BoundExpression>
543where
544 I: IntoIterator<Item = BoundExpression>,
545{
546 iter.into_iter().reduce_balanced(bound_or)
547}
548
549pub fn and(lhs: Expression, rhs: Expression) -> Expression {
569 Binary
570 .try_new_expr(Operator::And, [lhs, rhs])
571 .vortex_expect("Failed to create And binary expression")
572}
573
574pub fn bound_and(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
576 bound_binary(Operator::And, lhs, rhs)
577}
578
579pub fn and_collect<I>(iter: I) -> Option<Expression>
586where
587 I: IntoIterator<Item = Expression>,
588{
589 iter.into_iter().reduce_balanced(and)
590}
591
592pub fn bound_and_collect<I>(iter: I) -> Option<BoundExpression>
594where
595 I: IntoIterator<Item = BoundExpression>,
596{
597 iter.into_iter().reduce_balanced(bound_and)
598}
599
600pub fn union_child_validities(expression: &Expression) -> VortexResult<Option<Expression>> {
608 let child_validities = expression
609 .children()
610 .iter()
611 .map(Expression::validity)
612 .collect::<VortexResult<Vec<_>>>()?;
613 Ok(and_collect(child_validities))
614}
615
616pub fn checked_add(lhs: Expression, rhs: Expression) -> Expression {
635 Binary
636 .try_new_expr(Operator::Add, [lhs, rhs])
637 .vortex_expect("Failed to create Add binary expression")
638}
639
640pub fn bound_checked_add(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
642 bound_binary(Operator::Add, lhs, rhs)
643}
644
645pub fn not(operand: Expression) -> Expression {
656 Not.new_expr(EmptyOptions, vec![operand])
657}
658
659pub fn bound_not(operand: BoundExpression) -> BoundExpression {
661 Not.try_new_bound_expr(EmptyOptions, [operand])
662 .vortex_expect("not expressions require a boolean operand")
663}
664
665pub fn between(
683 arr: Expression,
684 lower: Expression,
685 upper: Expression,
686 options: BetweenOptions,
687) -> Expression {
688 Between
689 .try_new_expr(options, [arr, lower, upper])
690 .vortex_expect("Failed to create Between expression")
691}
692
693pub fn bound_between(
695 arr: BoundExpression,
696 lower: BoundExpression,
697 upper: BoundExpression,
698 options: BetweenOptions,
699) -> BoundExpression {
700 Between
701 .try_new_bound_expr(options, [arr, lower, upper])
702 .vortex_expect("between expressions require compatible operand dtypes")
703}
704
705pub fn select(field_names: impl Into<FieldNames>, child: Expression) -> Expression {
715 Select
716 .try_new_expr(FieldSelection::Include(field_names.into()), [child])
717 .vortex_expect("Failed to create Select expression")
718}
719
720pub fn bound_select(field_names: impl Into<FieldNames>, child: BoundExpression) -> BoundExpression {
722 Select
723 .try_new_bound_expr(FieldSelection::Include(field_names.into()), [child])
724 .vortex_expect("select expressions require fields from a struct child")
725}
726
727pub fn select_exclude(fields: impl Into<FieldNames>, child: Expression) -> Expression {
736 Select
737 .try_new_expr(FieldSelection::Exclude(fields.into()), [child])
738 .vortex_expect("Failed to create Select expression")
739}
740
741pub fn bound_select_exclude(
743 fields: impl Into<FieldNames>,
744 child: BoundExpression,
745) -> BoundExpression {
746 Select
747 .try_new_bound_expr(FieldSelection::Exclude(fields.into()), [child])
748 .vortex_expect("select expressions require fields from a struct child")
749}
750
751pub fn pack(
761 elements: impl IntoIterator<Item = (impl Into<FieldName>, Expression)>,
762 nullability: Nullability,
763) -> Expression {
764 let (names, values): (Vec<_>, Vec<_>) = elements
765 .into_iter()
766 .map(|(name, value)| (name.into(), value))
767 .unzip();
768 Pack.new_expr(
769 PackOptions {
770 names: names.into(),
771 nullability,
772 },
773 values,
774 )
775}
776
777pub fn bound_pack(
779 elements: impl IntoIterator<Item = (impl Into<FieldName>, BoundExpression)>,
780 nullability: Nullability,
781) -> BoundExpression {
782 let (names, values): (Vec<_>, Vec<_>) = elements
783 .into_iter()
784 .map(|(name, value)| (name.into(), value))
785 .unzip();
786 Pack.try_new_bound_expr(
787 PackOptions {
788 names: names.into(),
789 nullability,
790 },
791 values,
792 )
793 .vortex_expect("pack expressions must have one name per child")
794}
795
796pub fn cast(child: Expression, target: DType) -> Expression {
808 Cast.try_new_expr(target, [child])
809 .vortex_expect("Failed to create Cast expression")
810}
811
812pub fn bound_cast(child: BoundExpression, target: DType) -> BoundExpression {
814 Cast.try_new_bound_expr(target, [child])
815 .vortex_expect("cast expressions require a supported source and target dtype")
816}
817
818pub fn fill_null(child: Expression, fill_value: Expression) -> Expression {
827 FillNull.new_expr(EmptyOptions, [child, fill_value])
828}
829
830pub fn bound_fill_null(child: BoundExpression, fill_value: BoundExpression) -> BoundExpression {
832 FillNull
833 .try_new_bound_expr(EmptyOptions, [child, fill_value])
834 .vortex_expect("fill-null expressions require compatible child and fill dtypes")
835}
836
837pub fn is_null(child: Expression) -> Expression {
848 IsNull.new_expr(EmptyOptions, vec![child])
849}
850
851pub fn bound_is_null(child: BoundExpression) -> BoundExpression {
853 IsNull
854 .try_new_bound_expr(EmptyOptions, [child])
855 .vortex_expect("is-null expressions are always well-typed")
856}
857
858pub fn is_not_null(child: Expression) -> Expression {
869 IsNotNull.new_expr(EmptyOptions, vec![child])
870}
871
872pub fn bound_is_not_null(child: BoundExpression) -> BoundExpression {
874 IsNotNull
875 .try_new_bound_expr(EmptyOptions, [child])
876 .vortex_expect("is-not-null expressions are always well-typed")
877}
878
879pub fn like(child: Expression, pattern: Expression) -> Expression {
883 Like.new_expr(
884 LikeOptions {
885 negated: false,
886 case_insensitive: false,
887 },
888 [child, pattern],
889 )
890}
891
892pub fn bound_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
894 bound_like_with_options(child, pattern, false, false)
895}
896
897pub fn ilike(child: Expression, pattern: Expression) -> Expression {
899 Like.new_expr(
900 LikeOptions {
901 negated: false,
902 case_insensitive: true,
903 },
904 [child, pattern],
905 )
906}
907
908pub fn bound_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
910 bound_like_with_options(child, pattern, false, true)
911}
912
913pub fn not_like(child: Expression, pattern: Expression) -> Expression {
915 Like.new_expr(
916 LikeOptions {
917 negated: true,
918 case_insensitive: false,
919 },
920 [child, pattern],
921 )
922}
923
924pub fn bound_not_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
926 bound_like_with_options(child, pattern, true, false)
927}
928
929pub fn not_ilike(child: Expression, pattern: Expression) -> Expression {
931 Like.new_expr(
932 LikeOptions {
933 negated: true,
934 case_insensitive: true,
935 },
936 [child, pattern],
937 )
938}
939
940pub fn bound_not_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
942 bound_like_with_options(child, pattern, true, true)
943}
944
945fn bound_like_with_options(
946 child: BoundExpression,
947 pattern: BoundExpression,
948 negated: bool,
949 case_insensitive: bool,
950) -> BoundExpression {
951 Like.try_new_bound_expr(
952 LikeOptions {
953 negated,
954 case_insensitive,
955 },
956 [child, pattern],
957 )
958 .vortex_expect("like expressions require UTF-8 or binary operands")
959}
960
961pub fn mask(array: Expression, mask: Expression) -> Expression {
965 Mask.new_expr(EmptyOptions, [array, mask])
966}
967
968pub fn bound_mask(array: BoundExpression, mask: BoundExpression) -> BoundExpression {
970 Mask.try_new_bound_expr(EmptyOptions, [array, mask])
971 .vortex_expect("mask expressions require a boolean mask")
972}
973
974pub fn merge(elements: impl IntoIterator<Item = impl Into<Expression>>) -> Expression {
987 use itertools::Itertools as _;
988 let values = elements.into_iter().map(|value| value.into()).collect_vec();
989 Merge.new_expr(DuplicateHandling::default(), values)
990}
991
992pub fn bound_merge(elements: impl IntoIterator<Item = BoundExpression>) -> BoundExpression {
994 bound_merge_opts(elements, DuplicateHandling::default())
995}
996
997pub fn merge_opts(
999 elements: impl IntoIterator<Item = impl Into<Expression>>,
1000 duplicate_handling: DuplicateHandling,
1001) -> Expression {
1002 use itertools::Itertools as _;
1003 let values = elements.into_iter().map(|value| value.into()).collect_vec();
1004 Merge.new_expr(duplicate_handling, values)
1005}
1006
1007pub fn bound_merge_opts(
1009 elements: impl IntoIterator<Item = BoundExpression>,
1010 duplicate_handling: DuplicateHandling,
1011) -> BoundExpression {
1012 Merge
1013 .try_new_bound_expr(duplicate_handling, elements)
1014 .vortex_expect("merge expressions require non-nullable struct children")
1015}
1016
1017pub fn zip_expr(mask: Expression, if_true: Expression, if_false: Expression) -> Expression {
1026 Zip.new_expr(EmptyOptions, [if_true, if_false, mask])
1027}
1028
1029pub fn bound_zip_expr(
1031 mask: BoundExpression,
1032 if_true: BoundExpression,
1033 if_false: BoundExpression,
1034) -> BoundExpression {
1035 Zip.try_new_bound_expr(EmptyOptions, [if_true, if_false, mask])
1036 .vortex_expect("zip expressions require a boolean mask and compatible value dtypes")
1037}
1038
1039pub fn dynamic_with_options(options: DynamicComparisonExpr, lhs: Expression) -> Expression {
1043 DynamicComparison.new_expr(options, [lhs])
1044}
1045
1046pub fn bound_dynamic_with_options(
1048 options: DynamicComparisonExpr,
1049 lhs: BoundExpression,
1050) -> BoundExpression {
1051 DynamicComparison
1052 .try_new_bound_expr(options, [lhs])
1053 .vortex_expect("dynamic comparisons require a compatible left-hand dtype")
1054}
1055
1056pub fn dynamic(
1058 operator: CompareOperator,
1059 rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1060 rhs_dtype: DType,
1061 default: bool,
1062 lhs: Expression,
1063) -> Expression {
1064 dynamic_with_options(
1065 DynamicComparisonExpr {
1066 operator,
1067 rhs: Arc::new(Rhs {
1068 value: Arc::new(rhs_value),
1069 dtype: rhs_dtype,
1070 }),
1071 default,
1072 },
1073 lhs,
1074 )
1075}
1076
1077pub fn bound_dynamic(
1079 operator: CompareOperator,
1080 rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1081 rhs_dtype: DType,
1082 default: bool,
1083 lhs: BoundExpression,
1084) -> BoundExpression {
1085 bound_dynamic_with_options(
1086 DynamicComparisonExpr {
1087 operator,
1088 rhs: Arc::new(Rhs {
1089 value: Arc::new(rhs_value),
1090 dtype: rhs_dtype,
1091 }),
1092 default,
1093 },
1094 lhs,
1095 )
1096}
1097
1098pub fn list_contains(list: Expression, value: Expression) -> Expression {
1109 ListContains.new_expr(EmptyOptions, [list, value])
1110}
1111
1112pub fn bound_list_contains(list: BoundExpression, value: BoundExpression) -> BoundExpression {
1114 ListContains
1115 .try_new_bound_expr(EmptyOptions, [list, value])
1116 .vortex_expect("list-contains expressions require a compatible list and value dtype")
1117}
1118
1119pub fn byte_length(input: Expression) -> Expression {
1129 ByteLength.new_expr(EmptyOptions, [input])
1130}
1131
1132pub fn bound_byte_length(input: BoundExpression) -> BoundExpression {
1134 ByteLength
1135 .try_new_bound_expr(EmptyOptions, [input])
1136 .vortex_expect("byte-length expressions require a variable-length binary child")
1137}
1138
1139pub fn ext_storage(input: Expression) -> Expression {
1148 ExtStorage.new_expr(EmptyOptions, [input])
1149}
1150
1151pub fn bound_ext_storage(input: BoundExpression) -> BoundExpression {
1153 ExtStorage
1154 .try_new_bound_expr(EmptyOptions, [input])
1155 .vortex_expect("extension-storage expressions require an extension child")
1156}
1157
1158pub fn list_length(input: Expression) -> Expression {
1169 ListLength.new_expr(EmptyOptions, [input])
1170}
1171
1172pub fn bound_list_length(input: BoundExpression) -> BoundExpression {
1174 ListLength
1175 .try_new_bound_expr(EmptyOptions, [input])
1176 .vortex_expect("list-length expressions require a list child")
1177}
1178
1179pub fn list_sum(input: Expression) -> Expression {
1194 ListSum.new_expr(NumericalAggregateOpts::default(), [input])
1195}
1196
1197pub fn bound_list_sum(input: BoundExpression) -> BoundExpression {
1199 ListSum
1200 .try_new_bound_expr(NumericalAggregateOpts::default(), [input])
1201 .vortex_expect("list-sum expressions require a numeric list child")
1202}
1203
1204pub fn list_sum_opts(input: Expression, options: NumericalAggregateOpts) -> Expression {
1207 ListSum.new_expr(options, [input])
1208}
1209
1210pub fn bound_list_sum_opts(
1212 input: BoundExpression,
1213 options: NumericalAggregateOpts,
1214) -> BoundExpression {
1215 ListSum
1216 .try_new_bound_expr(options, [input])
1217 .vortex_expect("list-sum expressions require a numeric list child")
1218}
1219
1220pub mod bound {
1226 pub use super::bound_and as and;
1227 pub use super::bound_and_collect as and_collect;
1228 pub use super::bound_between as between;
1229 pub use super::bound_binary as binary;
1230 pub use super::bound_byte_length as byte_length;
1231 pub use super::bound_case_when as case_when;
1232 pub use super::bound_case_when_no_else as case_when_no_else;
1233 pub use super::bound_cast as cast;
1234 pub use super::bound_checked_add as checked_add;
1235 pub use super::bound_col as col;
1236 pub use super::bound_dynamic as dynamic;
1237 pub use super::bound_dynamic_with_options as dynamic_with_options;
1238 pub use super::bound_eq as eq;
1239 pub use super::bound_ext_storage as ext_storage;
1240 pub use super::bound_fill_null as fill_null;
1241 pub use super::bound_get_item as get_item;
1242 pub use super::bound_gt as gt;
1243 pub use super::bound_gt_eq as gt_eq;
1244 pub use super::bound_ilike as ilike;
1245 pub use super::bound_is_not_null as is_not_null;
1246 pub use super::bound_is_null as is_null;
1247 pub use super::bound_like as like;
1248 pub use super::bound_list_contains as list_contains;
1249 pub use super::bound_list_length as list_length;
1250 pub use super::bound_list_sum as list_sum;
1251 pub use super::bound_list_sum_opts as list_sum_opts;
1252 pub use super::bound_lit as lit;
1253 pub use super::bound_lt as lt;
1254 pub use super::bound_lt_eq as lt_eq;
1255 pub use super::bound_mask as mask;
1256 pub use super::bound_merge as merge;
1257 pub use super::bound_merge_opts as merge_opts;
1258 pub use super::bound_nested_case_when as nested_case_when;
1259 pub use super::bound_not as not;
1260 pub use super::bound_not_eq as not_eq;
1261 pub use super::bound_not_ilike as not_ilike;
1262 pub use super::bound_not_like as not_like;
1263 pub use super::bound_or as or;
1264 pub use super::bound_or_collect as or_collect;
1265 pub use super::bound_pack as pack;
1266 pub use super::bound_root as root;
1267 pub use super::bound_select as select;
1268 pub use super::bound_select_exclude as select_exclude;
1269 pub use super::bound_variant_get as variant_get;
1270 pub use super::bound_zip_expr as zip_expr;
1271}