1+ //! Scalar value conversion between Vortex and DuckDB.
2+ //!
3+ //! This module provides functionality to convert Vortex scalar values to DuckDB values.
4+ //!
5+ //! Note that nullability of Vortex scalars is not transferred to DuckDB scalars.
6+ //!
7+ //! # Supported Scalar Conversions
8+ //!
9+ //! | Vortex Scalar | DuckDB Value |
10+ //! |---------------|--------------|
11+ //! | `Null` | `NULL` |
12+ //! | `Bool` | `BOOLEAN` |
13+ //! | `Primitive` (integers/floats) | Corresponding numeric types |
14+ //! | `Decimal` | `DECIMAL` |
15+ //! | `Utf8` | `VARCHAR` |
16+ //! | `Binary` | `BLOB` |
17+ //! | `ExtScalar` (temporal) | `DATE`/`TIME`/`TIMESTAMP` |
18+
119use vortex:: dtype:: datetime:: { TemporalMetadata , TimeUnit } ;
220use vortex:: dtype:: half:: f16;
321use vortex:: dtype:: { DType , PType , match_each_native_simd_ptype} ;
@@ -9,12 +27,22 @@ use vortex::scalar::{
927
1028use crate :: duckdb:: Value ;
1129
30+ /// Trait for converting Vortex scalars to DuckDB values.
1231pub trait ToDuckDBScalar {
1332 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > ;
1433}
1534
1635impl ToDuckDBScalar for Scalar {
36+ /// Converts a generic Vortex scalar to a DuckDB value.
37+ ///
38+ /// # Note
39+ ///
40+ /// Struct and List scalars are not yet implemented and cause a panic.
1741 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
42+ if self . is_null ( ) {
43+ return Ok ( Value :: null ( ) ) ;
44+ }
45+
1846 match self . dtype ( ) {
1947 DType :: Null => Ok ( Value :: null ( ) ) ,
2048 DType :: Bool ( _) => self . as_bool ( ) . try_to_duckdb_scalar ( ) ,
@@ -29,6 +57,11 @@ impl ToDuckDBScalar for Scalar {
2957}
3058
3159impl ToDuckDBScalar for PrimitiveScalar < ' _ > {
60+ /// Converts a primitive scalar (integer, float, or boolean) to a DuckDB value.
61+ ///
62+ /// # Note
63+ ///
64+ /// - `F16` values are converted to `F32` before creating the DuckDB value
3265 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
3366 if self . ptype ( ) == PType :: F16 {
3467 return Ok ( Value :: from (
@@ -46,6 +79,18 @@ impl ToDuckDBScalar for PrimitiveScalar<'_> {
4679}
4780
4881impl ToDuckDBScalar for DecimalScalar < ' _ > {
82+ /// Converts a decimal scalar to a DuckDB decimal value.
83+ ///
84+ /// # Supported Decimal Types
85+ ///
86+ /// - `I8`, `I16`, `I32`, `I64` - Converted to `i128` for DuckDB
87+ /// - `I128` - Used directly
88+ /// - `I256` - Not supported, returns an error
89+ ///
90+ /// # Note: Scalar vs Array Conversion Differences
91+ ///
92+ /// This scalar conversion always uses `i128` for all decimal values regardless of precision,
93+ /// which differs from the array conversion logic that uses precision-based storage optimization.
4994 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
5095 let decimal_type = self
5196 . dtype ( )
@@ -74,12 +119,14 @@ impl ToDuckDBScalar for DecimalScalar<'_> {
74119}
75120
76121impl ToDuckDBScalar for BoolScalar < ' _ > {
122+ /// Converts a boolean scalar to a DuckDB boolean value.
77123 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
78124 Ok ( Value :: from ( self . value ( ) ) )
79125 }
80126}
81127
82128impl ToDuckDBScalar for Utf8Scalar < ' _ > {
129+ /// Converts a UTF-8 string scalar to a DuckDB VARCHAR value.
83130 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
84131 Ok ( match self . value ( ) {
85132 Some ( value) => Value :: from ( value. as_str ( ) ) ,
@@ -89,6 +136,7 @@ impl ToDuckDBScalar for Utf8Scalar<'_> {
89136}
90137
91138impl ToDuckDBScalar for BinaryScalar < ' _ > {
139+ /// Converts a binary scalar to a DuckDB BLOB value.
92140 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
93141 Ok ( match self . value ( ) {
94142 Some ( value) => Value :: from ( value. as_slice ( ) ) ,
@@ -98,6 +146,7 @@ impl ToDuckDBScalar for BinaryScalar<'_> {
98146}
99147
100148impl ToDuckDBScalar for ExtScalar < ' _ > {
149+ /// Converts an extension scalar (primarily temporal types) to a DuckDB value.
101150 fn try_to_duckdb_scalar ( & self ) -> VortexResult < Value > {
102151 let time = TemporalMetadata :: try_from ( self . ext_dtype ( ) ) ?;
103152 let value = || {
0 commit comments