Skip to main content

vortex_array/expr/
exprs.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Factory functions for creating [`Expression`]s from scalar function vtables.
5
6use 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::select::FieldSelection;
55use crate::scalar_fn::fns::select::Select;
56use crate::scalar_fn::fns::variant_get::VariantGet;
57use crate::scalar_fn::fns::variant_get::VariantGetOptions;
58use crate::scalar_fn::fns::variant_get::VariantPath;
59use crate::scalar_fn::fns::zip::Zip;
60
61/// Creates an expression that references the root scope.
62///
63/// Returns the entire input array as passed to the expression evaluator.
64/// This is commonly used as the starting point for field access and other operations.
65pub fn root() -> Expression {
66    Expression::Root
67}
68
69/// Creates a bound expression that references a root scope with the given dtype.
70pub fn bound_root(dtype: DType) -> BoundExpression {
71    BoundExpression::new_root(dtype)
72}
73
74/// Return whether the expression is a root expression.
75pub fn is_root(expr: &Expression) -> bool {
76    expr.is_root()
77}
78
79// ---- Literal ----
80
81/// Create a new `Literal` expression from a type that coerces to `Scalar`.
82///
83///
84/// ## Example usage
85///
86/// ```
87/// use vortex_array::arrays::PrimitiveArray;
88/// use vortex_array::dtype::Nullability;
89/// use vortex_array::expr::lit;
90/// use vortex_array::scalar_fn::fns::literal::Literal;
91/// use vortex_array::scalar::Scalar;
92///
93/// let number = lit(34i32);
94///
95/// let scalar = number.as_::<Literal>();
96/// assert_eq!(scalar, &Scalar::primitive(34i32, Nullability::NonNullable));
97/// ```
98pub fn lit(value: impl Into<Scalar>) -> Expression {
99    Literal.new_expr(value.into(), [])
100}
101
102/// Creates a bound literal expression.
103pub fn bound_lit(value: impl Into<Scalar>) -> BoundExpression {
104    Literal
105        .try_new_bound_expr(value.into(), [])
106        .vortex_expect("literal expressions are always well-typed")
107}
108
109// ---- GetItem / Col ----
110
111/// Creates an expression that accesses a field from the root array.
112///
113/// Equivalent to `get_item(field, root())` - extracts a named field from the input array.
114///
115/// ```rust
116/// # use vortex_array::expr::col;
117/// let expr = col("name");
118/// ```
119pub fn col(field: impl Into<FieldName>) -> Expression {
120    GetItem.new_expr(field.into(), vec![root()])
121}
122
123/// Creates a bound expression that accesses a field from a root scope with the given dtype.
124pub fn bound_col(field: impl Into<FieldName>, scope: DType) -> BoundExpression {
125    bound_get_item(field, bound_root(scope))
126}
127
128/// Creates an expression that extracts a named field from a struct expression.
129///
130/// Accesses the specified field from the result of the child expression.
131///
132/// ```rust
133/// # use vortex_array::expr::{get_item, root};
134/// let expr = get_item("user_id", root());
135/// ```
136pub fn get_item(field: impl Into<FieldName>, child: Expression) -> Expression {
137    GetItem.new_expr(field.into(), vec![child])
138}
139
140/// Creates a bound expression that extracts a named field from a struct expression.
141pub fn bound_get_item(field: impl Into<FieldName>, child: BoundExpression) -> BoundExpression {
142    GetItem
143        .try_new_bound_expr(field.into(), [child])
144        .vortex_expect("get-item expressions must reference a field in the child dtype")
145}
146
147// ---- VariantGet ----
148
149/// Creates an expression that extracts a path from a Variant expression.
150///
151/// Missing paths, traversal mismatches, and failed casts return null. When `dtype` is `None`,
152/// results are nullable Variant values; otherwise results are nullable values of `dtype`.
153pub fn variant_get(
154    child: Expression,
155    path: impl Into<VariantPath>,
156    dtype: Option<DType>,
157) -> Expression {
158    VariantGet.new_expr(VariantGetOptions::new(path.into(), dtype), vec![child])
159}
160
161/// Creates a bound expression that extracts a path from a Variant expression.
162pub fn bound_variant_get(
163    child: BoundExpression,
164    path: impl Into<VariantPath>,
165    dtype: Option<DType>,
166) -> BoundExpression {
167    VariantGet
168        .try_new_bound_expr(VariantGetOptions::new(path.into(), dtype), [child])
169        .vortex_expect("variant-get expressions require a Variant child")
170}
171
172// ---- CaseWhen ----
173
174/// Creates a CASE WHEN expression with one WHEN/THEN pair and an ELSE value.
175pub fn case_when(
176    condition: Expression,
177    then_value: Expression,
178    else_value: Expression,
179) -> Expression {
180    let options = CaseWhenOptions {
181        num_when_then_pairs: 1,
182        has_else: true,
183    };
184    CaseWhen.new_expr(options, [condition, then_value, else_value])
185}
186
187/// Creates a bound CASE WHEN expression with one WHEN/THEN pair and an ELSE value.
188pub fn bound_case_when(
189    condition: BoundExpression,
190    then_value: BoundExpression,
191    else_value: BoundExpression,
192) -> BoundExpression {
193    let options = CaseWhenOptions {
194        num_when_then_pairs: 1,
195        has_else: true,
196    };
197    CaseWhen
198        .try_new_bound_expr(options, [condition, then_value, else_value])
199        .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
200}
201
202/// Creates a CASE WHEN expression with one WHEN/THEN pair and no ELSE value.
203pub fn case_when_no_else(condition: Expression, then_value: Expression) -> Expression {
204    let options = CaseWhenOptions {
205        num_when_then_pairs: 1,
206        has_else: false,
207    };
208    CaseWhen.new_expr(options, [condition, then_value])
209}
210
211/// Creates a bound CASE WHEN expression with one WHEN/THEN pair and no ELSE value.
212pub fn bound_case_when_no_else(
213    condition: BoundExpression,
214    then_value: BoundExpression,
215) -> BoundExpression {
216    let options = CaseWhenOptions {
217        num_when_then_pairs: 1,
218        has_else: false,
219    };
220    CaseWhen
221        .try_new_bound_expr(options, [condition, then_value])
222        .vortex_expect("case expressions must have boolean conditions")
223}
224
225/// Creates an n-ary CASE WHEN expression from WHEN/THEN pairs and an optional ELSE value.
226pub fn nested_case_when(
227    when_then_pairs: Vec<(Expression, Expression)>,
228    else_value: Option<Expression>,
229) -> Expression {
230    assert!(
231        !when_then_pairs.is_empty(),
232        "nested_case_when requires at least one when/then pair"
233    );
234
235    let has_else = else_value.is_some();
236    let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
237    for (condition, then_value) in &when_then_pairs {
238        children.push(condition.clone());
239        children.push(then_value.clone());
240    }
241    if let Some(else_expr) = else_value {
242        children.push(else_expr);
243    }
244
245    let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
246        vortex_panic!("nested_case_when has too many when/then pairs");
247    };
248    let options = CaseWhenOptions {
249        num_when_then_pairs,
250        has_else,
251    };
252    CaseWhen.new_expr(options, children)
253}
254
255/// Creates a bound n-ary CASE WHEN expression from WHEN/THEN pairs and an optional ELSE value.
256pub fn bound_nested_case_when(
257    when_then_pairs: Vec<(BoundExpression, BoundExpression)>,
258    else_value: Option<BoundExpression>,
259) -> BoundExpression {
260    assert!(
261        !when_then_pairs.is_empty(),
262        "nested_case_when requires at least one when/then pair"
263    );
264
265    let Ok(num_when_then_pairs) = u32::try_from(when_then_pairs.len()) else {
266        vortex_panic!("nested_case_when has too many when/then pairs");
267    };
268    let has_else = else_value.is_some();
269    let mut children = Vec::with_capacity(when_then_pairs.len() * 2 + usize::from(has_else));
270    for (condition, then_value) in when_then_pairs {
271        children.push(condition);
272        children.push(then_value);
273    }
274    if let Some(else_expr) = else_value {
275        children.push(else_expr);
276    }
277
278    let options = CaseWhenOptions {
279        num_when_then_pairs,
280        has_else,
281    };
282    CaseWhen
283        .try_new_bound_expr(options, children)
284        .vortex_expect("case expressions must have boolean conditions and matching branch dtypes")
285}
286
287// ---- Binary operators ----
288
289/// Creates a binary expression with the given operator.
290pub fn binary(operator: Operator, lhs: Expression, rhs: Expression) -> Expression {
291    Binary
292        .try_new_expr(operator, [lhs, rhs])
293        .vortex_expect("Failed to create binary expression")
294}
295
296/// Creates a bound binary expression with the given operator.
297pub fn bound_binary(
298    operator: Operator,
299    lhs: BoundExpression,
300    rhs: BoundExpression,
301) -> BoundExpression {
302    Binary
303        .try_new_bound_expr(operator, [lhs, rhs])
304        .vortex_expect("binary expressions must have compatible operand dtypes")
305}
306
307/// Create a new [`Binary`] using the [`Eq`](Operator::Eq) operator.
308///
309/// ## Example usage
310///
311/// ```
312/// # use vortex_array::arrays::{BoolArray, PrimitiveArray};
313/// # use vortex_array::arrays::bool::BoolArrayExt;
314/// # use vortex_array::IntoArray;
315/// # use vortex_array::{VortexSessionExecute, array_session};
316/// # use vortex_array::validity::Validity;
317/// # use vortex_buffer::buffer;
318/// # use vortex_array::expr::{eq, root, lit};
319/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
320/// let result = xs.into_array().apply(&eq(root(), lit(3))).unwrap();
321/// let mut ctx = array_session().create_execution_ctx();
322///
323/// assert_eq!(
324///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
325///     BoolArray::from_iter(vec![false, false, true]).to_bit_buffer(),
326/// );
327/// ```
328pub fn eq(lhs: Expression, rhs: Expression) -> Expression {
329    Binary
330        .try_new_expr(Operator::Eq, [lhs, rhs])
331        .vortex_expect("Failed to create Eq binary expression")
332}
333
334/// Creates a bound equality expression.
335pub fn bound_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
336    bound_binary(Operator::Eq, lhs, rhs)
337}
338
339/// Create a new [`Binary`] using the [`NotEq`](Operator::NotEq) operator.
340///
341/// ## Example usage
342///
343/// ```
344/// # use vortex_array::arrays::{BoolArray, PrimitiveArray};
345/// # use vortex_array::arrays::bool::BoolArrayExt;
346/// # use vortex_array::IntoArray;
347/// # use vortex_array::{VortexSessionExecute, array_session};
348/// # use vortex_array::validity::Validity;
349/// # use vortex_buffer::buffer;
350/// # use vortex_array::expr::{root, lit, not_eq};
351/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
352/// let result = xs.into_array().apply(&not_eq(root(), lit(3))).unwrap();
353/// let mut ctx = array_session().create_execution_ctx();
354///
355/// assert_eq!(
356///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
357///     BoolArray::from_iter(vec![true, true, false]).to_bit_buffer(),
358/// );
359/// ```
360pub fn not_eq(lhs: Expression, rhs: Expression) -> Expression {
361    Binary
362        .try_new_expr(Operator::NotEq, [lhs, rhs])
363        .vortex_expect("Failed to create NotEq binary expression")
364}
365
366/// Creates a bound inequality expression.
367pub fn bound_not_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
368    bound_binary(Operator::NotEq, lhs, rhs)
369}
370
371/// Create a new [`Binary`] using the [`Gte`](Operator::Gte) operator.
372///
373/// ## Example usage
374///
375/// ```
376/// # use vortex_array::arrays::{BoolArray, PrimitiveArray };
377/// # use vortex_array::arrays::bool::BoolArrayExt;
378/// # use vortex_array::IntoArray;
379/// # use vortex_array::{VortexSessionExecute, array_session};
380/// # use vortex_array::validity::Validity;
381/// # use vortex_buffer::buffer;
382/// # use vortex_array::expr::{gt_eq, root, lit};
383/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
384/// let result = xs.into_array().apply(&gt_eq(root(), lit(3))).unwrap();
385/// let mut ctx = array_session().create_execution_ctx();
386///
387/// assert_eq!(
388///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
389///     BoolArray::from_iter(vec![false, false, true]).to_bit_buffer(),
390/// );
391/// ```
392pub fn gt_eq(lhs: Expression, rhs: Expression) -> Expression {
393    Binary
394        .try_new_expr(Operator::Gte, [lhs, rhs])
395        .vortex_expect("Failed to create Gte binary expression")
396}
397
398/// Creates a bound greater-than-or-equal expression.
399pub fn bound_gt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
400    bound_binary(Operator::Gte, lhs, rhs)
401}
402
403/// Create a new [`Binary`] using the [`Gt`](Operator::Gt) operator.
404///
405/// ## Example usage
406///
407/// ```
408/// # use vortex_array::arrays::{BoolArray, PrimitiveArray };
409/// # use vortex_array::arrays::bool::BoolArrayExt;
410/// # use vortex_array::IntoArray;
411/// # use vortex_array::{VortexSessionExecute, array_session};
412/// # use vortex_array::validity::Validity;
413/// # use vortex_buffer::buffer;
414/// # use vortex_array::expr::{gt, root, lit};
415/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
416/// let result = xs.into_array().apply(&gt(root(), lit(2))).unwrap();
417/// let mut ctx = array_session().create_execution_ctx();
418///
419/// assert_eq!(
420///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
421///     BoolArray::from_iter(vec![false, false, true]).to_bit_buffer(),
422/// );
423/// ```
424pub fn gt(lhs: Expression, rhs: Expression) -> Expression {
425    Binary
426        .try_new_expr(Operator::Gt, [lhs, rhs])
427        .vortex_expect("Failed to create Gt binary expression")
428}
429
430/// Creates a bound greater-than expression.
431pub fn bound_gt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
432    bound_binary(Operator::Gt, lhs, rhs)
433}
434
435/// Create a new [`Binary`] using the [`Lte`](Operator::Lte) operator.
436///
437/// ## Example usage
438///
439/// ```
440/// # use vortex_array::arrays::{BoolArray, PrimitiveArray };
441/// # use vortex_array::arrays::bool::BoolArrayExt;
442/// # use vortex_array::IntoArray;
443/// # use vortex_array::{VortexSessionExecute, array_session};
444/// # use vortex_array::validity::Validity;
445/// # use vortex_buffer::buffer;
446/// # use vortex_array::expr::{root, lit, lt_eq};
447/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
448/// let result = xs.into_array().apply(&lt_eq(root(), lit(2))).unwrap();
449/// let mut ctx = array_session().create_execution_ctx();
450///
451/// assert_eq!(
452///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
453///     BoolArray::from_iter(vec![true, true, false]).to_bit_buffer(),
454/// );
455/// ```
456pub fn lt_eq(lhs: Expression, rhs: Expression) -> Expression {
457    Binary
458        .try_new_expr(Operator::Lte, [lhs, rhs])
459        .vortex_expect("Failed to create Lte binary expression")
460}
461
462/// Creates a bound less-than-or-equal expression.
463pub fn bound_lt_eq(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
464    bound_binary(Operator::Lte, lhs, rhs)
465}
466
467/// Create a new [`Binary`] using the [`Lt`](Operator::Lt) operator.
468///
469/// ## Example usage
470///
471/// ```
472/// # use vortex_array::arrays::{BoolArray, PrimitiveArray };
473/// # use vortex_array::arrays::bool::BoolArrayExt;
474/// # use vortex_array::IntoArray;
475/// # use vortex_array::{VortexSessionExecute, array_session};
476/// # use vortex_array::validity::Validity;
477/// # use vortex_buffer::buffer;
478/// # use vortex_array::expr::{root, lit, lt};
479/// let xs = PrimitiveArray::new(buffer![1i32, 2i32, 3i32], Validity::NonNullable);
480/// let result = xs.into_array().apply(&lt(root(), lit(3))).unwrap();
481/// let mut ctx = array_session().create_execution_ctx();
482///
483/// assert_eq!(
484///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
485///     BoolArray::from_iter(vec![true, true, false]).to_bit_buffer(),
486/// );
487/// ```
488pub fn lt(lhs: Expression, rhs: Expression) -> Expression {
489    Binary
490        .try_new_expr(Operator::Lt, [lhs, rhs])
491        .vortex_expect("Failed to create Lt binary expression")
492}
493
494/// Creates a bound less-than expression.
495pub fn bound_lt(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
496    bound_binary(Operator::Lt, lhs, rhs)
497}
498
499/// Create a new [`Binary`] using the [`Or`](Operator::Or) operator.
500///
501/// ## Example usage
502///
503/// ```
504/// # use vortex_array::arrays::BoolArray;
505/// # use vortex_array::arrays::bool::BoolArrayExt;
506/// # use vortex_array::IntoArray;
507/// # use vortex_array::{VortexSessionExecute, array_session};
508/// # use vortex_array::expr::{root, lit, or};
509/// let xs = BoolArray::from_iter(vec![true, false, true]);
510/// let result = xs.into_array().apply(&or(root(), lit(false))).unwrap();
511/// let mut ctx = array_session().create_execution_ctx();
512///
513/// assert_eq!(
514///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
515///     BoolArray::from_iter(vec![true, false, true]).to_bit_buffer(),
516/// );
517/// ```
518pub fn or(lhs: Expression, rhs: Expression) -> Expression {
519    Binary
520        .try_new_expr(Operator::Or, [lhs, rhs])
521        .vortex_expect("Failed to create Or binary expression")
522}
523
524/// Creates a bound boolean OR expression.
525pub fn bound_or(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
526    bound_binary(Operator::Or, lhs, rhs)
527}
528
529/// Collects a list of `or`ed values into a single expression using a balanced tree.
530///
531/// This creates a balanced binary tree to avoid deep nesting that could cause
532/// stack overflow during drop or evaluation.
533///
534/// [a, b, c, d] => or(or(a, b), or(c, d))
535pub fn or_collect<I>(iter: I) -> Option<Expression>
536where
537    I: IntoIterator<Item = Expression>,
538{
539    iter.into_iter().reduce_balanced(or)
540}
541
542/// Collects bound expressions into a balanced tree of boolean OR expressions.
543pub fn bound_or_collect<I>(iter: I) -> Option<BoundExpression>
544where
545    I: IntoIterator<Item = BoundExpression>,
546{
547    iter.into_iter().reduce_balanced(bound_or)
548}
549
550/// Create a new [`Binary`] using the [`And`](Operator::And) operator.
551///
552/// ## Example usage
553///
554/// ```
555/// # use vortex_array::arrays::BoolArray;
556/// # use vortex_array::arrays::bool::BoolArrayExt;
557/// # use vortex_array::IntoArray;
558/// # use vortex_array::{VortexSessionExecute, array_session};
559/// # use vortex_array::expr::{and, root, lit};
560/// let xs = BoolArray::from_iter(vec![true, false, true]).into_array();
561/// let result = xs.apply(&and(root(), lit(true))).unwrap();
562/// let mut ctx = array_session().create_execution_ctx();
563///
564/// assert_eq!(
565///     result.execute::<BoolArray>(&mut ctx).unwrap().to_bit_buffer(),
566///     BoolArray::from_iter(vec![true, false, true]).to_bit_buffer(),
567/// );
568/// ```
569pub fn and(lhs: Expression, rhs: Expression) -> Expression {
570    Binary
571        .try_new_expr(Operator::And, [lhs, rhs])
572        .vortex_expect("Failed to create And binary expression")
573}
574
575/// Creates a bound boolean AND expression.
576pub fn bound_and(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
577    bound_binary(Operator::And, lhs, rhs)
578}
579
580/// Collects a list of `and`ed values into a single expression using a balanced tree.
581///
582/// This creates a balanced binary tree to avoid deep nesting that could cause
583/// stack overflow during drop or evaluation.
584///
585/// [a, b, c, d] => and(and(a, b), and(c, d))
586pub fn and_collect<I>(iter: I) -> Option<Expression>
587where
588    I: IntoIterator<Item = Expression>,
589{
590    iter.into_iter().reduce_balanced(and)
591}
592
593/// Collects bound expressions into a balanced tree of boolean AND expressions.
594pub fn bound_and_collect<I>(iter: I) -> Option<BoundExpression>
595where
596    I: IntoIterator<Item = BoundExpression>,
597{
598    iter.into_iter().reduce_balanced(bound_and)
599}
600
601/// Create a new [`Binary`] using the [`Add`](Operator::Add) operator.
602///
603/// ## Example usage
604///
605/// ```
606/// # use vortex_array::IntoArray;
607/// # use vortex_array::arrays::PrimitiveArray;
608/// # use vortex_array::builtins::ArrayBuiltins;
609/// # use vortex_array::{VortexSessionExecute, array_session};
610/// # use vortex_buffer::buffer;
611/// # use vortex_array::expr::{checked_add, lit, root};
612/// let xs = buffer![1, 2, 3].into_array();
613/// let result = xs.apply(&checked_add(root(), lit(5))).unwrap();
614///
615/// let mut ctx = array_session().create_execution_ctx();
616/// let result = result.execute::<PrimitiveArray>(&mut ctx).unwrap();
617/// assert_eq!(result.as_slice::<i32>(), [6, 7, 8]);
618/// ```
619pub fn checked_add(lhs: Expression, rhs: Expression) -> Expression {
620    Binary
621        .try_new_expr(Operator::Add, [lhs, rhs])
622        .vortex_expect("Failed to create Add binary expression")
623}
624
625/// Creates a bound checked-add expression.
626pub fn bound_checked_add(lhs: BoundExpression, rhs: BoundExpression) -> BoundExpression {
627    bound_binary(Operator::Add, lhs, rhs)
628}
629
630// ---- Not ----
631
632/// Creates an expression that logically inverts boolean values.
633///
634/// Returns the logical negation of the input boolean expression.
635///
636/// ```rust
637/// # use vortex_array::expr::{not, root};
638/// let expr = not(root());
639/// ```
640pub fn not(operand: Expression) -> Expression {
641    Not.new_expr(EmptyOptions, vec![operand])
642}
643
644/// Creates a bound expression that logically inverts boolean values.
645pub fn bound_not(operand: BoundExpression) -> BoundExpression {
646    Not.try_new_bound_expr(EmptyOptions, [operand])
647        .vortex_expect("not expressions require a boolean operand")
648}
649
650// ---- Between ----
651
652/// Creates an expression that checks if values are between two bounds.
653///
654/// Returns a boolean array indicating which values fall within the specified range.
655/// The comparison strictness is controlled by the options parameter.
656///
657/// ```rust
658/// # use vortex_array::scalar_fn::fns::between::BetweenOptions;
659/// # use vortex_array::scalar_fn::fns::between::StrictComparison;
660/// # use vortex_array::expr::{between, lit, root};
661/// let opts = BetweenOptions {
662///     lower_strict: StrictComparison::NonStrict,
663///     upper_strict: StrictComparison::NonStrict,
664/// };
665/// let expr = between(root(), lit(10), lit(20), opts);
666/// ```
667pub fn between(
668    arr: Expression,
669    lower: Expression,
670    upper: Expression,
671    options: BetweenOptions,
672) -> Expression {
673    Between
674        .try_new_expr(options, [arr, lower, upper])
675        .vortex_expect("Failed to create Between expression")
676}
677
678/// Creates a bound expression that checks if values are between two bounds.
679pub fn bound_between(
680    arr: BoundExpression,
681    lower: BoundExpression,
682    upper: BoundExpression,
683    options: BetweenOptions,
684) -> BoundExpression {
685    Between
686        .try_new_bound_expr(options, [arr, lower, upper])
687        .vortex_expect("between expressions require compatible operand dtypes")
688}
689
690// ---- Select ----
691
692/// Creates an expression that selects (includes) specific fields from an array.
693///
694/// Projects only the specified fields from the child expression, which must be of DType struct.
695/// ```rust
696/// # use vortex_array::expr::{select, root};
697/// let expr = select(["name", "age"], root());
698/// ```
699pub fn select(field_names: impl Into<FieldNames>, child: Expression) -> Expression {
700    Select
701        .try_new_expr(FieldSelection::Include(field_names.into()), [child])
702        .vortex_expect("Failed to create Select expression")
703}
704
705/// Creates a bound expression that selects specific fields from a struct expression.
706pub fn bound_select(field_names: impl Into<FieldNames>, child: BoundExpression) -> BoundExpression {
707    Select
708        .try_new_bound_expr(FieldSelection::Include(field_names.into()), [child])
709        .vortex_expect("select expressions require fields from a struct child")
710}
711
712/// Creates an expression that excludes specific fields from an array.
713///
714/// Projects all fields except the specified ones from the input struct expression.
715///
716/// ```rust
717/// # use vortex_array::expr::{select_exclude, root};
718/// let expr = select_exclude(["internal_id", "metadata"], root());
719/// ```
720pub fn select_exclude(fields: impl Into<FieldNames>, child: Expression) -> Expression {
721    Select
722        .try_new_expr(FieldSelection::Exclude(fields.into()), [child])
723        .vortex_expect("Failed to create Select expression")
724}
725
726/// Creates a bound expression that excludes specific fields from a struct expression.
727pub fn bound_select_exclude(
728    fields: impl Into<FieldNames>,
729    child: BoundExpression,
730) -> BoundExpression {
731    Select
732        .try_new_bound_expr(FieldSelection::Exclude(fields.into()), [child])
733        .vortex_expect("select expressions require fields from a struct child")
734}
735
736// ---- Pack ----
737
738/// Creates an expression that packs values into a struct with named fields.
739///
740/// ```rust
741/// # use vortex_array::dtype::Nullability;
742/// # use vortex_array::expr::{pack, col, lit};
743/// let expr = pack([("id", col("user_id")), ("constant", lit(42))], Nullability::NonNullable);
744/// ```
745pub fn pack(
746    elements: impl IntoIterator<Item = (impl Into<FieldName>, Expression)>,
747    nullability: Nullability,
748) -> Expression {
749    let (names, values): (Vec<_>, Vec<_>) = elements
750        .into_iter()
751        .map(|(name, value)| (name.into(), value))
752        .unzip();
753    Pack.new_expr(
754        PackOptions {
755            names: names.into(),
756            nullability,
757        },
758        values,
759    )
760}
761
762/// Creates a bound expression that packs values into a struct with named fields.
763pub fn bound_pack(
764    elements: impl IntoIterator<Item = (impl Into<FieldName>, BoundExpression)>,
765    nullability: Nullability,
766) -> BoundExpression {
767    let (names, values): (Vec<_>, Vec<_>) = elements
768        .into_iter()
769        .map(|(name, value)| (name.into(), value))
770        .unzip();
771    Pack.try_new_bound_expr(
772        PackOptions {
773            names: names.into(),
774            nullability,
775        },
776        values,
777    )
778    .vortex_expect("pack expressions must have one name per child")
779}
780
781// ---- Cast ----
782
783/// Creates an expression that casts values to a target data type.
784///
785/// Converts the input expression's values to the specified target type.
786///
787/// ```rust
788/// # use vortex_array::dtype::{DType, Nullability, PType};
789/// # use vortex_array::expr::{cast, root};
790/// let expr = cast(root(), DType::Primitive(PType::I64, Nullability::NonNullable));
791/// ```
792pub fn cast(child: Expression, target: DType) -> Expression {
793    Cast.try_new_expr(target, [child])
794        .vortex_expect("Failed to create Cast expression")
795}
796
797/// Creates a bound expression that casts values to a target dtype.
798pub fn bound_cast(child: BoundExpression, target: DType) -> BoundExpression {
799    Cast.try_new_bound_expr(target, [child])
800        .vortex_expect("cast expressions require a supported source and target dtype")
801}
802
803// ---- FillNull ----
804
805/// Creates an expression that replaces null values with a fill value.
806///
807/// ```rust
808/// # use vortex_array::expr::{fill_null, root, lit};
809/// let expr = fill_null(root(), lit(0i32));
810/// ```
811pub fn fill_null(child: Expression, fill_value: Expression) -> Expression {
812    FillNull.new_expr(EmptyOptions, [child, fill_value])
813}
814
815/// Creates a bound expression that replaces null values with a fill value.
816pub fn bound_fill_null(child: BoundExpression, fill_value: BoundExpression) -> BoundExpression {
817    FillNull
818        .try_new_bound_expr(EmptyOptions, [child, fill_value])
819        .vortex_expect("fill-null expressions require compatible child and fill dtypes")
820}
821
822// ---- IsNull ----
823
824/// Creates an expression that checks for null values.
825///
826/// Returns a boolean array indicating which positions contain null values.
827///
828/// ```rust
829/// # use vortex_array::expr::{is_null, root};
830/// let expr = is_null(root());
831/// ```
832pub fn is_null(child: Expression) -> Expression {
833    IsNull.new_expr(EmptyOptions, vec![child])
834}
835
836/// Creates a bound expression that checks for null values.
837pub fn bound_is_null(child: BoundExpression) -> BoundExpression {
838    IsNull
839        .try_new_bound_expr(EmptyOptions, [child])
840        .vortex_expect("is-null expressions are always well-typed")
841}
842
843// ---- IsNan ----
844
845/// Creates an expression that checks for NaN values.
846///
847/// The expression is strict: null inputs produce null outputs, so the output nullability
848/// follows the input. Only primitive float inputs are supported.
849///
850/// ```rust
851/// # use vortex_array::expr::{is_nan, root};
852/// let expr = is_nan(root());
853/// ```
854pub fn is_nan(child: Expression) -> Expression {
855    IsNan.new_expr(EmptyOptions, vec![child])
856}
857
858/// Creates a bound expression that checks for NaN values.
859pub fn bound_is_nan(child: BoundExpression) -> BoundExpression {
860    IsNan
861        .try_new_bound_expr(EmptyOptions, [child])
862        .vortex_expect("is-nan expressions are always well-typed")
863}
864
865// ---- IsNotNull ----
866
867/// Creates an expression that checks for non-null values.
868///
869/// Returns a boolean array indicating which positions contain non-null values.
870///
871/// ```rust
872/// # use vortex_array::expr::{is_not_null, root};
873/// let expr = is_not_null(root());
874/// ```
875pub fn is_not_null(child: Expression) -> Expression {
876    IsNotNull.new_expr(EmptyOptions, vec![child])
877}
878
879/// Creates a bound expression that checks for non-null values.
880pub fn bound_is_not_null(child: BoundExpression) -> BoundExpression {
881    IsNotNull
882        .try_new_bound_expr(EmptyOptions, [child])
883        .vortex_expect("is-not-null expressions are always well-typed")
884}
885
886// ---- Like ----
887
888/// Creates a SQL LIKE expression.
889pub fn like(child: Expression, pattern: Expression) -> Expression {
890    Like.new_expr(
891        LikeOptions {
892            negated: false,
893            case_insensitive: false,
894        },
895        [child, pattern],
896    )
897}
898
899/// Creates a bound SQL LIKE expression.
900pub fn bound_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
901    bound_like_with_options(child, pattern, false, false)
902}
903
904/// Creates a case-insensitive SQL ILIKE expression.
905pub fn ilike(child: Expression, pattern: Expression) -> Expression {
906    Like.new_expr(
907        LikeOptions {
908            negated: false,
909            case_insensitive: true,
910        },
911        [child, pattern],
912    )
913}
914
915/// Creates a bound case-insensitive SQL ILIKE expression.
916pub fn bound_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
917    bound_like_with_options(child, pattern, false, true)
918}
919
920/// Creates a negated SQL NOT LIKE expression.
921pub fn not_like(child: Expression, pattern: Expression) -> Expression {
922    Like.new_expr(
923        LikeOptions {
924            negated: true,
925            case_insensitive: false,
926        },
927        [child, pattern],
928    )
929}
930
931/// Creates a bound negated SQL NOT LIKE expression.
932pub fn bound_not_like(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
933    bound_like_with_options(child, pattern, true, false)
934}
935
936/// Creates a negated case-insensitive SQL NOT ILIKE expression.
937pub fn not_ilike(child: Expression, pattern: Expression) -> Expression {
938    Like.new_expr(
939        LikeOptions {
940            negated: true,
941            case_insensitive: true,
942        },
943        [child, pattern],
944    )
945}
946
947/// Creates a bound negated case-insensitive SQL NOT ILIKE expression.
948pub fn bound_not_ilike(child: BoundExpression, pattern: BoundExpression) -> BoundExpression {
949    bound_like_with_options(child, pattern, true, true)
950}
951
952fn bound_like_with_options(
953    child: BoundExpression,
954    pattern: BoundExpression,
955    negated: bool,
956    case_insensitive: bool,
957) -> BoundExpression {
958    Like.try_new_bound_expr(
959        LikeOptions {
960            negated,
961            case_insensitive,
962        },
963        [child, pattern],
964    )
965    .vortex_expect("like expressions require UTF-8 or binary operands")
966}
967
968// ---- Mask ----
969
970/// Creates a mask expression that applies the given boolean mask to the input array.
971pub fn mask(array: Expression, mask: Expression) -> Expression {
972    Mask.new_expr(EmptyOptions, [array, mask])
973}
974
975/// Creates a bound mask expression.
976pub fn bound_mask(array: BoundExpression, mask: BoundExpression) -> BoundExpression {
977    Mask.try_new_bound_expr(EmptyOptions, [array, mask])
978        .vortex_expect("mask expressions require a boolean mask")
979}
980
981// ---- Merge ----
982
983/// Creates an expression that merges struct expressions into a single struct.
984///
985/// Combines fields from all input expressions. If field names are duplicated,
986/// later expressions win. Fields are not recursively merged.
987///
988/// ```rust
989/// # use vortex_array::dtype::Nullability;
990/// # use vortex_array::expr::{merge, get_item, root};
991/// let expr = merge([get_item("a", root()), get_item("b", root())]);
992/// ```
993pub fn merge(elements: impl IntoIterator<Item = impl Into<Expression>>) -> Expression {
994    use itertools::Itertools as _;
995    let values = elements.into_iter().map(|value| value.into()).collect_vec();
996    Merge.new_expr(DuplicateHandling::default(), values)
997}
998
999/// Creates a bound expression that merges struct expressions.
1000pub fn bound_merge(elements: impl IntoIterator<Item = BoundExpression>) -> BoundExpression {
1001    bound_merge_opts(elements, DuplicateHandling::default())
1002}
1003
1004/// Creates a merge expression with explicit duplicate handling.
1005pub fn merge_opts(
1006    elements: impl IntoIterator<Item = impl Into<Expression>>,
1007    duplicate_handling: DuplicateHandling,
1008) -> Expression {
1009    use itertools::Itertools as _;
1010    let values = elements.into_iter().map(|value| value.into()).collect_vec();
1011    Merge.new_expr(duplicate_handling, values)
1012}
1013
1014/// Creates a bound merge expression with explicit duplicate handling.
1015pub fn bound_merge_opts(
1016    elements: impl IntoIterator<Item = BoundExpression>,
1017    duplicate_handling: DuplicateHandling,
1018) -> BoundExpression {
1019    Merge
1020        .try_new_bound_expr(duplicate_handling, elements)
1021        .vortex_expect("merge expressions require non-nullable struct children")
1022}
1023
1024// ---- Zip ----
1025
1026/// Creates a zip expression that conditionally selects between two arrays.
1027///
1028/// ```rust
1029/// # use vortex_array::expr::{zip_expr, root, lit};
1030/// let expr = zip_expr(lit(true), root(), lit(0i32));
1031/// ```
1032pub fn zip_expr(mask: Expression, if_true: Expression, if_false: Expression) -> Expression {
1033    Zip.new_expr(EmptyOptions, [if_true, if_false, mask])
1034}
1035
1036/// Creates a bound zip expression that conditionally selects between two arrays.
1037pub fn bound_zip_expr(
1038    mask: BoundExpression,
1039    if_true: BoundExpression,
1040    if_false: BoundExpression,
1041) -> BoundExpression {
1042    Zip.try_new_bound_expr(EmptyOptions, [if_true, if_false, mask])
1043        .vortex_expect("zip expressions require a boolean mask and compatible value dtypes")
1044}
1045
1046// ---- Dynamic ----
1047
1048/// Creates a dynamic comparison expression from its complete options.
1049pub fn dynamic_with_options(options: DynamicComparisonExpr, lhs: Expression) -> Expression {
1050    DynamicComparison.new_expr(options, [lhs])
1051}
1052
1053/// Creates a bound dynamic comparison expression from its complete options.
1054pub fn bound_dynamic_with_options(
1055    options: DynamicComparisonExpr,
1056    lhs: BoundExpression,
1057) -> BoundExpression {
1058    DynamicComparison
1059        .try_new_bound_expr(options, [lhs])
1060        .vortex_expect("dynamic comparisons require a compatible left-hand dtype")
1061}
1062
1063/// Creates a dynamic comparison expression.
1064pub fn dynamic(
1065    operator: CompareOperator,
1066    rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1067    rhs_dtype: DType,
1068    default: bool,
1069    lhs: Expression,
1070) -> Expression {
1071    dynamic_with_options(
1072        DynamicComparisonExpr {
1073            operator,
1074            rhs: Arc::new(Rhs {
1075                value: Arc::new(rhs_value),
1076                dtype: rhs_dtype,
1077            }),
1078            default,
1079        },
1080        lhs,
1081    )
1082}
1083
1084/// Creates a bound dynamic comparison expression.
1085pub fn bound_dynamic(
1086    operator: CompareOperator,
1087    rhs_value: impl Fn() -> Option<ScalarValue> + Send + Sync + 'static,
1088    rhs_dtype: DType,
1089    default: bool,
1090    lhs: BoundExpression,
1091) -> BoundExpression {
1092    bound_dynamic_with_options(
1093        DynamicComparisonExpr {
1094            operator,
1095            rhs: Arc::new(Rhs {
1096                value: Arc::new(rhs_value),
1097                dtype: rhs_dtype,
1098            }),
1099            default,
1100        },
1101        lhs,
1102    )
1103}
1104
1105// ---- ListContains ----
1106
1107/// Creates an expression that checks whether a list contains a value.
1108///
1109/// A null element never matches anything: a needle that matches no element yields `false`. For
1110/// SQL's three-valued `IN`, where a null element makes that `null`, use [`in_list`].
1111///
1112/// ```rust
1113/// # use vortex_array::expr::{list_contains, lit, root};
1114/// let expr = list_contains(root(), lit(42));
1115/// ```
1116pub fn list_contains(list: Expression, value: Expression) -> Expression {
1117    list_contains_opts(list, value, ListContainsOptions::default())
1118}
1119
1120/// Creates an expression that checks whether a list contains a value, with explicit
1121/// [`ListContainsOptions`].
1122pub fn list_contains_opts(
1123    list: Expression,
1124    value: Expression,
1125    options: ListContainsOptions,
1126) -> Expression {
1127    ListContains.new_expr(options, [list, value])
1128}
1129
1130/// Creates `needle IN (list)` with SQL null semantics: a null element is an unknown value, so a
1131/// needle that matches no element yields `null` rather than `false` when the list holds one, and
1132/// `not(in_list(..))` never admits such a row.
1133///
1134/// ```rust
1135/// # use vortex_array::expr::{in_list, lit, root};
1136/// let expr = in_list(root(), lit(vec![1, 2, 3]));
1137/// ```
1138pub fn in_list(needle: Expression, list: Expression) -> Expression {
1139    list_contains_opts(
1140        list,
1141        needle,
1142        ListContainsOptions {
1143            sql_null_semantics: true,
1144        },
1145    )
1146}
1147
1148/// Creates a bound expression that checks whether a list contains a value.
1149pub fn bound_list_contains(list: BoundExpression, value: BoundExpression) -> BoundExpression {
1150    ListContains
1151        .try_new_bound_expr(ListContainsOptions::default(), [list, value])
1152        .vortex_expect("list-contains expressions require a list child")
1153}
1154
1155/// Creates a bound `needle IN (list)` with SQL null semantics. See [`in_list`].
1156pub fn bound_in_list(needle: BoundExpression, list: BoundExpression) -> BoundExpression {
1157    ListContains
1158        .try_new_bound_expr(
1159            ListContainsOptions {
1160                sql_null_semantics: true,
1161            },
1162            [list, needle],
1163        )
1164        .vortex_expect("list-contains expressions require a list child")
1165}
1166
1167// ---- ByteLength ----
1168
1169/// Creates an expression that computes the byte length of each element.
1170/// This is akin to ANSI SQL OCTET_LENGTH(), or DuckDB's strlen().
1171///
1172/// ```rust
1173/// # use vortex_array::expr::{byte_length, root};
1174/// let expr = byte_length(root());
1175/// ```
1176pub fn byte_length(input: Expression) -> Expression {
1177    ByteLength.new_expr(EmptyOptions, [input])
1178}
1179
1180/// Creates a bound expression that computes each element's byte length.
1181pub fn bound_byte_length(input: BoundExpression) -> BoundExpression {
1182    ByteLength
1183        .try_new_bound_expr(EmptyOptions, [input])
1184        .vortex_expect("byte-length expressions require a variable-length binary child")
1185}
1186
1187// ---- ExtStorage ----
1188
1189/// Creates an expression that extracts the storage values from an extension array.
1190///
1191/// ```rust
1192/// # use vortex_array::expr::{ext_storage, root};
1193/// let expr = ext_storage(root());
1194/// ```
1195pub fn ext_storage(input: Expression) -> Expression {
1196    ExtStorage.new_expr(EmptyOptions, [input])
1197}
1198
1199/// Creates a bound expression that extracts an extension array's storage values.
1200pub fn bound_ext_storage(input: BoundExpression) -> BoundExpression {
1201    ExtStorage
1202        .try_new_bound_expr(EmptyOptions, [input])
1203        .vortex_expect("extension-storage expressions require an extension child")
1204}
1205
1206// ---- ListLength ----
1207
1208/// Creates an expression that computes the number of elements in each list
1209/// for `List` and `FixedSizeList` inputs. This is akin to ANSI SQL `CARDINALITY()`,
1210/// or DuckDB's `len()`/`array_length()`.
1211///
1212/// ```rust
1213/// # use vortex_array::expr::{list_length, root};
1214/// let expr = list_length(root());
1215/// ```
1216pub fn list_length(input: Expression) -> Expression {
1217    ListLength.new_expr(EmptyOptions, [input])
1218}
1219
1220/// Creates a bound expression that computes the number of elements in each list.
1221pub fn bound_list_length(input: BoundExpression) -> BoundExpression {
1222    ListLength
1223        .try_new_bound_expr(EmptyOptions, [input])
1224        .vortex_expect("list-length expressions require a list child")
1225}
1226
1227// ---- ListSum ----
1228
1229/// Creates an expression that sums the elements of each list for `List` and
1230/// `FixedSizeList` inputs, akin to DuckDB's `list_sum()`.
1231///
1232/// Follows SQL `SUM` semantics per list: null lists, empty lists, and lists whose elements are
1233/// all null yield null; null elements are skipped; integer and decimal overflow yields a null
1234/// value. The result dtype follows `sum`'s widening rules and is always nullable. NaN float
1235/// elements are skipped by default; see [`list_sum_opts`] for the NaN-including variant.
1236///
1237/// ```rust
1238/// # use vortex_array::expr::{list_sum, root};
1239/// let expr = list_sum(root());
1240/// ```
1241pub fn list_sum(input: Expression) -> Expression {
1242    ListSum.new_expr(NumericalAggregateOpts::default(), [input])
1243}
1244
1245/// Creates a bound expression that sums the elements of each list.
1246pub fn bound_list_sum(input: BoundExpression) -> BoundExpression {
1247    ListSum
1248        .try_new_bound_expr(NumericalAggregateOpts::default(), [input])
1249        .vortex_expect("list-sum expressions require a numeric list child")
1250}
1251
1252/// Creates a [`list_sum`] expression with explicit [`NumericalAggregateOpts`], controlling
1253/// whether NaN float elements are skipped (the default) or poison the list's sum to NaN.
1254pub fn list_sum_opts(input: Expression, options: NumericalAggregateOpts) -> Expression {
1255    ListSum.new_expr(options, [input])
1256}
1257
1258/// Creates a bound list-sum expression with explicit aggregate options.
1259pub fn bound_list_sum_opts(
1260    input: BoundExpression,
1261    options: NumericalAggregateOpts,
1262) -> BoundExpression {
1263    ListSum
1264        .try_new_bound_expr(options, [input])
1265        .vortex_expect("list-sum expressions require a numeric list child")
1266}
1267
1268/// Constructors for expressions whose children have already been bound and type-checked.
1269///
1270/// These mirror the constructors in [`crate::expr`] and panic when the supplied children do not
1271/// form a well-typed expression. Use [`BoundExpression::try_new`] when construction must be
1272/// fallible.
1273pub mod bound {
1274    pub use super::bound_and as and;
1275    pub use super::bound_and_collect as and_collect;
1276    pub use super::bound_between as between;
1277    pub use super::bound_binary as binary;
1278    pub use super::bound_byte_length as byte_length;
1279    pub use super::bound_case_when as case_when;
1280    pub use super::bound_case_when_no_else as case_when_no_else;
1281    pub use super::bound_cast as cast;
1282    pub use super::bound_checked_add as checked_add;
1283    pub use super::bound_col as col;
1284    pub use super::bound_dynamic as dynamic;
1285    pub use super::bound_dynamic_with_options as dynamic_with_options;
1286    pub use super::bound_eq as eq;
1287    pub use super::bound_ext_storage as ext_storage;
1288    pub use super::bound_fill_null as fill_null;
1289    pub use super::bound_get_item as get_item;
1290    pub use super::bound_gt as gt;
1291    pub use super::bound_gt_eq as gt_eq;
1292    pub use super::bound_ilike as ilike;
1293    pub use super::bound_in_list as in_list;
1294    pub use super::bound_is_nan as is_nan;
1295    pub use super::bound_is_not_null as is_not_null;
1296    pub use super::bound_is_null as is_null;
1297    pub use super::bound_like as like;
1298    pub use super::bound_list_contains as list_contains;
1299    pub use super::bound_list_length as list_length;
1300    pub use super::bound_list_sum as list_sum;
1301    pub use super::bound_list_sum_opts as list_sum_opts;
1302    pub use super::bound_lit as lit;
1303    pub use super::bound_lt as lt;
1304    pub use super::bound_lt_eq as lt_eq;
1305    pub use super::bound_mask as mask;
1306    pub use super::bound_merge as merge;
1307    pub use super::bound_merge_opts as merge_opts;
1308    pub use super::bound_nested_case_when as nested_case_when;
1309    pub use super::bound_not as not;
1310    pub use super::bound_not_eq as not_eq;
1311    pub use super::bound_not_ilike as not_ilike;
1312    pub use super::bound_not_like as not_like;
1313    pub use super::bound_or as or;
1314    pub use super::bound_or_collect as or_collect;
1315    pub use super::bound_pack as pack;
1316    pub use super::bound_root as root;
1317    pub use super::bound_select as select;
1318    pub use super::bound_select_exclude as select_exclude;
1319    pub use super::bound_variant_get as variant_get;
1320    pub use super::bound_zip_expr as zip_expr;
1321}