better_duck_core::types::value::DuckValue is the dynamic representation of any DuckDB column
value. Reading a row gives you &DuckValues; binding
parameters and appending accept them.
Variant families
The full variant list is split across focused pages:Scalar types
Booleans, every integer width, floats, text, blob, decimal, uuid, bit, bignum.
Temporal types
Dates, times, timestamps, intervals, and ±infinity sentinels.
Composite types
LIST, ARRAY, STRUCT, MAP, UNION, ENUM.
Null variant represents SQL NULL and is shared by all families.
Traits and equality
DuckValue is Clone + PartialEq + Eq + Hash:
- Floats are canonicalized for
Eq/Hash(soNaNbehaves consistently), andMapvalues hash order-independently — aDuckValueworks as aHashMapkey. Option<T>converts toNull/Some(..)on both read and write directions.
Constructors and Map helpers
DuckValue::text(impl Into<String>) -> DuckValue— build aTextvalue.- On a
Mapvariant:get(key),get_mut(key),contains_key(key), taking any key convertible intoDuckValue. On non-Mapvariants they returnNone/false.
The conversion traits
Four traits connect Rust types and DuckDB values. You rarely implement them by hand — the derives and built-in impls cover the common cases — but knowing the roles clarifies error messages and generic bounds.Write direction. Binds to a prepared-statement parameter or appends to an appender row.
Implemented for every
DuckValue and the primitive Rust types. This is the bound on
execute_with and Appender::append.Read direction.
from_duck_value(&DuckValue) -> Result<Self, DuckDBConversionError>. A
NULL into a non-Option target is NullValue; a mismatched variant is a
conversion error. Option<T> reads Null as None.The low-level
from_duck / to_duck round-trip against a raw FFI value (or, for temporal types,
a packed FFI struct). The machinery AppendAble/FromDuckValue build on.Gives a Rust type (not value) its fixed DuckDB logical type, so
Vec<T>, Box<[T]>, and
HashMap<K, V> can map to LIST/ARRAY/MAP even when empty. See
LogicalType::of::<T>().DuckValue deliberately does not implement DuckLogicalType: the enum has no single fixed
logical type (it depends on the runtime variant). Wrap a Vec<DuckValue> as DuckValue::List(v)
and bind it directly instead.Converting a whole value
to_duck() -> Result<duckdb_value, DuckDBConversionError>— build a heap DuckDB value (caller destroys it). Errors for an empty collection whose element type can’t be inferred.logical_type_of(&DuckValue) -> Result<duckdb_logical_type, _>— the value’s logical type.to_owned_value() -> Result<OwnedValue, _>— materialize anOwnedValuefor introspection (SQL-NULL check, SQL rendering, STRUCT child access).
See also
- Scalar types · Temporal types · Composite types.
- Positional parameters — binding values via
AppendAble. - FromRow / ToRow — deriving the conversions for your structs.