Skip to main content

hdbconnect_arrow/builders/
primitive.rs

1//! Primitive type builders for numeric Arrow arrays.
2//!
3//! Implements builders for:
4//! - `UInt8` (HANA TINYINT)
5//! - `Int16` (HANA SMALLINT)
6//! - `Int32` (HANA INT)
7//! - `Int64` (HANA BIGINT)
8//! - `Float32` (HANA REAL)
9//! - `Float64` (HANA DOUBLE)
10
11use std::sync::Arc;
12
13use arrow_array::ArrayRef;
14use arrow_array::builder::{
15    Float32Builder, Float64Builder, Int16Builder, Int32Builder, Int64Builder, UInt8Builder,
16};
17
18use crate::Result;
19use crate::traits::builder::HanaCompatibleBuilder;
20use crate::traits::sealed::private::Sealed;
21
22// ═══════════════════════════════════════════════════════════════════════════
23// Macro for Primitive Builder Implementation
24// ═══════════════════════════════════════════════════════════════════════════
25
26/// Generate builder wrapper implementation for primitive types.
27///
28/// # Arguments
29///
30/// * `$name` - Wrapper struct name (e.g., `Int32BuilderWrapper`)
31/// * `$builder` - Arrow builder type (e.g., `Int32Builder`)
32/// * `$rust_ty` - Rust target type (e.g., `i32`)
33/// * `$hana_variant` - `HdbValue` variant name (e.g., `INT`)
34macro_rules! impl_primitive_builder {
35    ($name:ident, $builder:ty, $rust_ty:ty, $hana_variant:ident) => {
36        /// Builder wrapper for Arrow primitive arrays.
37        ///
38        /// Implements [`HanaCompatibleBuilder`] for HANA value conversion.
39        #[derive(Debug)]
40        pub struct $name {
41            builder: $builder,
42            len: usize,
43        }
44
45        impl $name {
46            /// Create a new builder with the specified capacity.
47            #[must_use]
48            pub fn new(capacity: usize) -> Self {
49                Self {
50                    builder: <$builder>::with_capacity(capacity),
51                    len: 0,
52                }
53            }
54
55            /// Create a builder with default capacity.
56            #[must_use]
57            pub fn default_capacity() -> Self {
58                Self::new(1024)
59            }
60        }
61
62        impl Sealed for $name {}
63
64        impl HanaCompatibleBuilder for $name {
65            fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
66                use hdbconnect::HdbValue;
67
68                match value {
69                    HdbValue::$hana_variant(v) => {
70                        let converted: $rust_ty = (*v).try_into().map_err(|e| {
71                            crate::ArrowConversionError::value_conversion(
72                                stringify!($name),
73                                format!("cannot convert {} to {}: {}", v, stringify!($rust_ty), e),
74                            )
75                        })?;
76                        self.builder.append_value(converted);
77                    }
78                    other => {
79                        return Err(crate::ArrowConversionError::value_conversion(
80                            stringify!($name),
81                            format!("expected {}, got {:?}", stringify!($hana_variant), other),
82                        ));
83                    }
84                }
85                self.len += 1;
86                Ok(())
87            }
88
89            fn append_null(&mut self) {
90                self.builder.append_null();
91                self.len += 1;
92            }
93
94            fn finish(&mut self) -> ArrayRef {
95                self.len = 0;
96                Arc::new(self.builder.finish())
97            }
98
99            fn len(&self) -> usize {
100                self.len
101            }
102
103            fn capacity(&self) -> Option<usize> {
104                Some(self.builder.capacity())
105            }
106        }
107    };
108}
109
110// ═══════════════════════════════════════════════════════════════════════════
111// Builder Implementations
112// ═══════════════════════════════════════════════════════════════════════════
113
114impl_primitive_builder!(UInt8BuilderWrapper, UInt8Builder, u8, TINYINT);
115impl_primitive_builder!(Int16BuilderWrapper, Int16Builder, i16, SMALLINT);
116impl_primitive_builder!(Int32BuilderWrapper, Int32Builder, i32, INT);
117impl_primitive_builder!(Int64BuilderWrapper, Int64Builder, i64, BIGINT);
118impl_primitive_builder!(Float32BuilderWrapper, Float32Builder, f32, REAL);
119impl_primitive_builder!(Float64BuilderWrapper, Float64Builder, f64, DOUBLE);
120
121#[cfg(test)]
122mod tests {
123    use hdbconnect::HdbValue;
124
125    use super::*;
126
127    #[test]
128    fn test_int32_builder_wrapper() {
129        let mut builder = Int32BuilderWrapper::new(10);
130
131        assert_eq!(builder.len(), 0);
132        assert!(builder.is_empty());
133
134        builder.append_hana_value(&HdbValue::INT(42)).unwrap();
135        builder.append_null();
136        builder.append_hana_value(&HdbValue::INT(-100)).unwrap();
137
138        assert_eq!(builder.len(), 3);
139
140        let array = builder.finish();
141        assert_eq!(array.len(), 3);
142        assert_eq!(builder.len(), 0); // Reset after finish
143    }
144
145    #[test]
146    fn test_float64_builder_wrapper() {
147        let mut builder = Float64BuilderWrapper::new(5);
148
149        builder.append_hana_value(&HdbValue::DOUBLE(3.14)).unwrap();
150        builder.append_null();
151
152        let array = builder.finish();
153        assert_eq!(array.len(), 2);
154    }
155
156    #[test]
157    fn test_uint8_builder_wrapper() {
158        let mut builder = UInt8BuilderWrapper::new(5);
159
160        builder.append_hana_value(&HdbValue::TINYINT(255)).unwrap();
161        let array = builder.finish();
162        assert_eq!(array.len(), 1);
163    }
164
165    #[test]
166    fn test_capacity_hint() {
167        let builder = Int32BuilderWrapper::new(100);
168        assert_eq!(builder.capacity(), Some(100));
169    }
170}