1use std::sync::Arc;
11
12use arrow_array::ArrayRef;
13use arrow_array::builder::{
14 BinaryBuilder, FixedSizeBinaryBuilder, LargeBinaryBuilder, LargeStringBuilder, StringBuilder,
15};
16
17use crate::Result;
18use crate::traits::builder::HanaCompatibleBuilder;
19use crate::traits::sealed::private::Sealed;
20
21#[derive(Debug)]
27pub struct StringBuilderWrapper {
28 builder: StringBuilder,
29 len: usize,
30}
31
32impl StringBuilderWrapper {
33 #[must_use]
40 pub fn new(capacity: usize, data_capacity: usize) -> Self {
41 Self {
42 builder: StringBuilder::with_capacity(capacity, data_capacity),
43 len: 0,
44 }
45 }
46
47 #[must_use]
49 pub fn default_capacity() -> Self {
50 Self::new(1024, 32 * 1024)
51 }
52}
53
54impl Sealed for StringBuilderWrapper {}
55
56impl HanaCompatibleBuilder for StringBuilderWrapper {
57 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
58 use hdbconnect::HdbValue;
59
60 match value {
61 HdbValue::STRING(s) => {
62 self.builder.append_value(s);
63 }
64 other => {
66 self.builder.append_value(format!("{other:?}"));
67 }
68 }
69 self.len += 1;
70 Ok(())
71 }
72
73 fn append_null(&mut self) {
74 self.builder.append_null();
75 self.len += 1;
76 }
77
78 fn finish(&mut self) -> ArrayRef {
79 self.len = 0;
80 Arc::new(self.builder.finish())
81 }
82
83 fn len(&self) -> usize {
84 self.len
85 }
86
87 fn capacity(&self) -> Option<usize> {
88 None
90 }
91}
92
93#[derive(Debug)]
98pub struct LargeStringBuilderWrapper {
99 builder: LargeStringBuilder,
100 len: usize,
101 max_lob_bytes: Option<usize>,
102}
103
104impl LargeStringBuilderWrapper {
105 #[must_use]
107 pub fn new(capacity: usize, data_capacity: usize) -> Self {
108 Self {
109 builder: LargeStringBuilder::with_capacity(capacity, data_capacity),
110 len: 0,
111 max_lob_bytes: None,
112 }
113 }
114
115 #[must_use]
117 pub fn default_capacity() -> Self {
118 Self::new(1024, 1024 * 1024) }
120
121 #[must_use]
125 pub const fn with_max_lob_bytes(mut self, max: usize) -> Self {
126 self.max_lob_bytes = Some(max);
127 self
128 }
129
130 fn materialize_clob(&self, clob: hdbconnect::types::CLob) -> Result<String> {
132 if let Some(max) = self.max_lob_bytes {
133 #[allow(clippy::cast_possible_truncation)]
135 let lob_size = clob.total_byte_length() as usize;
136 if lob_size > max {
137 return Err(crate::ArrowConversionError::lob_streaming(format!(
138 "CLOB size {lob_size} bytes exceeds max_lob_bytes limit {max} bytes",
139 )));
140 }
141 }
142
143 clob.into_string().map_err(|e| {
144 crate::ArrowConversionError::lob_streaming(format!("CLOB read failed: {e}"))
145 })
146 }
147
148 fn materialize_nclob(&self, nclob: hdbconnect::types::NCLob) -> Result<String> {
150 if let Some(max) = self.max_lob_bytes {
151 #[allow(clippy::cast_possible_truncation)]
153 let lob_size = nclob.total_byte_length() as usize;
154 if lob_size > max {
155 return Err(crate::ArrowConversionError::lob_streaming(format!(
156 "NCLOB size {lob_size} bytes exceeds max_lob_bytes limit {max} bytes",
157 )));
158 }
159 }
160
161 nclob.into_string().map_err(|e| {
162 crate::ArrowConversionError::lob_streaming(format!("NCLOB read failed: {e}"))
163 })
164 }
165}
166
167impl Sealed for LargeStringBuilderWrapper {}
168
169impl HanaCompatibleBuilder for LargeStringBuilderWrapper {
170 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
171 use hdbconnect::HdbValue;
172
173 match value {
174 HdbValue::STRING(s) => {
175 self.builder.append_value(s);
176 }
177 HdbValue::SYNC_CLOB(clob) => {
178 let content = self.materialize_clob(clob.clone())?;
179 self.builder.append_value(&content);
180 }
181 HdbValue::SYNC_NCLOB(nclob) => {
182 let content = self.materialize_nclob(nclob.clone())?;
183 self.builder.append_value(&content);
184 }
185 other => {
186 return Err(crate::ArrowConversionError::value_conversion(
187 "large_string",
188 format!(
189 "cannot convert {:?} to LargeUtf8",
190 std::mem::discriminant(other)
191 ),
192 ));
193 }
194 }
195 self.len += 1;
196 Ok(())
197 }
198
199 fn append_null(&mut self) {
200 self.builder.append_null();
201 self.len += 1;
202 }
203
204 fn finish(&mut self) -> ArrayRef {
205 self.len = 0;
206 Arc::new(self.builder.finish())
207 }
208
209 fn len(&self) -> usize {
210 self.len
211 }
212
213 fn capacity(&self) -> Option<usize> {
214 None
215 }
216}
217
218#[derive(Debug)]
224pub struct BinaryBuilderWrapper {
225 builder: BinaryBuilder,
226 len: usize,
227}
228
229impl BinaryBuilderWrapper {
230 #[must_use]
232 pub fn new(capacity: usize, data_capacity: usize) -> Self {
233 Self {
234 builder: BinaryBuilder::with_capacity(capacity, data_capacity),
235 len: 0,
236 }
237 }
238
239 #[must_use]
241 pub fn default_capacity() -> Self {
242 Self::new(1024, 64 * 1024) }
244}
245
246impl Sealed for BinaryBuilderWrapper {}
247
248impl HanaCompatibleBuilder for BinaryBuilderWrapper {
249 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
250 use hdbconnect::HdbValue;
251
252 match value {
253 HdbValue::BINARY(bytes) | HdbValue::GEOMETRY(bytes) | HdbValue::POINT(bytes) => {
255 self.builder.append_value(bytes);
256 }
257 other => {
258 return Err(crate::ArrowConversionError::value_conversion(
259 "binary",
260 format!("cannot convert {other:?} to binary"),
261 ));
262 }
263 }
264 self.len += 1;
265 Ok(())
266 }
267
268 fn append_null(&mut self) {
269 self.builder.append_null();
270 self.len += 1;
271 }
272
273 fn finish(&mut self) -> ArrayRef {
274 self.len = 0;
275 Arc::new(self.builder.finish())
276 }
277
278 fn len(&self) -> usize {
279 self.len
280 }
281
282 fn capacity(&self) -> Option<usize> {
283 None
284 }
285}
286
287#[derive(Debug)]
292pub struct LargeBinaryBuilderWrapper {
293 builder: LargeBinaryBuilder,
294 len: usize,
295 max_lob_bytes: Option<usize>,
296}
297
298impl LargeBinaryBuilderWrapper {
299 #[must_use]
301 pub fn new(capacity: usize, data_capacity: usize) -> Self {
302 Self {
303 builder: LargeBinaryBuilder::with_capacity(capacity, data_capacity),
304 len: 0,
305 max_lob_bytes: None,
306 }
307 }
308
309 #[must_use]
311 pub fn default_capacity() -> Self {
312 Self::new(1024, 1024 * 1024) }
314
315 #[must_use]
319 pub const fn with_max_lob_bytes(mut self, max: usize) -> Self {
320 self.max_lob_bytes = Some(max);
321 self
322 }
323
324 fn materialize_blob(&self, blob: hdbconnect::types::BLob) -> Result<Vec<u8>> {
326 if let Some(max) = self.max_lob_bytes {
327 #[allow(clippy::cast_possible_truncation)]
329 let lob_size = blob.total_byte_length() as usize;
330 if lob_size > max {
331 return Err(crate::ArrowConversionError::lob_streaming(format!(
332 "BLOB size {lob_size} bytes exceeds max_lob_bytes limit {max} bytes",
333 )));
334 }
335 }
336
337 blob.into_bytes().map_err(|e| {
338 crate::ArrowConversionError::lob_streaming(format!("BLOB read failed: {e}"))
339 })
340 }
341}
342
343impl Sealed for LargeBinaryBuilderWrapper {}
344
345impl HanaCompatibleBuilder for LargeBinaryBuilderWrapper {
346 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
347 use hdbconnect::HdbValue;
348
349 match value {
350 HdbValue::BINARY(bytes) => {
351 self.builder.append_value(bytes);
352 }
353 HdbValue::SYNC_BLOB(blob) => {
354 let content = self.materialize_blob(blob.clone())?;
355 self.builder.append_value(&content);
356 }
357 other => {
358 return Err(crate::ArrowConversionError::value_conversion(
359 "large_binary",
360 format!(
361 "cannot convert {:?} to LargeBinary",
362 std::mem::discriminant(other)
363 ),
364 ));
365 }
366 }
367 self.len += 1;
368 Ok(())
369 }
370
371 fn append_null(&mut self) {
372 self.builder.append_null();
373 self.len += 1;
374 }
375
376 fn finish(&mut self) -> ArrayRef {
377 self.len = 0;
378 Arc::new(self.builder.finish())
379 }
380
381 fn len(&self) -> usize {
382 self.len
383 }
384
385 fn capacity(&self) -> Option<usize> {
386 None
387 }
388}
389
390#[derive(Debug)]
392pub struct FixedSizeBinaryBuilderWrapper {
393 builder: FixedSizeBinaryBuilder,
394 byte_width: i32,
395 len: usize,
396}
397
398impl FixedSizeBinaryBuilderWrapper {
399 #[must_use]
406 pub fn new(capacity: usize, byte_width: i32) -> Self {
407 Self {
408 builder: FixedSizeBinaryBuilder::with_capacity(capacity, byte_width),
409 byte_width,
410 len: 0,
411 }
412 }
413}
414
415impl Sealed for FixedSizeBinaryBuilderWrapper {}
416
417impl HanaCompatibleBuilder for FixedSizeBinaryBuilderWrapper {
418 fn append_hana_value(&mut self, value: &hdbconnect::HdbValue) -> Result<()> {
419 use hdbconnect::HdbValue;
420
421 match value {
422 HdbValue::BINARY(bytes) => {
423 #[allow(clippy::cast_sign_loss)]
424 if bytes.len() != self.byte_width as usize {
425 return Err(crate::ArrowConversionError::value_conversion(
426 "fixed_size_binary",
427 format!("expected {} bytes, got {}", self.byte_width, bytes.len()),
428 ));
429 }
430 self.builder.append_value(bytes).map_err(|e| {
431 crate::ArrowConversionError::value_conversion(
432 "fixed_size_binary",
433 e.to_string(),
434 )
435 })?;
436 }
437 other => {
438 return Err(crate::ArrowConversionError::value_conversion(
439 "fixed_size_binary",
440 format!("cannot convert {other:?} to fixed-size binary"),
441 ));
442 }
443 }
444 self.len += 1;
445 Ok(())
446 }
447
448 fn append_null(&mut self) {
449 self.builder.append_null();
450 self.len += 1;
451 }
452
453 fn finish(&mut self) -> ArrayRef {
454 self.len = 0;
455 Arc::new(self.builder.finish())
456 }
457
458 fn len(&self) -> usize {
459 self.len
460 }
461
462 fn capacity(&self) -> Option<usize> {
463 None
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use arrow_array::{
470 Array, BinaryArray, FixedSizeBinaryArray, LargeBinaryArray, LargeStringArray, StringArray,
471 };
472 use hdbconnect::HdbValue;
473
474 use super::*;
475
476 #[test]
481 fn test_string_builder_new() {
482 let builder = StringBuilderWrapper::new(10, 100);
483 assert_eq!(builder.len(), 0);
484 assert!(builder.capacity().is_none());
485 }
486
487 #[test]
488 fn test_string_builder_default_capacity() {
489 let builder = StringBuilderWrapper::default_capacity();
490 assert_eq!(builder.len(), 0);
491 }
492
493 #[test]
494 fn test_string_builder_append_string() {
495 let mut builder = StringBuilderWrapper::new(10, 100);
496 builder
497 .append_hana_value(&HdbValue::STRING("hello".to_string()))
498 .unwrap();
499 assert_eq!(builder.len(), 1);
500 }
501
502 #[test]
503 fn test_string_builder_append_null() {
504 let mut builder = StringBuilderWrapper::new(10, 100);
505 builder.append_null();
506 assert_eq!(builder.len(), 1);
507
508 let array = builder.finish();
509 let string_array = array.as_any().downcast_ref::<StringArray>().unwrap();
510 assert!(string_array.is_null(0));
511 }
512
513 #[test]
514 fn test_string_builder_append_non_string_type() {
515 let mut builder = StringBuilderWrapper::new(10, 100);
516 builder.append_hana_value(&HdbValue::INT(42)).unwrap();
517 assert_eq!(builder.len(), 1);
518
519 let array = builder.finish();
520 let string_array = array.as_any().downcast_ref::<StringArray>().unwrap();
521 assert!(string_array.value(0).contains("INT"));
522 }
523
524 #[test]
525 fn test_string_builder_finish_and_reuse() {
526 let mut builder = StringBuilderWrapper::new(10, 100);
527 builder
528 .append_hana_value(&HdbValue::STRING("first".to_string()))
529 .unwrap();
530 let _array1 = builder.finish();
531 assert_eq!(builder.len(), 0);
532
533 builder
534 .append_hana_value(&HdbValue::STRING("second".to_string()))
535 .unwrap();
536 let array2 = builder.finish();
537 assert_eq!(array2.len(), 1);
538 }
539
540 #[test]
541 fn test_string_builder_empty_string() {
542 let mut builder = StringBuilderWrapper::new(10, 100);
543 builder
544 .append_hana_value(&HdbValue::STRING(String::new()))
545 .unwrap();
546
547 let array = builder.finish();
548 let string_array = array.as_any().downcast_ref::<StringArray>().unwrap();
549 assert_eq!(string_array.value(0), "");
550 }
551
552 #[test]
553 fn test_string_builder_unicode() {
554 let mut builder = StringBuilderWrapper::new(10, 1000);
555 builder
556 .append_hana_value(&HdbValue::STRING("日本語テスト".to_string()))
557 .unwrap();
558 builder
559 .append_hana_value(&HdbValue::STRING("émojis: 🚀🎉".to_string()))
560 .unwrap();
561
562 let array = builder.finish();
563 let string_array = array.as_any().downcast_ref::<StringArray>().unwrap();
564 assert_eq!(string_array.value(0), "日本語テスト");
565 assert_eq!(string_array.value(1), "émojis: 🚀🎉");
566 }
567
568 #[test]
573 fn test_large_string_builder_new() {
574 let builder = LargeStringBuilderWrapper::new(10, 1000);
575 assert_eq!(builder.len(), 0);
576 assert!(builder.max_lob_bytes.is_none());
577 }
578
579 #[test]
580 fn test_large_string_builder_default_capacity() {
581 let builder = LargeStringBuilderWrapper::default_capacity();
582 assert_eq!(builder.len(), 0);
583 }
584
585 #[test]
586 fn test_large_string_builder_with_max_lob_bytes() {
587 let builder = LargeStringBuilderWrapper::new(10, 1000).with_max_lob_bytes(1_000_000);
588 assert_eq!(builder.max_lob_bytes, Some(1_000_000));
589 }
590
591 #[test]
592 fn test_large_string_builder_append_string() {
593 let mut builder = LargeStringBuilderWrapper::new(10, 1000);
594 builder
595 .append_hana_value(&HdbValue::STRING("large text".to_string()))
596 .unwrap();
597
598 let array = builder.finish();
599 let large_string_array = array.as_any().downcast_ref::<LargeStringArray>().unwrap();
600 assert_eq!(large_string_array.value(0), "large text");
601 }
602
603 #[test]
604 fn test_large_string_builder_append_null() {
605 let mut builder = LargeStringBuilderWrapper::new(10, 1000);
606 builder.append_null();
607
608 let array = builder.finish();
609 let large_string_array = array.as_any().downcast_ref::<LargeStringArray>().unwrap();
610 assert!(large_string_array.is_null(0));
611 }
612
613 #[test]
614 fn test_large_string_builder_reject_non_string_type() {
615 let mut builder = LargeStringBuilderWrapper::new(10, 1000);
616 let result = builder.append_hana_value(&HdbValue::BIGINT(123456789));
617
618 assert!(result.is_err());
619 let err = result.unwrap_err();
620 assert!(err.is_value_conversion());
621 }
622
623 #[test]
628 fn test_binary_builder_new() {
629 let builder = BinaryBuilderWrapper::new(10, 100);
630 assert_eq!(builder.len(), 0);
631 }
632
633 #[test]
634 fn test_binary_builder_default_capacity() {
635 let builder = BinaryBuilderWrapper::default_capacity();
636 assert_eq!(builder.len(), 0);
637 }
638
639 #[test]
640 fn test_binary_builder_append_binary() {
641 let mut builder = BinaryBuilderWrapper::new(10, 100);
642 builder
643 .append_hana_value(&HdbValue::BINARY(vec![1, 2, 3]))
644 .unwrap();
645
646 let array = builder.finish();
647 let binary_array = array.as_any().downcast_ref::<BinaryArray>().unwrap();
648 assert_eq!(binary_array.value(0), &[1, 2, 3]);
649 }
650
651 #[test]
652 fn test_binary_builder_append_null() {
653 let mut builder = BinaryBuilderWrapper::new(10, 100);
654 builder.append_null();
655
656 let array = builder.finish();
657 let binary_array = array.as_any().downcast_ref::<BinaryArray>().unwrap();
658 assert!(binary_array.is_null(0));
659 }
660
661 #[test]
662 fn test_binary_builder_append_geometry() {
663 let mut builder = BinaryBuilderWrapper::new(10, 100);
664 builder
665 .append_hana_value(&HdbValue::GEOMETRY(vec![0x00, 0x01, 0x02]))
666 .unwrap();
667
668 let array = builder.finish();
669 assert_eq!(array.len(), 1);
670 }
671
672 #[test]
673 fn test_binary_builder_append_point() {
674 let mut builder = BinaryBuilderWrapper::new(10, 100);
675 builder
676 .append_hana_value(&HdbValue::POINT(vec![0xAB, 0xCD]))
677 .unwrap();
678
679 let array = builder.finish();
680 assert_eq!(array.len(), 1);
681 }
682
683 #[test]
684 fn test_binary_builder_reject_string() {
685 let mut builder = BinaryBuilderWrapper::new(10, 100);
686 let result = builder.append_hana_value(&HdbValue::STRING("text".to_string()));
687 assert!(result.is_err());
688 assert!(result.unwrap_err().is_value_conversion());
689 }
690
691 #[test]
692 fn test_binary_builder_empty_binary() {
693 let mut builder = BinaryBuilderWrapper::new(10, 100);
694 builder
695 .append_hana_value(&HdbValue::BINARY(vec![]))
696 .unwrap();
697
698 let array = builder.finish();
699 let binary_array = array.as_any().downcast_ref::<BinaryArray>().unwrap();
700 assert!(binary_array.value(0).is_empty());
701 }
702
703 #[test]
708 fn test_large_binary_builder_new() {
709 let builder = LargeBinaryBuilderWrapper::new(10, 1000);
710 assert_eq!(builder.len(), 0);
711 assert!(builder.max_lob_bytes.is_none());
712 }
713
714 #[test]
715 fn test_large_binary_builder_default_capacity() {
716 let builder = LargeBinaryBuilderWrapper::default_capacity();
717 assert_eq!(builder.len(), 0);
718 }
719
720 #[test]
721 fn test_large_binary_builder_with_max_lob_bytes() {
722 let builder = LargeBinaryBuilderWrapper::new(10, 1000).with_max_lob_bytes(1_000_000);
723 assert_eq!(builder.max_lob_bytes, Some(1_000_000));
724 }
725
726 #[test]
727 fn test_large_binary_builder_append_binary() {
728 let mut builder = LargeBinaryBuilderWrapper::new(10, 1000);
729 builder
730 .append_hana_value(&HdbValue::BINARY(vec![1, 2, 3, 4, 5]))
731 .unwrap();
732
733 let array = builder.finish();
734 let large_binary_array = array.as_any().downcast_ref::<LargeBinaryArray>().unwrap();
735 assert_eq!(large_binary_array.value(0), &[1, 2, 3, 4, 5]);
736 }
737
738 #[test]
739 fn test_large_binary_builder_append_null() {
740 let mut builder = LargeBinaryBuilderWrapper::new(10, 1000);
741 builder.append_null();
742
743 let array = builder.finish();
744 let large_binary_array = array.as_any().downcast_ref::<LargeBinaryArray>().unwrap();
745 assert!(large_binary_array.is_null(0));
746 }
747
748 #[test]
749 fn test_large_binary_builder_reject_string() {
750 let mut builder = LargeBinaryBuilderWrapper::new(10, 1000);
751 let result = builder.append_hana_value(&HdbValue::STRING("text".to_string()));
752 assert!(result.is_err());
753 assert!(result.unwrap_err().is_value_conversion());
754 }
755
756 #[test]
761 fn test_fixed_size_binary_builder_new() {
762 let builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
763 assert_eq!(builder.len(), 0);
764 assert_eq!(builder.byte_width, 4);
765 }
766
767 #[test]
768 fn test_fixed_size_binary_builder_correct_size() {
769 let mut builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
770 builder
771 .append_hana_value(&HdbValue::BINARY(vec![1, 2, 3, 4]))
772 .unwrap();
773
774 let array = builder.finish();
775 let fixed_binary = array
776 .as_any()
777 .downcast_ref::<FixedSizeBinaryArray>()
778 .unwrap();
779 assert_eq!(fixed_binary.value(0), &[1, 2, 3, 4]);
780 }
781
782 #[test]
783 fn test_fixed_size_binary_builder_wrong_size_smaller() {
784 let mut builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
785 let result = builder.append_hana_value(&HdbValue::BINARY(vec![1, 2]));
786 assert!(result.is_err());
787 let err = result.unwrap_err();
788 assert!(err.is_value_conversion());
789 assert!(err.to_string().contains("expected 4 bytes"));
790 }
791
792 #[test]
793 fn test_fixed_size_binary_builder_wrong_size_larger() {
794 let mut builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
795 let result = builder.append_hana_value(&HdbValue::BINARY(vec![1, 2, 3, 4, 5, 6]));
796 assert!(result.is_err());
797 }
798
799 #[test]
800 fn test_fixed_size_binary_builder_append_null() {
801 let mut builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
802 builder.append_null();
803
804 let array = builder.finish();
805 let fixed_binary = array
806 .as_any()
807 .downcast_ref::<FixedSizeBinaryArray>()
808 .unwrap();
809 assert!(fixed_binary.is_null(0));
810 }
811
812 #[test]
813 fn test_fixed_size_binary_builder_reject_non_binary() {
814 let mut builder = FixedSizeBinaryBuilderWrapper::new(10, 4);
815 let result = builder.append_hana_value(&HdbValue::INT(42));
816 assert!(result.is_err());
817 assert!(result.unwrap_err().is_value_conversion());
818 }
819
820 #[test]
821 fn test_fixed_size_binary_builder_different_widths() {
822 let mut builder8 = FixedSizeBinaryBuilderWrapper::new(10, 8);
824 builder8
825 .append_hana_value(&HdbValue::BINARY(vec![1, 2, 3, 4, 5, 6, 7, 8]))
826 .unwrap();
827 assert_eq!(builder8.len(), 1);
828
829 let mut builder16 = FixedSizeBinaryBuilderWrapper::new(10, 16);
831 builder16
832 .append_hana_value(&HdbValue::BINARY(vec![0; 16]))
833 .unwrap();
834 assert_eq!(builder16.len(), 1);
835 }
836}