1use std::sync::Arc;
7
8use vortex_error::VortexExpect;
9use vortex_error::vortex_panic;
10use vortex_utils::iter::ReduceBalancedIterExt;
11
12use crate::aggregate_fn::NumericalAggregateOpts;
13use crate::dtype::DType;
14use crate::dtype::FieldName;
15use crate::dtype::FieldNames;
16use crate::dtype::Nullability;
17use crate::expr::BoundExpression;
18use crate::expr::Expression;
19use crate::scalar::Scalar;
20use crate::scalar::ScalarValue;
21use crate::scalar_fn::EmptyOptions;
22use crate::scalar_fn::ScalarFnVTableExt;
23use crate::scalar_fn::fns::between::Between;
24use crate::scalar_fn::fns::between::BetweenOptions;
25use crate::scalar_fn::fns::binary::Binary;
26use crate::scalar_fn::fns::byte_length::ByteLength;
27use crate::scalar_fn::fns::case_when::CaseWhen;
28use crate::scalar_fn::fns::case_when::CaseWhenOptions;
29use crate::scalar_fn::fns::cast::Cast;
30use crate::scalar_fn::fns::dynamic::DynamicComparison;
31use crate::scalar_fn::fns::dynamic::DynamicComparisonExpr;
32use crate::scalar_fn::fns::dynamic::Rhs;
33use crate::scalar_fn::fns::ext_storage::ExtStorage;
34use crate::scalar_fn::fns::fill_null::FillNull;
35use crate::scalar_fn::fns::get_item::GetItem;
36use crate::scalar_fn::fns::is_nan::IsNan;
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_contains::ListContainsOptions;
43use crate::scalar_fn::fns::list_length::ListLength;
44use crate::scalar_fn::fns::list_sum::ListSum;
45use crate::scalar_fn::fns::literal::Literal;
46use crate::scalar_fn::fns::mask::Mask;
47use crate::scalar_fn::fns::merge::DuplicateHandling;
48use crate::scalar_fn::fns::merge::Merge;
49use crate::scalar_fn::fns::not::Not;
50use crate::scalar_fn::fns::operators::CompareOperator;
51use crate::scalar_fn::fns::operators::Operator;
52use crate::scalar_fn::fns::pack::Pack;
53use crate::scalar_fn::fns::pack::PackOptions;
54use crate::scalar_fn::fns::replace_time_zone::ReplaceTimeZone;
55use crate::scalar_fn::fns::replace_time_zone::ReplaceTimeZoneOptions;
56use crate::scalar_fn::fns::select::FieldSelection;
57use crate::scalar_fn::fns::select::Select;
58use crate::scalar_fn::fns::variant_get::VariantGet;
59use crate::scalar_fn::fns::variant_get::VariantGetOptions;
60use crate::scalar_fn::fns::variant_get::VariantPath;
61use crate::scalar_fn::fns::zip::Zip;
62
63pub fn root() -> Expression {
68 Expression::Root
69}
70
71pub fn bound_root(dtype: DType) -> BoundExpression {
73 BoundExpression::new_root(dtype)
74}
75
76pub fn is_root(expr: &Expression) -> bool {
78 expr.is_root()
79}
80
81pub fn lit(value: impl Into<Scalar>) -> Expression {
101 Literal.new_expr(value.into(), [])
102}
103
104pub fn bound_lit(value: impl Into<Scalar>) -> BoundExpression {
106 Literal
107 .try_new_bound_expr(value.into(), [])
108 .vortex_expect("literal expressions are always well-typed")
109}
110
111pub fn col(field: impl Into<FieldName>) -> Expression {
122 GetItem.new_expr(field.into(), vec![root()])
123}
124
125pub fn bound_col(field: impl Into<FieldName>, scope: DType) -> BoundExpression {
127 bound_get_item(field, bound_root(scope))
128}
129
130pub fn get_item(field: impl Into<FieldName>, child: Expression) -> Expression {
139 GetItem.new_expr(field.into(), vec![child])
140}
141
142pub fn bound_get_item(field: impl Into<FieldName>, child: BoundExpression) -> BoundExpression {
144 GetItem
145 .try_new_bound_expr(field.into(), [child])
146 .vortex_expect("get-item expressions must reference a field in the child dtype")
147}
148
149pub fn variant_get(
156 child: Expression,
157 path: impl Into<VariantPath>,
158 dtype: Option<DType>,
159) -> Expression {
160 VariantGet.new_expr(VariantGetOptions::new(path.into(), dtype), vec![child])
161}
162
163pub fn bound_variant_get(
165 child: BoundExpression,
166 path: impl Into<VariantPath>,
167 dtype: Option<DType>,
168) -> BoundExpression {
169 VariantGet
170 .try_new_bound_expr(VariantGetOptions::new(path.into(), dtype), [child])
171 .vortex_expect("variant-get expressions require a Variant child")
172}
173
174pub fn case_when(
178 condition: Expression,
179 then_value: Expression,
180 else_value: Expression,
181) -> Expression {
182 let options = CaseWhenOptions {
183 num_when_then_pairs: 1,
184 has_else: true,
185 };
186 CaseWhen.new_expr(options, [condition, then_value, else_value])
187}
188
189pub fn bound_case_when(
191 condition: BoundExpression,
192 then_value: BoundExpression,
193 else_value: BoundExpression,
194) -> BoundExpression {
195 let options = CaseWhenOptions {
196 num_when_then_pairs: 1,
197 has_else: true,
198 };
199 CaseWhen
200 .try_new_bound_expr(options, [condition, then_value, else_value])
201 .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
202}
203
204pub fn case_when_no_else(condition: Expression, then_value: Expression) -> Expression {
206 let options = CaseWhenOptions {
207 num_when_then_pairs: 1,
208 has_else: false,
209 };
210 CaseWhen.new_expr(options, [condition, then_value])
211}
212
213pub fn bound_case_when_no_else(
215 condition: BoundExpression,
216 then_value: BoundExpression,
217) -> BoundExpression {
218 let options = CaseWhenOptions {
219 num_when_then_pairs: 1,
220 has_else: false,
221 };
222 CaseWhen
223 .try_new_bound_expr(options, [condition, then_value])
224 .vortex_expect("case expressions must have boolean conditions")
225}
226
227pub fn nested_case_when(
229 when_then_pairs: Vec<(Expression, Expression)>,
230 else_value: Option<Expression>,
231) -> Expression {
232 assert!(
233 !when_then_pairs.is_empty(),
234 "nested_case_when requires at least one when/then pair"
235 );
236
237 let has_else = else_value.is_some();
238 let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
239 for (condition, then_value) in &when_then_pairs {
240 children.push(condition.clone());
241 children.push(then_value.clone());
242 }
243 if let Some(else_expr) = else_value {
244 children.push(else_expr);
245 }
246
247 let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
248 vortex_panic!("nested_case_when has too many when/then pairs");
249 };
250 let options = CaseWhenOptions {
251 num_when_then_pairs,
252 has_else,
253 };
254 CaseWhen.new_expr(options, children)
255}
256
257pub fn bound_nested_case_when(
259 when_then_pairs: Vec<(BoundExpression, BoundExpression)>,
260 else_value: Option<BoundExpression>,
261) -> BoundExpression {
262 assert!(
263 !when_then_pairs.is_empty(),
264 "nested_case_when requires at least one when/then pair"
265 );
266
267 let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
268 vortex_panic!("nested_case_when has too many when/then pairs");
269 };
270 let has_else = else_value.is_some();
271 let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
272 for (condition, then_value) in when_then_pairs {
273 children.push(condition);
274 children.push(then_value);
275 }
276 if let Some(else_expr) = else_value {
277 children.push(else_expr);
278 }
279
280 let options = CaseWhenOptions {
281 num_when_then_pairs,
282 has_else,
283 };
284 CaseWhen
285 .try_new_bound_expr(options, children)
286 .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
287}
288
289pub fn binary(operator: Operator, lhs: Expression, rhs: Expression) -> Expression {
293 Binary
294 .try_new_expr(operator, [lhs, rhs])
295 .vortex_expect("Failed to create binary expression")
296}
297
298pub fn bound_binary(
300 operator: Operator,
301 lhs: BoundExpression,
302 rhs: BoundExpression,
303) -> BoundExpression {
304 Binary
305 .try_new_bound_expr(operator, [lhs, rhs])
306 .vortex_expect("binary expressions must have compatible operand dtypes")
307}
308
309pub fn eq(lhs: Expression, rhs: Expression) -> Expression {
331 Binary
332 .try_new_expr(Operator::Eq, [lhs, rhs])
333 .vortex_expect("Failed to create Eq binary expression")
334}
335
336pub fn bound_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
338 bound_binary(Operator::Eq, lhs, rhs)
339}
340
341pub fn not_eq(lhs: Expression, rhs: Expression) -> Expression {
363 Binary
364 .try_new_expr(Operator::NotEq, [lhs, rhs])
365 .vortex_expect("Failed to create NotEq binary expression")
366}
367
368pub fn bound_not_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
370 bound_binary(Operator::NotEq, lhs, rhs)
371}
372
373pub fn gt_eq(lhs: Expression, rhs: Expression) -> Expression {
395 Binary
396 .try_new_expr(Operator::Gte, [lhs, rhs])
397 .vortex_expect("Failed to create Gte binary expression")
398}
399
400pub fn bound_gt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
402 bound_binary(Operator::Gte, lhs, rhs)
403}
404
405pub fn gt(lhs: Expression, rhs: Expression) -> Expression {
427 Binary
428 .try_new_expr(Operator::Gt, [lhs, rhs])
429 .vortex_expect("Failed to create Gt binary expression")
430}
431
432pub fn bound_gt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
434 bound_binary(Operator::Gt, lhs, rhs)
435}
436
437pub fn lt_eq(lhs: Expression, rhs: Expression) -> Expression {
459 Binary
460 .try_new_expr(Operator::Lte, [lhs, rhs])
461 .vortex_expect("Failed to create Lte binary expression")
462}
463
464pub fn bound_lt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
466 bound_binary(Operator::Lte, lhs, rhs)
467}
468
469pub fn lt(lhs: Expression, rhs: Expression) -> Expression {
491 Binary
492 .try_new_expr(Operator::Lt, [lhs, rhs])
493 .vortex_expect("Failed to create Lt binary expression")
494}
495
496pub fn bound_lt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
498 bound_binary(Operator::Lt, lhs, rhs)
499}
500
501pub fn or(lhs: Expression, rhs: Expression) -> Expression {
521 Binary
522 .try_new_expr(Operator::Or, [lhs, rhs])
523 .vortex_expect("Failed to create Or binary expression")
524}
525
526pub fn bound_or(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
528 bound_binary(Operator::Or, lhs, rhs)
529}
530
531pub fn or_collect<I>(iter: I) -> Option<Expression>
538where
539 I: IntoIterator<Item = Expression>,
540{
541 iter.into_iter().reduce_balanced(or)
542}
543
544pub fn bound_or_collect<I>(iter: I) -> Option<BoundExpression>
546where
547 I: IntoIterator<Item = BoundExpression>,
548{
549 iter.into_iter().reduce_balanced(bound_or)
550}
551
552pub fn and(lhs: Expression, rhs: Expression) -> Expression {
572 Binary
573 .try_new_expr(Operator::And, [lhs, rhs])
574 .vortex_expect("Failed to create And binary expression")
575}
576
577pub fn bound_and(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
579 bound_binary(Operator::And, lhs, rhs)
580}
581
582pub fn and_collect<I>(iter: I) -> Option<Expression>
589where
590 I: IntoIterator<Item = Expression>,
591{
592 iter.into_iter().reduce_balanced(and)
593}
594
595pub fn bound_and_collect<I>(iter: I) -> Option<BoundExpression>
597where
598 I: IntoIterator<Item = BoundExpression>,
599{
600 iter.into_iter().reduce_balanced(bound_and)
601}
602
603pub fn checked_add(lhs: Expression, rhs: Expression) -> Expression {
622 Binary
623 .try_new_expr(Operator::Add, [lhs, rhs])
624 .vortex_expect("Failed to create Add binary expression")
625}
626
627pub fn bound_checked_add(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
629 bound_binary(Operator::Add, lhs, rhs)
630}
631
632pub fn not(operand: Expression) -> Expression {
643 Not.new_expr(EmptyOptions, vec![operand])
644}
645
646pub fn bound_not(operand: BoundExpression) -> BoundExpression {
648 Not.try_new_bound_expr(EmptyOptions, [operand])
649 .vortex_expect("not expressions require a boolean operand")
650}
651
652pub fn between(
670 arr: Expression,
671 lower: Expression,
672 upper: Expression,
673 options: BetweenOptions,
674) -> Expression {
675 Between
676 .try_new_expr(options, [arr, lower, upper])
677 .vortex_expect("Failed to create Between expression")
678}
679
680pub fn bound_between(
682 arr: BoundExpression,
683 lower: BoundExpression,
684 upper: BoundExpression,
685 options: BetweenOptions,
686) -> BoundExpression {
687 Between
688 .try_new_bound_expr(options, [arr, lower, upper])
689 .vortex_expect("between expressions require compatible operand dtypes")
690}
691
692pub fn select(field_names: impl Into<FieldNames>, child: Expression) -> Expression {
702 Select
703 .try_new_expr(FieldSelection::Include(field_names.into()), [child])
704 .vortex_expect("Failed to create Select expression")
705}
706
707pub fn bound_select(field_names: impl Into<FieldNames>, child: BoundExpression) -> BoundExpression {
709 Select
710 .try_new_bound_expr(FieldSelection::Include(field_names.into()), [child])
711 .vortex_expect("select expressions require fields from a struct child")
712}
713
714pub fn select_exclude(fields: impl Into<FieldNames>, child: Expression) -> Expression {
723 Select
724 .try_new_expr(FieldSelection::Exclude(fields.into()), [child])
725 .vortex_expect("Failed to create Select expression")
726}
727
728pub fn bound_select_exclude(
730 fields: impl Into<FieldNames>,
731 child: BoundExpression,
732) -> BoundExpression {
733 Select
734 .try_new_bound_expr(FieldSelection::Exclude(fields.into()), [child])
735 .vortex_expect("select expressions require fields from a struct child")
736}
737
738pub fn pack(
748 elements: impl IntoIterator<Item = (impl Into<FieldName>, Expression)>,
749 nullability: Nullability,
750) -> Expression {
751 let (names, values): (Vec<_>, Vec<_>) = elements
752 .into_iter()
753 .map(|(name, value)| (name.into(), value))
754 .unzip();
755 Pack.new_expr(
756 PackOptions {
757 names: names.into(),
758 nullability,
759 },
760 values,
761 )
762}
763
764pub fn bound_pack(
766 elements: impl IntoIterator<Item = (impl Into<FieldName>, BoundExpression)>,
767 nullability: Nullability,
768) -> BoundExpression {
769 let (names, values): (Vec<_>, Vec<_>) = elements
770 .into_iter()
771 .map(|(name, value)| (name.into(), value))
772 .unzip();
773 Pack.try_new_bound_expr(
774 PackOptions {
775 names: names.into(),
776 nullability,
777 },
778 values,
779 )
780 .vortex_expect("pack expressions must have one name per child")
781}
782
783pub fn cast(child: Expression, target: DType) -> Expression {
795 Cast.try_new_expr(target, [child])
796 .vortex_expect("Failed to create Cast expression")
797}
798
799pub fn bound_cast(child: BoundExpression, target: DType) -> BoundExpression {
801 Cast.try_new_bound_expr(target, [child])
802 .vortex_expect("cast expressions require a supported source and target dtype")
803}
804
805pub fn fill_null(child: Expression, fill_value: Expression) -> Expression {
814 FillNull.new_expr(EmptyOptions, [child, fill_value])
815}
816
817pub fn bound_fill_null(child: BoundExpression, fill_value: BoundExpression) -> BoundExpression {
819 FillNull
820 .try_new_bound_expr(EmptyOptions, [child, fill_value])
821 .vortex_expect("fill-null expressions require compatible child and fill dtypes")
822}
823
824pub fn is_null(child: Expression) -> Expression {
835 IsNull.new_expr(EmptyOptions, vec![child])
836}
837
838pub fn bound_is_null(child: BoundExpression) -> BoundExpression {
840 IsNull
841 .try_new_bound_expr(EmptyOptions, [child])
842 .vortex_expect("is-null expressions are always well-typed")
843}
844
845pub fn is_nan(child: Expression) -> Expression {
857 IsNan.new_expr(EmptyOptions, vec![child])
858}
859
860pub fn bound_is_nan(child: BoundExpression) -> BoundExpression {
862 IsNan
863 .try_new_bound_expr(EmptyOptions, [child])
864 .vortex_expect("is-nan expressions are always well-typed")
865}
866
867pub fn is_not_null(child: Expression) -> Expression {
878 IsNotNull.new_expr(EmptyOptions, vec![child])
879}
880
881pub fn bound_is_not_null(child: BoundExpression) -> BoundExpression {
883 IsNotNull
884 .try_new_bound_expr(EmptyOptions, [child])
885 .vortex_expect("is-not-null expressions are always well-typed")
886}
887
888pub fn like(child: Expression, pattern: Expression) -> Expression {
892 Like.new_expr(
893 LikeOptions {
894 negated: false,
895 case_insensitive: false,
896 },
897 [child, pattern],
898 )
899}
900
901pub fn bound_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
903 bound_like_with_options(child, pattern, false, false)
904}
905
906pub fn ilike(child: Expression, pattern: Expression) -> Expression {
908 Like.new_expr(
909 LikeOptions {
910 negated: false,
911 case_insensitive: true,
912 },
913 [child, pattern],
914 )
915}
916
917pub fn bound_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
919 bound_like_with_options(child, pattern, false, true)
920}
921
922pub fn not_like(child: Expression, pattern: Expression) -> Expression {
924 Like.new_expr(
925 LikeOptions {
926 negated: true,
927 case_insensitive: false,
928 },
929 [child, pattern],
930 )
931}
932
933pub fn bound_not_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
935 bound_like_with_options(child, pattern, true, false)
936}
937
938pub fn not_ilike(child: Expression, pattern: Expression) -> Expression {
940 Like.new_expr(
941 LikeOptions {
942 negated: true,
943 case_insensitive: true,
944 },
945 [child, pattern],
946 )
947}
948
949pub fn bound_not_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
951 bound_like_with_options(child, pattern, true, true)
952}
953
954fn bound_like_with_options(
955 child: BoundExpression,
956 pattern: BoundExpression,
957 negated: bool,
958 case_insensitive: bool,
959) -> BoundExpression {
960 Like.try_new_bound_expr(
961 LikeOptions {
962 negated,
963 case_insensitive,
964 },
965 [child, pattern],
966 )
967 .vortex_expect("like expressions require UTF-8 or binary operands")
968}
969
970pub fn mask(array: Expression, mask: Expression) -> Expression {
974 Mask.new_expr(EmptyOptions, [array, mask])
975}
976
977pub fn bound_mask(array: BoundExpression, mask: BoundExpression) -> BoundExpression {
979 Mask.try_new_bound_expr(EmptyOptions, [array, mask])
980 .vortex_expect("mask expressions require a boolean mask")
981}
982
983pub fn merge(elements: impl IntoIterator<Item = impl Into<Expression>>) -> Expression {
996 use itertools::Itertools as _;
997 let values = elements.into_iter().map(|value| value.into()).collect_vec();
998 Merge.new_expr(DuplicateHandling::default(), values)
999}
1000
1001pub fn bound_merge(elements: impl IntoIterator<Item = BoundExpression>) -> BoundExpression {
1003 bound_merge_opts(elements, DuplicateHandling::default())
1004}
1005
1006pub fn merge_opts(
1008 elements: impl IntoIterator<Item = impl Into<Expression>>,
1009 duplicate_handling: DuplicateHandling,
1010) -> Expression {
1011 use itertools::Itertools as _;
1012 let values = elements.into_iter().map(|value| value.into()).collect_vec();
1013 Merge.new_expr(duplicate_handling, values)
1014}
1015
1016pub fn bound_merge_opts(
1018 elements: impl IntoIterator<Item = BoundExpression>,
1019 duplicate_handling: DuplicateHandling,
1020) -> BoundExpression {
1021 Merge
1022 .try_new_bound_expr(duplicate_handling, elements)
1023 .vortex_expect("merge expressions require non-nullable struct children")
1024}
1025
1026pub fn zip_expr(mask: Expression, if_true: Expression, if_false: Expression) -> Expression {
1035 Zip.new_expr(EmptyOptions, [if_true, if_false, mask])
1036}
1037
1038pub fn bound_zip_expr(
1040 mask: BoundExpression,
1041 if_true: BoundExpression,
1042 if_false: BoundExpression,
1043) -> BoundExpression {
1044 Zip.try_new_bound_expr(EmptyOptions, [if_true, if_false, mask])
1045 .vortex_expect("zip expressions require a boolean mask and compatible value dtypes")
1046}
1047
1048pub fn dynamic_with_options(options: DynamicComparisonExpr, lhs: Expression) -> Expression {
1052 DynamicComparison.new_expr(options, [lhs])
1053}
1054
1055pub fn bound_dynamic_with_options(
1057 options: DynamicComparisonExpr,
1058 lhs: BoundExpression,
1059) -> BoundExpression {
1060 DynamicComparison
1061 .try_new_bound_expr(options, [lhs])
1062 .vortex_expect("dynamic comparisons require a compatible left-hand dtype")
1063}
1064
1065pub fn dynamic(
1067 operator: CompareOperator,
1068 rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1069 rhs_dtype: DType,
1070 default: bool,
1071 lhs: Expression,
1072) -> Expression {
1073 dynamic_with_options(
1074 DynamicComparisonExpr {
1075 operator,
1076 rhs: Arc::new(Rhs {
1077 value: Arc::new(rhs_value),
1078 dtype: rhs_dtype,
1079 }),
1080 default,
1081 },
1082 lhs,
1083 )
1084}
1085
1086pub fn bound_dynamic(
1088 operator: CompareOperator,
1089 rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1090 rhs_dtype: DType,
1091 default: bool,
1092 lhs: BoundExpression,
1093) -> BoundExpression {
1094 bound_dynamic_with_options(
1095 DynamicComparisonExpr {
1096 operator,
1097 rhs: Arc::new(Rhs {
1098 value: Arc::new(rhs_value),
1099 dtype: rhs_dtype,
1100 }),
1101 default,
1102 },
1103 lhs,
1104 )
1105}
1106
1107pub fn list_contains(list: Expression, value: Expression) -> Expression {
1119 list_contains_opts(list, value, ListContainsOptions::default())
1120}
1121
1122pub fn list_contains_opts(
1125 list: Expression,
1126 value: Expression,
1127 options: ListContainsOptions,
1128) -> Expression {
1129 ListContains.new_expr(options, [list, value])
1130}
1131
1132pub fn in_list(needle: Expression, list: Expression) -> Expression {
1141 list_contains_opts(
1142 list,
1143 needle,
1144 ListContainsOptions {
1145 sql_null_semantics: true,
1146 },
1147 )
1148}
1149
1150pub fn bound_list_contains(list: BoundExpression, value: BoundExpression) -> BoundExpression {
1152 ListContains
1153 .try_new_bound_expr(ListContainsOptions::default(), [list, value])
1154 .vortex_expect("list-contains expressions require a list child")
1155}
1156
1157pub fn bound_in_list(needle: BoundExpression, list: BoundExpression) -> BoundExpression {
1159 ListContains
1160 .try_new_bound_expr(
1161 ListContainsOptions {
1162 sql_null_semantics: true,
1163 },
1164 [list, needle],
1165 )
1166 .vortex_expect("list-contains expressions require a list child")
1167}
1168
1169pub fn byte_length(input: Expression) -> Expression {
1179 ByteLength.new_expr(EmptyOptions, [input])
1180}
1181
1182pub fn bound_byte_length(input: BoundExpression) -> BoundExpression {
1184 ByteLength
1185 .try_new_bound_expr(EmptyOptions, [input])
1186 .vortex_expect("byte-length expressions require a variable-length binary child")
1187}
1188
1189pub fn ext_storage(input: Expression) -> Expression {
1198 ExtStorage.new_expr(EmptyOptions, [input])
1199}
1200
1201pub fn bound_ext_storage(input: BoundExpression) -> BoundExpression {
1203 ExtStorage
1204 .try_new_bound_expr(EmptyOptions, [input])
1205 .vortex_expect("extension-storage expressions require an extension child")
1206}
1207
1208pub fn list_length(input: Expression) -> Expression {
1219 ListLength.new_expr(EmptyOptions, [input])
1220}
1221
1222pub fn bound_list_length(input: BoundExpression) -> BoundExpression {
1224 ListLength
1225 .try_new_bound_expr(EmptyOptions, [input])
1226 .vortex_expect("list-length expressions require a list child")
1227}
1228
1229pub fn list_sum(input: Expression) -> Expression {
1244 ListSum.new_expr(NumericalAggregateOpts::default(), [input])
1245}
1246
1247pub fn bound_list_sum(input: BoundExpression) -> BoundExpression {
1249 ListSum
1250 .try_new_bound_expr(NumericalAggregateOpts::default(), [input])
1251 .vortex_expect("list-sum expressions require a numeric list child")
1252}
1253
1254pub fn list_sum_opts(input: Expression, options: NumericalAggregateOpts) -> Expression {
1257 ListSum.new_expr(options, [input])
1258}
1259
1260pub fn bound_list_sum_opts(
1262 input: BoundExpression,
1263 options: NumericalAggregateOpts,
1264) -> BoundExpression {
1265 ListSum
1266 .try_new_bound_expr(options, [input])
1267 .vortex_expect("list-sum expressions require a numeric list child")
1268}
1269
1270pub fn replace_time_zone(
1275 input: Expression,
1276 ambiguous: Expression,
1277 options: ReplaceTimeZoneOptions,
1278) -> Expression {
1279 ReplaceTimeZone.new_expr(options, [input, ambiguous])
1280}
1281
1282pub fn bound_replace_time_zone(
1284 input: BoundExpression,
1285 ambiguous: BoundExpression,
1286 options: ReplaceTimeZoneOptions,
1287) -> BoundExpression {
1288 ReplaceTimeZone
1289 .try_new_bound_expr(options, [input, ambiguous])
1290 .vortex_expect("timezone replacement requires a timestamp and a UTF-8 ambiguity policy")
1291}
1292
1293pub mod bound {
1299 pub use super::bound_and as and;
1300 pub use super::bound_and_collect as and_collect;
1301 pub use super::bound_between as between;
1302 pub use super::bound_binary as binary;
1303 pub use super::bound_byte_length as byte_length;
1304 pub use super::bound_case_when as case_when;
1305 pub use super::bound_case_when_no_else as case_when_no_else;
1306 pub use super::bound_cast as cast;
1307 pub use super::bound_checked_add as checked_add;
1308 pub use super::bound_col as col;
1309 pub use super::bound_dynamic as dynamic;
1310 pub use super::bound_dynamic_with_options as dynamic_with_options;
1311 pub use super::bound_eq as eq;
1312 pub use super::bound_ext_storage as ext_storage;
1313 pub use super::bound_fill_null as fill_null;
1314 pub use super::bound_get_item as get_item;
1315 pub use super::bound_gt as gt;
1316 pub use super::bound_gt_eq as gt_eq;
1317 pub use super::bound_ilike as ilike;
1318 pub use super::bound_in_list as in_list;
1319 pub use super::bound_is_nan as is_nan;
1320 pub use super::bound_is_not_null as is_not_null;
1321 pub use super::bound_is_null as is_null;
1322 pub use super::bound_like as like;
1323 pub use super::bound_list_contains as list_contains;
1324 pub use super::bound_list_length as list_length;
1325 pub use super::bound_list_sum as list_sum;
1326 pub use super::bound_list_sum_opts as list_sum_opts;
1327 pub use super::bound_lit as lit;
1328 pub use super::bound_lt as lt;
1329 pub use super::bound_lt_eq as lt_eq;
1330 pub use super::bound_mask as mask;
1331 pub use super::bound_merge as merge;
1332 pub use super::bound_merge_opts as merge_opts;
1333 pub use super::bound_nested_case_when as nested_case_when;
1334 pub use super::bound_not as not;
1335 pub use super::bound_not_eq as not_eq;
1336 pub use super::bound_not_ilike as not_ilike;
1337 pub use super::bound_not_like as not_like;
1338 pub use super::bound_or as or;
1339 pub use super::bound_or_collect as or_collect;
1340 pub use super::bound_pack as pack;
1341 pub use super::bound_replace_time_zone as replace_time_zone;
1342 pub use super::bound_root as root;
1343 pub use super::bound_select as select;
1344 pub use super::bound_select_exclude as select_exclude;
1345 pub use super::bound_variant_get as variant_get;
1346 pub use super::bound_zip_expr as zip_expr;
1347}