Skip to content

Commit 23df94d

Browse files
committed
variant get
Signed-off-by: Adam Gutglick <adam@spiraldb.com>
1 parent 4a5b7d7 commit 23df94d

12 files changed

Lines changed: 538 additions & 0 deletions

File tree

encodings/parquet-variant/src/kernel.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ use vortex_mask::Mask;
1919

2020
use crate::ParquetVariant;
2121
use crate::ParquetVariantArrayExt;
22+
use crate::variant_get::VariantGetExecuteParent;
2223

2324
pub(crate) static PARENT_KERNELS: ParentKernelSet<ParquetVariant> = ParentKernelSet::new(&[
2425
ParentKernelSet::lift(&FilterExecuteAdaptor(ParquetVariant)),
2526
ParentKernelSet::lift(&SliceExecuteAdaptor(ParquetVariant)),
2627
ParentKernelSet::lift(&TakeExecuteAdaptor(ParquetVariant)),
28+
ParentKernelSet::lift(&VariantGetExecuteParent),
2729
]);
2830

2931
impl SliceKernel for ParquetVariant {

encodings/parquet-variant/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ mod array;
2828
mod kernel;
2929
mod operations;
3030
mod validity;
31+
mod variant_get;
32+
#[cfg(test)]
33+
mod variant_get_tests;
3134
mod vtable;
3235

3336
pub use array::ParquetVariantArrayExt;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Execute-parent kernel for `variant_get` on `ParquetVariantArray`.
5+
//!
6+
//! Delegates to `parquet_variant_compute::variant_get` after converting to Arrow.
7+
8+
use std::sync::Arc;
9+
10+
use parquet_variant::VariantPathElement;
11+
use parquet_variant_compute::GetOptions;
12+
use parquet_variant_compute::VariantArray as ArrowVariantArray;
13+
use vortex_array::ArrayRef;
14+
use vortex_array::ArrayView;
15+
use vortex_array::ExecutionCtx;
16+
use vortex_array::arrays::scalar_fn::ExactScalarFn;
17+
use vortex_array::arrays::scalar_fn::ScalarFnArrayView;
18+
use vortex_array::dtype::FieldName;
19+
use vortex_array::kernel::ExecuteParentKernel;
20+
use vortex_array::scalar_fn::fns::variant_get::VariantGet;
21+
use vortex_error::VortexResult;
22+
use vortex_error::vortex_err;
23+
24+
use crate::ParquetVariant;
25+
use crate::ParquetVariantArrayExt;
26+
use crate::ParquetVariantData;
27+
28+
#[derive(Debug)]
29+
pub(crate) struct VariantGetExecuteParent;
30+
31+
impl ExecuteParentKernel<ParquetVariant> for VariantGetExecuteParent {
32+
type Parent = ExactScalarFn<VariantGet>;
33+
34+
fn execute_parent(
35+
&self,
36+
array: ArrayView<'_, ParquetVariant>,
37+
parent: ScalarFnArrayView<'_, VariantGet>,
38+
_child_idx: usize,
39+
ctx: &mut ExecutionCtx,
40+
) -> VortexResult<Option<ArrayRef>> {
41+
let field_name: &FieldName = parent.options;
42+
variant_get_impl(array, field_name, ctx).map(Some)
43+
}
44+
}
45+
46+
fn variant_get_impl(
47+
array: ArrayView<'_, ParquetVariant>,
48+
field_name: &FieldName,
49+
ctx: &mut ExecutionCtx,
50+
) -> VortexResult<ArrayRef> {
51+
// Convert to Arrow VariantArray
52+
let arrow_variant = array.to_arrow(ctx)?;
53+
54+
// Build path for a single field access
55+
let path_element = VariantPathElement::Field {
56+
name: field_name.as_ref().into(),
57+
};
58+
let options = GetOptions::new_with_path(vec![path_element].into());
59+
60+
// Delegate to the parquet-variant-compute kernel.
61+
// With as_type = None, the result is itself a VariantArray.
62+
let inner: Arc<dyn arrow_array::Array> = Arc::new(arrow_variant.into_inner());
63+
let arrow_result = parquet_variant_compute::variant_get(&inner, options)
64+
.map_err(|e| vortex_err!("variant_get failed: {e}"))?;
65+
66+
// Convert back to Vortex
67+
let result_variant = ArrowVariantArray::try_new(
68+
arrow_result
69+
.as_any()
70+
.downcast_ref::<arrow_array::StructArray>()
71+
.ok_or_else(|| vortex_err!("variant_get did not return a StructArray"))?,
72+
)
73+
.map_err(|e| vortex_err!("failed to create VariantArray from result: {e}"))?;
74+
75+
ParquetVariantData::from_arrow_variant(&result_variant)
76+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
#[cfg(test)]
5+
mod tests {
6+
use arrow_array::StructArray;
7+
use arrow_buffer::NullBuffer;
8+
use parquet_variant::Variant as PqVariant;
9+
use parquet_variant::VariantBuilderExt;
10+
use parquet_variant_compute::VariantArrayBuilder;
11+
use vortex_array::ArrayRef;
12+
use vortex_array::LEGACY_SESSION;
13+
use vortex_array::VortexSessionExecute;
14+
use vortex_array::expr::root;
15+
use vortex_array::expr::variant_get;
16+
use vortex_error::VortexResult;
17+
18+
use crate::ParquetVariantData;
19+
20+
/// Apply variant_get and execute through the full pipeline (including execute_parent).
21+
fn apply_variant_get(arr: &ArrayRef, field: &str) -> VortexResult<ArrayRef> {
22+
let expr = variant_get(field, root());
23+
let lazy = arr.clone().apply(&expr)?;
24+
let mut ctx = LEGACY_SESSION.create_execution_ctx();
25+
lazy.execute::<ArrayRef>(&mut ctx)
26+
}
27+
28+
/// Build a VariantArray of objects: [{"a": 1, "b": "x"}, {"a": 2, "c": true}, {"b": "y"}]
29+
fn make_object_array() -> VortexResult<ArrayRef> {
30+
let mut builder = VariantArrayBuilder::new(3);
31+
32+
builder
33+
.new_object()
34+
.with_field("a", 1i32)
35+
.with_field("b", "x")
36+
.finish();
37+
38+
builder
39+
.new_object()
40+
.with_field("a", 2i32)
41+
.with_field("c", true)
42+
.finish();
43+
44+
builder.new_object().with_field("b", "y").finish();
45+
46+
ParquetVariantData::from_arrow_variant(&builder.build())
47+
}
48+
49+
/// Build a nullable VariantArray: [{"a": 10}, NULL, {"a": 30}]
50+
fn make_nullable_object_array() -> VortexResult<ArrayRef> {
51+
let mut builder = VariantArrayBuilder::new(3);
52+
53+
builder.new_object().with_field("a", 10i32).finish();
54+
55+
builder.new_object().with_field("a", 20i32).finish();
56+
57+
builder.new_object().with_field("a", 30i32).finish();
58+
59+
let inner = builder.build().into_inner();
60+
let null_struct = StructArray::try_new(
61+
inner.fields().clone(),
62+
inner.columns().to_vec(),
63+
Some(NullBuffer::from(vec![true, false, true])),
64+
)
65+
.unwrap();
66+
let arrow_variant = parquet_variant_compute::VariantArray::try_new(&null_struct).unwrap();
67+
ParquetVariantData::from_arrow_variant(&arrow_variant)
68+
}
69+
70+
#[test]
71+
fn test_variant_get_basic() -> VortexResult<()> {
72+
let arr = make_object_array()?;
73+
let result = apply_variant_get(&arr, "a")?;
74+
75+
assert_eq!(result.len(), 3);
76+
77+
// Row 0: {"a": 1, ...} → variant(1)
78+
let s0 = result.scalar_at(0)?;
79+
assert!(!s0.is_null());
80+
let inner0 = s0.as_variant().value().unwrap();
81+
assert_eq!(*inner0, 1i32.into());
82+
83+
// Row 1: {"a": 2, ...} → variant(2)
84+
let s1 = result.scalar_at(1)?;
85+
assert!(!s1.is_null());
86+
let inner1 = s1.as_variant().value().unwrap();
87+
assert_eq!(*inner1, 2i32.into());
88+
89+
// Row 2: {"b": "y"} → null (field "a" missing)
90+
let s2 = result.scalar_at(2)?;
91+
assert!(s2.is_null());
92+
93+
Ok(())
94+
}
95+
96+
#[test]
97+
fn test_variant_get_missing_field() -> VortexResult<()> {
98+
let arr = make_object_array()?;
99+
let result = apply_variant_get(&arr, "nonexistent")?;
100+
101+
assert_eq!(result.len(), 3);
102+
for i in 0..3 {
103+
assert!(result.scalar_at(i)?.is_null(), "row {i} should be null");
104+
}
105+
106+
Ok(())
107+
}
108+
109+
#[test]
110+
fn test_variant_get_null_input() -> VortexResult<()> {
111+
let arr = make_nullable_object_array()?;
112+
let result = apply_variant_get(&arr, "a")?;
113+
114+
assert_eq!(result.len(), 3);
115+
116+
// Row 0: {"a": 10} → variant(10)
117+
assert!(!result.scalar_at(0)?.is_null());
118+
119+
// Row 1: NULL → null
120+
assert!(result.scalar_at(1)?.is_null());
121+
122+
// Row 2: {"a": 30} → variant(30)
123+
assert!(!result.scalar_at(2)?.is_null());
124+
125+
Ok(())
126+
}
127+
128+
#[test]
129+
fn test_variant_get_non_object() -> VortexResult<()> {
130+
// Array of primitive variants (not objects)
131+
let mut builder = VariantArrayBuilder::new(2);
132+
builder.append_variant(PqVariant::from(42i32));
133+
builder.append_variant(PqVariant::from("hello"));
134+
let arr = ParquetVariantData::from_arrow_variant(&builder.build())?;
135+
136+
let result = apply_variant_get(&arr, "a")?;
137+
138+
assert_eq!(result.len(), 2);
139+
assert!(result.scalar_at(0)?.is_null());
140+
assert!(result.scalar_at(1)?.is_null());
141+
142+
Ok(())
143+
}
144+
145+
#[test]
146+
fn test_variant_get_different_field() -> VortexResult<()> {
147+
let arr = make_object_array()?;
148+
let result = apply_variant_get(&arr, "b")?;
149+
150+
assert_eq!(result.len(), 3);
151+
152+
// Row 0: {"a": 1, "b": "x"} → variant("x")
153+
assert!(!result.scalar_at(0)?.is_null());
154+
155+
// Row 1: {"a": 2, "c": true} → null (no "b")
156+
assert!(result.scalar_at(1)?.is_null());
157+
158+
// Row 2: {"b": "y"} → variant("y")
159+
assert!(!result.scalar_at(2)?.is_null());
160+
161+
Ok(())
162+
}
163+
}

vortex-array/public-api.lock

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12430,6 +12430,8 @@ pub fn vortex_array::expr::select_exclude(fields: impl core::convert::Into<vorte
1243012430

1243112431
pub fn vortex_array::expr::split_conjunction(expr: &vortex_array::expr::Expression) -> alloc::vec::Vec<vortex_array::expr::Expression>
1243212432

12433+
pub fn vortex_array::expr::variant_get(field: impl core::convert::Into<vortex_array::dtype::FieldName>, child: vortex_array::expr::Expression) -> vortex_array::expr::Expression
12434+
1243312435
pub fn vortex_array::expr::zip_expr(mask: vortex_array::expr::Expression, if_true: vortex_array::expr::Expression, if_false: vortex_array::expr::Expression) -> vortex_array::expr::Expression
1243412436

1243512437
pub type vortex_array::expr::Annotations<'a, A> = vortex_utils::aliases::hash_map::HashMap<&'a vortex_array::expr::Expression, vortex_utils::aliases::hash_set::HashSet<A>>
@@ -17198,6 +17200,52 @@ pub fn vortex_array::scalar_fn::fns::select::Select::stat_falsification(&self, o
1719817200

1719917201
pub fn vortex_array::scalar_fn::fns::select::Select::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
1720017202

17203+
pub mod vortex_array::scalar_fn::fns::variant_get
17204+
17205+
pub struct vortex_array::scalar_fn::fns::variant_get::VariantGet
17206+
17207+
impl core::clone::Clone for vortex_array::scalar_fn::fns::variant_get::VariantGet
17208+
17209+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::clone(&self) -> vortex_array::scalar_fn::fns::variant_get::VariantGet
17210+
17211+
impl vortex_array::scalar_fn::ScalarFnVTable for vortex_array::scalar_fn::fns::variant_get::VariantGet
17212+
17213+
pub type vortex_array::scalar_fn::fns::variant_get::VariantGet::Options = vortex_array::dtype::FieldName
17214+
17215+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::arity(&self, _field_name: &vortex_array::dtype::FieldName) -> vortex_array::scalar_fn::Arity
17216+
17217+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::child_name(&self, _instance: &Self::Options, child_idx: usize) -> vortex_array::scalar_fn::ChildName
17218+
17219+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::coerce_args(&self, options: &Self::Options, args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult<alloc::vec::Vec<vortex_array::dtype::DType>>
17220+
17221+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::deserialize(&self, metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult<Self::Options>
17222+
17223+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::execute(&self, _field_name: &vortex_array::dtype::FieldName, _args: &dyn vortex_array::scalar_fn::ExecutionArgs, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<vortex_array::ArrayRef>
17224+
17225+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::fmt_sql(&self, field_name: &vortex_array::dtype::FieldName, expr: &vortex_array::expr::Expression, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
17226+
17227+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::id(&self) -> vortex_array::scalar_fn::ScalarFnId
17228+
17229+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::is_fallible(&self, _field_name: &vortex_array::dtype::FieldName) -> bool
17230+
17231+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::is_null_sensitive(&self, _field_name: &vortex_array::dtype::FieldName) -> bool
17232+
17233+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::reduce(&self, field_name: &vortex_array::dtype::FieldName, node: &dyn vortex_array::scalar_fn::ReduceNode, ctx: &dyn vortex_array::scalar_fn::ReduceCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::scalar_fn::ReduceNodeRef>>
17234+
17235+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::return_dtype(&self, _field_name: &vortex_array::dtype::FieldName, arg_dtypes: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult<vortex_array::dtype::DType>
17236+
17237+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::serialize(&self, instance: &Self::Options) -> vortex_error::VortexResult<core::option::Option<alloc::vec::Vec<u8>>>
17238+
17239+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::simplify(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, ctx: &dyn vortex_array::scalar_fn::SimplifyCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
17240+
17241+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::simplify_untyped(&self, options: &Self::Options, expr: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
17242+
17243+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::stat_expression(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, stat: vortex_array::expr::stats::Stat, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option<vortex_array::expr::Expression>
17244+
17245+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::stat_falsification(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option<vortex_array::expr::Expression>
17246+
17247+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
17248+
1720117249
pub mod vortex_array::scalar_fn::fns::zip
1720217250

1720317251
pub struct vortex_array::scalar_fn::fns::zip::Zip
@@ -18406,6 +18454,44 @@ pub fn vortex_array::scalar_fn::fns::select::Select::stat_falsification(&self, o
1840618454

1840718455
pub fn vortex_array::scalar_fn::fns::select::Select::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
1840818456

18457+
impl vortex_array::scalar_fn::ScalarFnVTable for vortex_array::scalar_fn::fns::variant_get::VariantGet
18458+
18459+
pub type vortex_array::scalar_fn::fns::variant_get::VariantGet::Options = vortex_array::dtype::FieldName
18460+
18461+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::arity(&self, _field_name: &vortex_array::dtype::FieldName) -> vortex_array::scalar_fn::Arity
18462+
18463+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::child_name(&self, _instance: &Self::Options, child_idx: usize) -> vortex_array::scalar_fn::ChildName
18464+
18465+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::coerce_args(&self, options: &Self::Options, args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult<alloc::vec::Vec<vortex_array::dtype::DType>>
18466+
18467+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::deserialize(&self, metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult<Self::Options>
18468+
18469+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::execute(&self, _field_name: &vortex_array::dtype::FieldName, _args: &dyn vortex_array::scalar_fn::ExecutionArgs, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<vortex_array::ArrayRef>
18470+
18471+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::fmt_sql(&self, field_name: &vortex_array::dtype::FieldName, expr: &vortex_array::expr::Expression, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
18472+
18473+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::id(&self) -> vortex_array::scalar_fn::ScalarFnId
18474+
18475+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::is_fallible(&self, _field_name: &vortex_array::dtype::FieldName) -> bool
18476+
18477+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::is_null_sensitive(&self, _field_name: &vortex_array::dtype::FieldName) -> bool
18478+
18479+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::reduce(&self, field_name: &vortex_array::dtype::FieldName, node: &dyn vortex_array::scalar_fn::ReduceNode, ctx: &dyn vortex_array::scalar_fn::ReduceCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::scalar_fn::ReduceNodeRef>>
18480+
18481+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::return_dtype(&self, _field_name: &vortex_array::dtype::FieldName, arg_dtypes: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult<vortex_array::dtype::DType>
18482+
18483+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::serialize(&self, instance: &Self::Options) -> vortex_error::VortexResult<core::option::Option<alloc::vec::Vec<u8>>>
18484+
18485+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::simplify(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, ctx: &dyn vortex_array::scalar_fn::SimplifyCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
18486+
18487+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::simplify_untyped(&self, options: &Self::Options, expr: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
18488+
18489+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::stat_expression(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, stat: vortex_array::expr::stats::Stat, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option<vortex_array::expr::Expression>
18490+
18491+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::stat_falsification(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option<vortex_array::expr::Expression>
18492+
18493+
pub fn vortex_array::scalar_fn::fns::variant_get::VariantGet::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
18494+
1840918495
impl vortex_array::scalar_fn::ScalarFnVTable for vortex_array::scalar_fn::fns::zip::Zip
1841018496

1841118497
pub type vortex_array::scalar_fn::fns::zip::Zip::Options = vortex_array::scalar_fn::EmptyOptions

vortex-array/src/expr/exprs.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use crate::scalar_fn::fns::pack::PackOptions;
4646
use crate::scalar_fn::fns::root::Root;
4747
use crate::scalar_fn::fns::select::FieldSelection;
4848
use crate::scalar_fn::fns::select::Select;
49+
use crate::scalar_fn::fns::variant_get::VariantGet;
4950
use crate::scalar_fn::fns::zip::Zip;
5051

5152
// ---- Root ----
@@ -699,3 +700,17 @@ pub fn dynamic(
699700
pub fn list_contains(list: Expression, value: Expression) -> Expression {
700701
ListContains.new_expr(EmptyOptions, [list, value])
701702
}
703+
704+
// ---- VariantGet ----
705+
706+
/// Creates an expression that extracts a field from a variant object by name.
707+
///
708+
/// Returns a new variant containing the field's value, or null if the field does not exist.
709+
///
710+
/// ```rust
711+
/// # use vortex_array::expr::{variant_get, root};
712+
/// let expr = variant_get("field_name", root());
713+
/// ```
714+
pub fn variant_get(field: impl Into<FieldName>, child: Expression) -> Expression {
715+
VariantGet.new_expr(field.into(), vec![child])
716+
}

0 commit comments

Comments
 (0)