From 2051e6ae245b3cef504c31b7c186c11983290a00 Mon Sep 17 00:00:00 2001 From: redraiment Date: Sat, 9 Aug 2025 22:49:01 +0800 Subject: [PATCH] feat: add comprehensive type conversion methods to Value struct Add missing type conversion methods to complement the existing to_int64() method, providing complete coverage for all DuckDB data types: - Integer types: to_int8, to_uint8, to_int16, to_uint16, to_int32, to_uint32, to_uint64 - Large integer types: to_hugeint, to_uhugeint, to_varint - Numeric types: to_decimal, to_float, to_double - Temporal types: to_date, to_time, to_time_tz, to_timestamp, to_timestamp_tz, to_timestamp_s, to_timestamp_ms, to_timestamp_ns, to_interval - Other types: to_bool, to_varchar, to_blob, to_bit, to_uuid - Complex types: to_list, to_map_entries, to_struct_properties - Utility methods: value_type All methods follow the same unsafe pattern as the original to_int64() implementation, directly wrapping the corresponding duckdb_get_* C API calls. This enhancement provides a complete and consistent API for extracting values from DuckDB result sets in Rust applications. --- crates/duckdb/src/vtab/value.rs | 193 +++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/crates/duckdb/src/vtab/value.rs b/crates/duckdb/src/vtab/value.rs index afe81d53..6f7e5609 100644 --- a/crates/duckdb/src/vtab/value.rs +++ b/crates/duckdb/src/vtab/value.rs @@ -1,4 +1,15 @@ -use crate::ffi::{duckdb_destroy_value, duckdb_free, duckdb_get_int64, duckdb_get_varchar, duckdb_value}; +use libduckdb_sys::{ + duckdb_bit, duckdb_blob, duckdb_date, duckdb_decimal, duckdb_destroy_value, duckdb_free, duckdb_get_bit, + duckdb_get_blob, duckdb_get_bool, duckdb_get_date, duckdb_get_decimal, duckdb_get_double, duckdb_get_float, + duckdb_get_hugeint, duckdb_get_int16, duckdb_get_int32, duckdb_get_int64, duckdb_get_int8, duckdb_get_interval, + duckdb_get_list_child, duckdb_get_list_size, duckdb_get_map_key, duckdb_get_map_size, duckdb_get_map_value, + duckdb_get_struct_child, duckdb_get_time, duckdb_get_time_tz, duckdb_get_timestamp, duckdb_get_timestamp_ms, + duckdb_get_timestamp_ns, duckdb_get_timestamp_s, duckdb_get_timestamp_tz, duckdb_get_uhugeint, duckdb_get_uint16, + duckdb_get_uint32, duckdb_get_uint64, duckdb_get_uint8, duckdb_get_uuid, duckdb_get_value_type, duckdb_get_varchar, + duckdb_get_varint, duckdb_hugeint, duckdb_interval, duckdb_logical_type, duckdb_struct_type_child_count, + duckdb_struct_type_child_name, duckdb_time, duckdb_time_tz, duckdb_timestamp, duckdb_timestamp_ms, + duckdb_timestamp_ns, duckdb_timestamp_s, duckdb_uhugeint, duckdb_value, duckdb_varint, +}; use std::{ffi::CStr, fmt, os::raw::c_void}; /// The Value object holds a single arbitrary value of any type that can be @@ -26,10 +37,190 @@ impl Drop for Value { } impl Value { + /// Returns the value as a boolean + pub fn to_bool(&self) -> bool { + unsafe { duckdb_get_bool(self.ptr) } + } + + /// Returns the value as an i8 + pub fn to_int8(&self) -> i8 { + unsafe { duckdb_get_int8(self.ptr) } + } + + /// Returns the value as an u8 + pub fn to_uint8(&self) -> u8 { + unsafe { duckdb_get_uint8(self.ptr) } + } + + /// Returns the value as an i16 + pub fn to_int16(&self) -> i16 { + unsafe { duckdb_get_int16(self.ptr) } + } + + /// Returns the value as an u16 + pub fn to_uint16(&self) -> u16 { + unsafe { duckdb_get_uint16(self.ptr) } + } + + /// Returns the value as an i32 + pub fn to_int32(&self) -> i32 { + unsafe { duckdb_get_int32(self.ptr) } + } + + /// Returns the value as an u32 + pub fn to_uint32(&self) -> u32 { + unsafe { duckdb_get_uint32(self.ptr) } + } + /// Returns the value as a int64 pub fn to_int64(&self) -> i64 { unsafe { duckdb_get_int64(self.ptr) } } + + /// Returns the value as a int64 + pub fn to_uint64(&self) -> u64 { + unsafe { duckdb_get_uint64(self.ptr) } + } + /// Returns the value as a hugeint + pub fn to_hugeint(&self) -> duckdb_hugeint { + unsafe { duckdb_get_hugeint(self.ptr) } + } + + /// Returns the value as a uhugeint + pub fn to_uhugeint(&self) -> duckdb_uhugeint { + unsafe { duckdb_get_uhugeint(self.ptr) } + } + + /// Returns the value as a varint + pub fn to_varint(&self) -> duckdb_varint { + unsafe { duckdb_get_varint(self.ptr) } + } + + /// Returns the value as a decimal + pub fn to_decimal(&self) -> duckdb_decimal { + unsafe { duckdb_get_decimal(self.ptr) } + } + + /// Returns the value as a float + pub fn to_float(&self) -> f32 { + unsafe { duckdb_get_float(self.ptr) } + } + + /// Returns the value as a double + pub fn to_double(&self) -> f64 { + unsafe { duckdb_get_double(self.ptr) } + } + + /// Returns the value as a date + pub fn to_date(&self) -> duckdb_date { + unsafe { duckdb_get_date(self.ptr) } + } + + /// Returns the value as a time + pub fn to_time(&self) -> duckdb_time { + unsafe { duckdb_get_time(self.ptr) } + } + + /// Returns the value as a time_tz + pub fn to_time_tz(&self) -> duckdb_time_tz { + unsafe { duckdb_get_time_tz(self.ptr) } + } + + /// Returns the value as a timestamp + pub fn to_timestamp(&self) -> duckdb_timestamp { + unsafe { duckdb_get_timestamp(self.ptr) } + } + + /// Returns the value as a timestamp_tz + pub fn to_timestamp_tz(&self) -> duckdb_timestamp { + unsafe { duckdb_get_timestamp_tz(self.ptr) } + } + + /// Returns the value as a timestamp_s + pub fn to_timestamp_s(&self) -> duckdb_timestamp_s { + unsafe { duckdb_get_timestamp_s(self.ptr) } + } + + /// Returns the value as a timestamp_ms + pub fn to_timestamp_ms(&self) -> duckdb_timestamp_ms { + unsafe { duckdb_get_timestamp_ms(self.ptr) } + } + + /// Returns the value as a timestamp_ns + pub fn to_timestamp_ns(&self) -> duckdb_timestamp_ns { + unsafe { duckdb_get_timestamp_ns(self.ptr) } + } + + /// Returns the value as a interval + pub fn to_interval(&self) -> duckdb_interval { + unsafe { duckdb_get_interval(self.ptr) } + } + + /// Returns the value as a blob + pub fn to_blob(&self) -> duckdb_blob { + unsafe { duckdb_get_blob(self.ptr) } + } + + /// Returns the value as a bit + pub fn to_bit(&self) -> duckdb_bit { + unsafe { duckdb_get_bit(self.ptr) } + } + + /// Returns the value as a uuid + pub fn to_uuid(&self) -> duckdb_uhugeint { + unsafe { duckdb_get_uuid(self.ptr) } + } + + /// Returns the value as a String + pub fn to_varchar(&self) -> String { + unsafe { + let varchar = duckdb_get_varchar(self.ptr); + let c_str = CStr::from_ptr(varchar); + c_str.to_string_lossy().into_owned() + } + } + + /// Returns the value as a list + pub fn to_list(&self) -> Vec { + unsafe { + let size = duckdb_get_list_size(self.ptr); + (0..size) + .map(|index| Value::from(duckdb_get_list_child(self.ptr, index))) + .collect() + } + } + + /// Returns the value as a map key & value entries + pub fn to_map_entries(&self) -> Vec<(Self, Self)> { + unsafe { + let size = duckdb_get_map_size(self.ptr); + (0..size) + .map(|index| ( + Value::from(duckdb_get_map_key(self.ptr, index)), + Value::from(duckdb_get_map_value(self.ptr, index)), + )) + .collect() + } + } + + /// Returns the value as a struct type child names and values + pub fn to_struct_properties(&self) -> Vec<(String, Self)> { + unsafe { + let value_type = self.value_type(); + let size = duckdb_struct_type_child_count(value_type); + (0..size) + .map(|index| ( + CStr::from_ptr(duckdb_struct_type_child_name(value_type, index)).to_string_lossy().to_string(), + Value::from(duckdb_get_struct_child(self.ptr, index)), + )) + .collect() + } + } + + /// Returns the value logical type + pub fn value_type(&self) -> duckdb_logical_type { + unsafe { duckdb_get_value_type(self.ptr) } + } } impl fmt::Display for Value {