1use std::collections::HashMap;
19use std::sync::Arc;
20
21use crate::arrow::schema::extension::try_add_extension_type;
22use crate::arrow::schema::primitive::convert_primitive;
23use crate::arrow::schema::virtual_type::{RowGroupIndex, RowNumber};
24use crate::arrow::{PARQUET_FIELD_ID_META_KEY, ProjectionMask};
25use crate::basic::{ConvertedType, Repetition};
26use crate::errors::ParquetError;
27use crate::errors::Result;
28use crate::schema::types::{SchemaDescriptor, Type, TypePtr};
29use arrow_schema::{DataType, Field, Fields, SchemaBuilder, extension::ExtensionType};
30
31fn get_repetition(t: &Type) -> Repetition {
32 let info = t.get_basic_info();
33 match info.has_repetition() {
34 true => info.repetition(),
35 false => Repetition::REQUIRED,
36 }
37}
38
39#[derive(Debug, Clone)]
41pub struct ParquetField {
42 pub rep_level: i16,
45 pub def_level: i16,
49 pub nullable: bool,
51 pub arrow_type: DataType,
56 pub field_type: ParquetFieldType,
58}
59
60impl ParquetField {
61 fn into_list(self, name: &str) -> Self {
65 ParquetField {
66 rep_level: self.rep_level,
67 def_level: self.def_level,
68 nullable: false,
69 arrow_type: DataType::List(Arc::new(Field::new(name, self.arrow_type.clone(), false))),
70 field_type: ParquetFieldType::Group {
71 children: vec![self],
72 },
73 }
74 }
75
76 fn into_list_with_arrow_list_hint(
83 self,
84 parquet_field_type: &Type,
85 list_data_type: Option<DataType>,
86 ) -> Result<Self, ParquetError> {
87 let arrow_field = match &list_data_type {
88 Some(
89 DataType::List(field_hint)
90 | DataType::LargeList(field_hint)
91 | DataType::FixedSizeList(field_hint, _),
92 ) => Some(field_hint.as_ref()),
93 Some(_) => {
94 return Err(general_err!(
95 "Internal error: should be validated earlier that list_data_type is only a type of list"
96 ));
97 }
98 None => None,
99 };
100
101 let arrow_field = convert_field(
102 parquet_field_type,
103 &self,
104 arrow_field,
105 false,
107 )?
108 .with_nullable(false);
109
110 Ok(ParquetField {
111 rep_level: self.rep_level,
112 def_level: self.def_level,
113 nullable: false,
114 arrow_type: match list_data_type {
115 Some(DataType::List(_)) => DataType::List(Arc::new(arrow_field)),
116 Some(DataType::LargeList(_)) => DataType::LargeList(Arc::new(arrow_field)),
117 Some(DataType::FixedSizeList(_, len)) => {
118 DataType::FixedSizeList(Arc::new(arrow_field), len)
119 }
120 _ => DataType::List(Arc::new(arrow_field)),
121 },
122 field_type: ParquetFieldType::Group {
123 children: vec![self],
124 },
125 })
126 }
127
128 pub fn children(&self) -> Option<&[Self]> {
130 match &self.field_type {
131 ParquetFieldType::Primitive { .. } => None,
132 ParquetFieldType::Group { children } => Some(children),
133 ParquetFieldType::Virtual(_) => None,
134 }
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq)]
140pub enum VirtualColumnType {
141 RowNumber,
143 RowGroupIndex,
145}
146
147#[derive(Debug, Clone)]
148pub enum ParquetFieldType {
149 Primitive {
150 col_idx: usize,
152 primitive_type: TypePtr,
154 },
155 Group {
156 children: Vec<ParquetField>,
157 },
158 Virtual(VirtualColumnType),
161}
162
163struct VisitorContext {
165 rep_level: i16,
166 def_level: i16,
167 data_type: Option<DataType>,
169
170 treat_repeated_as_list_arrow_hint: bool,
180}
181
182impl VisitorContext {
183 fn levels(&self, repetition: Repetition) -> (i16, i16, bool) {
186 match repetition {
187 Repetition::OPTIONAL => (self.def_level + 1, self.rep_level, true),
188 Repetition::REQUIRED => (self.def_level, self.rep_level, false),
189 Repetition::REPEATED => (self.def_level + 1, self.rep_level + 1, false),
190 }
191 }
192}
193
194struct Visitor {
200 next_col_idx: usize,
202
203 mask: ProjectionMask,
205}
206
207impl Visitor {
208 fn visit_primitive(
209 &mut self,
210 primitive_type: &TypePtr,
211 context: VisitorContext,
212 ) -> Result<Option<ParquetField>> {
213 let col_idx = self.next_col_idx;
214 self.next_col_idx += 1;
215
216 if !self.mask.leaf_included(col_idx) {
217 return Ok(None);
218 }
219
220 let repetition = get_repetition(primitive_type);
221 let (def_level, rep_level, nullable) = context.levels(repetition);
222
223 let primitive_arrow_data_type = match repetition {
224 Repetition::REPEATED if context.treat_repeated_as_list_arrow_hint => {
225 let arrow_field = match &context.data_type {
226 Some(DataType::List(f)) => Some(f.as_ref()),
227 Some(DataType::LargeList(f)) => Some(f.as_ref()),
228 Some(DataType::FixedSizeList(f, _)) => Some(f.as_ref()),
229 Some(d) => {
230 return Err(arrow_err!(
231 "incompatible arrow schema, expected list got {} for repeated primitive field",
232 d
233 ));
234 }
235 None => None,
236 };
237
238 arrow_field.map(|f| f.data_type().clone())
239 }
240 _ => context.data_type.clone(),
241 };
242
243 let arrow_type = convert_primitive(primitive_type, primitive_arrow_data_type)?;
244
245 let primitive_field = ParquetField {
246 rep_level,
247 def_level,
248 nullable,
249 arrow_type,
250 field_type: ParquetFieldType::Primitive {
251 primitive_type: primitive_type.clone(),
252 col_idx,
253 },
254 };
255
256 Ok(Some(match repetition {
257 Repetition::REPEATED if context.treat_repeated_as_list_arrow_hint => {
258 primitive_field.into_list_with_arrow_list_hint(primitive_type, context.data_type)?
259 }
260 Repetition::REPEATED => primitive_field.into_list(primitive_type.name()),
261 _ => primitive_field,
262 }))
263 }
264
265 fn visit_struct(
266 &mut self,
267 struct_type: &TypePtr,
268 context: VisitorContext,
269 ) -> Result<Option<ParquetField>> {
270 let repetition = get_repetition(struct_type);
272 let (def_level, rep_level, nullable) = context.levels(repetition);
273
274 let parquet_fields = struct_type.get_fields();
275
276 let arrow_struct = match repetition {
278 Repetition::REPEATED if context.treat_repeated_as_list_arrow_hint => {
279 let arrow_field = match &context.data_type {
280 Some(DataType::List(f)) => Some(f.as_ref()),
281 Some(DataType::LargeList(f)) => Some(f.as_ref()),
282 Some(DataType::FixedSizeList(f, _)) => Some(f.as_ref()),
283 Some(d) => {
284 return Err(arrow_err!(
285 "incompatible arrow schema, expected list got {} for repeated struct field",
286 d
287 ));
288 }
289 None => None,
290 };
291
292 arrow_field.map(|f| f.data_type())
293 }
294 _ => context.data_type.as_ref(),
295 };
296
297 let arrow_fields = match &arrow_struct {
298 Some(DataType::Struct(fields)) => {
299 if fields.len() != parquet_fields.len() {
300 return Err(arrow_err!(
301 "incompatible arrow schema, expected {} struct fields got {}",
302 parquet_fields.len(),
303 fields.len()
304 ));
305 }
306 Some(fields)
307 }
308 Some(d) => {
309 return Err(arrow_err!(
310 "incompatible arrow schema, expected struct got {}",
311 d
312 ));
313 }
314 None => None,
315 };
316
317 let mut child_fields = SchemaBuilder::with_capacity(parquet_fields.len());
318 let mut children = Vec::with_capacity(parquet_fields.len());
319
320 for (idx, parquet_field) in parquet_fields.iter().enumerate() {
322 let data_type = match arrow_fields {
323 Some(fields) => {
324 let field = &fields[idx];
325 if field.name() != parquet_field.name() {
326 return Err(arrow_err!(
327 "incompatible arrow schema, expected field named {} got {}",
328 parquet_field.name(),
329 field.name()
330 ));
331 }
332 Some(field.data_type().clone())
333 }
334 None => None,
335 };
336
337 let arrow_field = arrow_fields.map(|x| &*x[idx]);
338 let child_ctx = VisitorContext {
339 rep_level,
340 def_level,
341 data_type,
342
343 treat_repeated_as_list_arrow_hint: true,
350 };
351
352 if let Some(child) = self.dispatch(parquet_field, child_ctx)? {
353 child_fields.push(convert_field(parquet_field, &child, arrow_field, true)?);
356 children.push(child);
357 }
358 }
359
360 if children.is_empty() {
361 return Ok(None);
362 }
363
364 let struct_field = ParquetField {
365 rep_level,
366 def_level,
367 nullable,
368 arrow_type: DataType::Struct(child_fields.finish().fields),
369 field_type: ParquetFieldType::Group { children },
370 };
371
372 Ok(Some(match repetition {
373 Repetition::REPEATED if context.treat_repeated_as_list_arrow_hint => {
374 struct_field.into_list_with_arrow_list_hint(struct_type, context.data_type)?
375 }
376 Repetition::REPEATED => struct_field.into_list(struct_type.name()),
377 _ => struct_field,
378 }))
379 }
380
381 fn visit_map(
382 &mut self,
383 map_type: &TypePtr,
384 context: VisitorContext,
385 ) -> Result<Option<ParquetField>> {
386 let rep_level = context.rep_level + 1;
387 let (def_level, nullable) = match get_repetition(map_type) {
388 Repetition::REQUIRED => (context.def_level + 1, false),
389 Repetition::OPTIONAL => (context.def_level + 2, true),
390 Repetition::REPEATED => return Err(arrow_err!("Map cannot be repeated")),
391 };
392
393 if map_type.get_fields().len() != 1 {
394 return Err(arrow_err!(
395 "Map field must have exactly one key_value child, found {}",
396 map_type.get_fields().len()
397 ));
398 }
399
400 let map_key_value = &map_type.get_fields()[0];
402 if map_key_value.get_basic_info().repetition() != Repetition::REPEATED {
403 return Err(arrow_err!("Child of map field must be repeated"));
404 }
405
406 if map_key_value.get_fields().len() == 1 {
409 return self.visit_list(map_type, context);
410 }
411
412 if map_key_value.get_fields().len() != 2 {
413 return Err(arrow_err!(
414 "Child of map field must have two children, found {}",
415 map_key_value.get_fields().len()
416 ));
417 }
418
419 let map_key = &map_key_value.get_fields()[0];
421 let map_value = &map_key_value.get_fields()[1];
422
423 match map_key.get_basic_info().repetition() {
424 Repetition::REPEATED => {
425 return Err(arrow_err!("Map keys cannot be repeated"));
426 }
427 Repetition::REQUIRED | Repetition::OPTIONAL => {
428 }
433 }
434
435 if map_value.get_basic_info().repetition() == Repetition::REPEATED {
436 return Err(arrow_err!("Map values cannot be repeated"));
437 }
438
439 let (arrow_map, arrow_key, arrow_value, sorted) = match &context.data_type {
441 Some(DataType::Map(field, sorted)) => match field.data_type() {
442 DataType::Struct(fields) => {
443 if fields.len() != 2 {
444 return Err(arrow_err!(
445 "Map data type should contain struct with two children, got {}",
446 fields.len()
447 ));
448 }
449
450 (Some(field), Some(&*fields[0]), Some(&*fields[1]), *sorted)
451 }
452 d => {
453 return Err(arrow_err!("Map data type should contain struct got {}", d));
454 }
455 },
456 Some(d) => {
457 return Err(arrow_err!(
458 "incompatible arrow schema, expected map got {}",
459 d
460 ));
461 }
462 None => (None, None, None, false),
463 };
464
465 let maybe_key = {
466 let context = VisitorContext {
467 rep_level,
468 def_level,
469 data_type: arrow_key.map(|x| x.data_type().clone()),
470 treat_repeated_as_list_arrow_hint: false,
472 };
473
474 self.dispatch(map_key, context)?
475 };
476
477 let maybe_value = {
478 let context = VisitorContext {
479 rep_level,
480 def_level,
481 data_type: arrow_value.map(|x| x.data_type().clone()),
482 treat_repeated_as_list_arrow_hint: true,
484 };
485
486 self.dispatch(map_value, context)?
487 };
488
489 match (maybe_key, maybe_value) {
491 (Some(key), Some(value)) => {
492 let key_field = Arc::new(
493 convert_field(map_key, &key, arrow_key, true)?
494 .with_nullable(false),
496 );
497 let value_field = Arc::new(convert_field(map_value, &value, arrow_value, true)?);
498 let field_metadata = arrow_map
499 .map(|field| field.metadata().clone())
500 .unwrap_or_default();
501
502 let map_field = Field::new_struct(
503 map_key_value.name(),
504 [key_field, value_field],
505 false, )
507 .with_metadata(field_metadata);
508
509 Ok(Some(ParquetField {
510 rep_level,
511 def_level,
512 nullable,
513 arrow_type: DataType::Map(Arc::new(map_field), sorted),
514 field_type: ParquetFieldType::Group {
515 children: vec![key, value],
516 },
517 }))
518 }
519 _ => Ok(None),
520 }
521 }
522
523 fn visit_list(
524 &mut self,
525 list_type: &TypePtr,
526 context: VisitorContext,
527 ) -> Result<Option<ParquetField>> {
528 if list_type.is_primitive() {
529 return Err(arrow_err!(
530 "{:?} is a list type and can't be processed as primitive.",
531 list_type
532 ));
533 }
534
535 let fields = list_type.get_fields();
536 if fields.len() != 1 {
537 return Err(arrow_err!(
538 "list type must have a single child, found {}",
539 fields.len()
540 ));
541 }
542
543 let repeated_field = &fields[0];
544 if get_repetition(repeated_field) != Repetition::REPEATED {
545 return Err(arrow_err!("List child must be repeated"));
546 }
547
548 let (def_level, nullable) = match list_type.get_basic_info().repetition() {
550 Repetition::REQUIRED => (context.def_level, false),
551 Repetition::OPTIONAL => (context.def_level + 1, true),
552 Repetition::REPEATED => return Err(arrow_err!("List type cannot be repeated")),
553 };
554
555 let arrow_field = match &context.data_type {
556 Some(DataType::List(f)) => Some(f.as_ref()),
557 Some(DataType::LargeList(f)) => Some(f.as_ref()),
558 Some(DataType::FixedSizeList(f, _)) => Some(f.as_ref()),
559 Some(DataType::ListView(f)) => Some(f.as_ref()),
560 Some(DataType::LargeListView(f)) => Some(f.as_ref()),
561 Some(d) => {
562 return Err(arrow_err!(
563 "incompatible arrow schema, expected list got {}",
564 d
565 ));
566 }
567 None => None,
568 };
569
570 if repeated_field.is_primitive() {
571 let context = VisitorContext {
578 rep_level: context.rep_level,
579 def_level,
580 data_type: arrow_field.map(|f| f.data_type().clone()),
581 treat_repeated_as_list_arrow_hint: false,
582 };
583
584 return match self.visit_primitive(repeated_field, context) {
585 Ok(Some(mut field)) => {
586 field.nullable = nullable;
588 Ok(Some(field))
589 }
590 r => r,
591 };
592 }
593
594 let items = repeated_field.get_fields();
596 if items.len() != 1
597 || (!repeated_field.is_list()
598 && !repeated_field.has_single_repeated_child()
599 && (repeated_field.name() == "array"
600 || repeated_field.name() == format!("{}_tuple", list_type.name())))
601 {
602 let context = VisitorContext {
610 rep_level: context.rep_level,
611 def_level,
612 data_type: arrow_field.map(|f| f.data_type().clone()),
613 treat_repeated_as_list_arrow_hint: false,
614 };
615
616 return match self.visit_struct(repeated_field, context) {
617 Ok(Some(mut field)) => {
618 field.nullable = nullable;
619 Ok(Some(field))
620 }
621 r => r,
622 };
623 }
624
625 let item_type = &items[0];
627 let rep_level = context.rep_level + 1;
628 let def_level = def_level + 1;
629
630 let new_context = VisitorContext {
631 def_level,
632 rep_level,
633 data_type: arrow_field.map(|f| f.data_type().clone()),
634 treat_repeated_as_list_arrow_hint: true,
635 };
636
637 match self.dispatch(item_type, new_context) {
638 Ok(Some(item)) => {
639 let item_field = Arc::new(convert_field(item_type, &item, arrow_field, true)?);
640
641 let arrow_type = match context.data_type {
643 Some(DataType::LargeList(_)) => DataType::LargeList(item_field),
644 Some(DataType::FixedSizeList(_, len)) => {
645 DataType::FixedSizeList(item_field, len)
646 }
647 Some(DataType::ListView(_)) => DataType::ListView(item_field),
648 Some(DataType::LargeListView(_)) => DataType::LargeListView(item_field),
649 _ => DataType::List(item_field),
650 };
651
652 Ok(Some(ParquetField {
653 rep_level,
654 def_level,
655 nullable,
656 arrow_type,
657 field_type: ParquetFieldType::Group {
658 children: vec![item],
659 },
660 }))
661 }
662 r => r,
663 }
664 }
665
666 fn dispatch(
667 &mut self,
668 cur_type: &TypePtr,
669 context: VisitorContext,
670 ) -> Result<Option<ParquetField>> {
671 if cur_type.is_primitive() {
672 self.visit_primitive(cur_type, context)
673 } else {
674 match cur_type.get_basic_info().converted_type() {
675 ConvertedType::LIST => self.visit_list(cur_type, context),
676 ConvertedType::MAP | ConvertedType::MAP_KEY_VALUE => {
677 self.visit_map(cur_type, context)
678 }
679 _ => self.visit_struct(cur_type, context),
680 }
681 }
682 }
683}
684
685pub(super) fn convert_virtual_field(
695 arrow_field: &Field,
696 parent_rep_level: i16,
697 parent_def_level: i16,
698) -> Result<ParquetField> {
699 let nullable = arrow_field.is_nullable();
700 let def_level = if nullable {
701 parent_def_level + 1
702 } else {
703 parent_def_level
704 };
705
706 let extension_name = arrow_field.extension_type_name().ok_or_else(|| {
708 ParquetError::ArrowError(format!(
709 "virtual column field '{}' must have an extension type",
710 arrow_field.name()
711 ))
712 })?;
713
714 let virtual_type = match extension_name {
715 RowNumber::NAME => VirtualColumnType::RowNumber,
716 RowGroupIndex::NAME => VirtualColumnType::RowGroupIndex,
717 _ => {
718 return Err(ParquetError::ArrowError(format!(
719 "unsupported virtual column type '{}' for field '{}'",
720 extension_name,
721 arrow_field.name()
722 )));
723 }
724 };
725
726 Ok(ParquetField {
727 rep_level: parent_rep_level,
728 def_level,
729 nullable,
730 arrow_type: arrow_field.data_type().clone(),
731 field_type: ParquetFieldType::Virtual(virtual_type),
732 })
733}
734
735fn convert_field(
740 parquet_type: &Type,
741 field: &ParquetField,
742 arrow_hint: Option<&Field>,
743 add_field_id: bool,
744) -> Result<Field, ParquetError> {
745 let name = parquet_type.name();
746 let data_type = field.arrow_type.clone();
747 let nullable = field.nullable;
748
749 match arrow_hint {
750 Some(hint) => {
751 #[allow(deprecated)]
753 let field = match (&data_type, hint.dict_id(), hint.dict_is_ordered()) {
754 (DataType::Dictionary(_, _), Some(id), Some(ordered)) =>
755 {
756 #[allow(deprecated)]
757 Field::new_dict(name, data_type, nullable, id, ordered)
758 }
759 _ => Field::new(name, data_type, nullable),
760 };
761
762 Ok(field.with_metadata(hint.metadata().clone()))
763 }
764 None => {
765 let mut ret = Field::new(name, data_type, nullable);
766 let basic_info = parquet_type.get_basic_info();
767 if add_field_id && basic_info.has_id() {
768 let mut meta = HashMap::with_capacity(1);
769 meta.insert(
770 PARQUET_FIELD_ID_META_KEY.to_string(),
771 basic_info.id().to_string(),
772 );
773 ret.set_metadata(meta);
774 }
775 try_add_extension_type(ret, parquet_type)
776 }
777 }
778}
779
780pub fn convert_schema(
786 schema: &SchemaDescriptor,
787 mask: ProjectionMask,
788 embedded_arrow_schema: Option<&Fields>,
789) -> Result<Option<ParquetField>> {
790 let mut visitor = Visitor {
791 next_col_idx: 0,
792 mask,
793 };
794
795 let context = VisitorContext {
796 rep_level: 0,
797 def_level: 0,
798 data_type: embedded_arrow_schema.map(|fields| DataType::Struct(fields.clone())),
799 treat_repeated_as_list_arrow_hint: true,
800 };
801
802 visitor.dispatch(&schema.root_schema_ptr(), context)
803}
804
805pub fn convert_type(parquet_type: &TypePtr) -> Result<ParquetField> {
807 let mut visitor = Visitor {
808 next_col_idx: 0,
809 mask: ProjectionMask::all(),
810 };
811
812 let context = VisitorContext {
813 rep_level: 0,
814 def_level: 0,
815 data_type: None,
816 treat_repeated_as_list_arrow_hint: false,
818 };
819
820 Ok(visitor.dispatch(parquet_type, context)?.unwrap())
821}
822
823#[cfg(test)]
824mod tests {
825 use crate::arrow::schema::complex::convert_schema;
826 use crate::arrow::{PARQUET_FIELD_ID_META_KEY, ProjectionMask};
827 use crate::schema::parser::parse_message_type;
828 use crate::schema::types::SchemaDescriptor;
829 use arrow_schema::{DataType, Field, Fields};
830 use std::sync::Arc;
831
832 trait WithFieldId {
833 fn with_field_id(self, id: i32) -> Self;
834 }
835 impl WithFieldId for arrow_schema::Field {
836 fn with_field_id(self, id: i32) -> Self {
837 let mut metadata = self.metadata().clone();
838 metadata.insert(PARQUET_FIELD_ID_META_KEY.to_string(), id.to_string());
839 self.with_metadata(metadata)
840 }
841 }
842
843 fn test_roundtrip(message_type: &str) -> crate::errors::Result<()> {
844 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
845 let schema = SchemaDescriptor::new(parsed_input_schema);
846
847 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
848
849 let DataType::Struct(schema_fields) = &converted.arrow_type else {
850 panic!("Expected struct from convert_schema");
851 };
852
853 let converted_again =
855 convert_schema(&schema, ProjectionMask::all(), Some(schema_fields))?.unwrap();
856
857 assert_eq!(converted_again.arrow_type, converted.arrow_type);
859
860 Ok(())
861 }
862
863 fn test_expected_type(
864 message_type: &str,
865 expected_fields: Fields,
866 ) -> crate::errors::Result<()> {
867 test_roundtrip(message_type)?;
868
869 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
870 let schema = SchemaDescriptor::new(parsed_input_schema);
871
872 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
873
874 let DataType::Struct(schema_fields) = &converted.arrow_type else {
875 panic!("Expected struct from convert_schema");
876 };
877
878 assert_eq!(schema_fields, &expected_fields);
879
880 Ok(())
881 }
882
883 #[test]
885 fn basic_backward_compatible_list_1() -> crate::errors::Result<()> {
886 test_expected_type(
887 "
888 message schema {
889 optional group my_list (LIST) {
890 repeated int32 element;
891 }
892 }
893 ",
894 Fields::from(vec![
895 Field::new(
897 "my_list",
898 DataType::List(Arc::new(Field::new("element", DataType::Int32, false))),
899 true,
900 ),
901 ]),
902 )
903 }
904
905 #[test]
907 fn basic_backward_compatible_list_2() -> crate::errors::Result<()> {
908 test_expected_type(
909 "
910 message schema {
911 optional group my_list (LIST) {
912 repeated group element {
913 required binary str (STRING);
914 required int32 num;
915 }
916 }
917 }
918 ",
919 Fields::from(vec![
920 Field::new(
922 "my_list",
923 DataType::List(Arc::new(Field::new(
924 "element",
925 DataType::Struct(Fields::from(vec![
926 Field::new("str", DataType::Utf8, false),
927 Field::new("num", DataType::Int32, false),
928 ])),
929 false,
930 ))),
931 true,
932 ),
933 ]),
934 )
935 }
936
937 #[test]
939 fn basic_backward_compatible_list_3() -> crate::errors::Result<()> {
940 test_expected_type(
941 "
942 message schema {
943 optional group my_list (LIST) {
944 repeated group array (LIST) {
945 repeated int32 array;
946 }
947 }
948 }
949 ",
950 Fields::from(vec![
951 Field::new(
953 "my_list",
954 DataType::List(Arc::new(Field::new(
955 "array",
956 DataType::List(Arc::new(Field::new("array", DataType::Int32, false))),
957 false,
958 ))),
959 true,
960 ),
961 ]),
962 )
963 }
964
965 #[test]
967 fn basic_backward_compatible_list_4_1() -> crate::errors::Result<()> {
968 test_expected_type(
969 "
970 message schema {
971 optional group my_list (LIST) {
972 repeated group array {
973 required binary str (STRING);
974 }
975 }
976 }
977 ",
978 Fields::from(vec![
979 Field::new(
981 "my_list",
982 DataType::List(Arc::new(Field::new(
983 "array",
984 DataType::Struct(Fields::from(vec![Field::new(
985 "str",
986 DataType::Utf8,
987 false,
988 )])),
989 false,
990 ))),
991 true,
992 ),
993 ]),
994 )
995 }
996
997 #[test]
999 fn basic_backward_compatible_list_4_2() -> crate::errors::Result<()> {
1000 test_expected_type(
1001 "
1002 message schema {
1003 optional group my_list (LIST) {
1004 repeated group my_list_tuple {
1005 required binary str (STRING);
1006 }
1007 }
1008 }
1009 ",
1010 Fields::from(vec![
1011 Field::new(
1013 "my_list",
1014 DataType::List(Arc::new(Field::new(
1015 "my_list_tuple",
1016 DataType::Struct(Fields::from(vec![Field::new(
1017 "str",
1018 DataType::Utf8,
1019 false,
1020 )])),
1021 false,
1022 ))),
1023 true,
1024 ),
1025 ]),
1026 )
1027 }
1028
1029 #[test]
1031 fn basic_backward_compatible_list_5() -> crate::errors::Result<()> {
1032 test_expected_type(
1033 "
1034 message schema {
1035 optional group my_list (LIST) {
1036 repeated group element {
1037 optional binary str (STRING);
1038 }
1039 }
1040 }
1041 ",
1042 Fields::from(vec![
1043 Field::new(
1045 "my_list",
1046 DataType::List(Arc::new(Field::new("str", DataType::Utf8, true))),
1047 true,
1048 ),
1049 ]),
1050 )
1051 }
1052
1053 #[test]
1054 fn basic_backward_compatible_map_1() -> crate::errors::Result<()> {
1055 test_expected_type(
1056 "
1057 message schema {
1058 optional group my_map (MAP) {
1059 repeated group map {
1060 required binary str (STRING);
1061 required int32 num;
1062 }
1063 }
1064 }
1065 ",
1066 Fields::from(vec![
1067 Field::new(
1069 "my_map",
1070 DataType::Map(
1071 Arc::new(Field::new(
1072 "map",
1073 DataType::Struct(Fields::from(vec![
1074 Field::new("str", DataType::Utf8, false),
1075 Field::new("num", DataType::Int32, false),
1076 ])),
1077 false,
1078 )),
1079 false,
1080 ),
1081 true,
1082 ),
1083 ]),
1084 )
1085 }
1086
1087 #[test]
1088 fn basic_backward_compatible_map_2() -> crate::errors::Result<()> {
1089 test_expected_type(
1090 "
1091 message schema {
1092 optional group my_map (MAP_KEY_VALUE) {
1093 repeated group map {
1094 required binary key (STRING);
1095 optional int32 value;
1096 }
1097 }
1098 }
1099 ",
1100 Fields::from(vec![
1101 Field::new(
1103 "my_map",
1104 DataType::Map(
1105 Arc::new(Field::new(
1106 "map",
1107 DataType::Struct(Fields::from(vec![
1108 Field::new("key", DataType::Utf8, false),
1109 Field::new("value", DataType::Int32, true),
1110 ])),
1111 false,
1112 )),
1113 false,
1114 ),
1115 true,
1116 ),
1117 ]),
1118 )
1119 }
1120
1121 #[test]
1122 fn convert_schema_with_nested_list_repeated_primitive() -> crate::errors::Result<()> {
1123 test_roundtrip(
1124 "
1125 message schema {
1126 optional group f1 (LIST) {
1127 repeated group element {
1128 repeated int32 element;
1129 }
1130 }
1131 }
1132 ",
1133 )
1134 }
1135
1136 #[test]
1137 fn convert_schema_with_repeated_primitive_keep_field_id() -> crate::errors::Result<()> {
1138 let message_type = "
1139 message schema {
1140 repeated BYTE_ARRAY col_1 = 1;
1141 }
1142 ";
1143
1144 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
1145 let schema = SchemaDescriptor::new(parsed_input_schema);
1146
1147 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
1148
1149 let DataType::Struct(schema_fields) = &converted.arrow_type else {
1150 panic!("Expected struct from convert_schema");
1151 };
1152
1153 assert_eq!(schema_fields.len(), 1);
1154
1155 let expected_schema = DataType::Struct(Fields::from(vec![Arc::new(
1156 arrow_schema::Field::new(
1157 "col_1",
1158 DataType::List(Arc::new(
1159 arrow_schema::Field::new("col_1", DataType::Binary, false),
1161 )),
1162 false,
1163 )
1164 .with_field_id(1),
1166 )]));
1167
1168 assert_eq!(converted.arrow_type, expected_schema);
1169
1170 Ok(())
1171 }
1172
1173 #[test]
1174 fn convert_schema_with_repeated_primitive_should_use_inferred_schema()
1175 -> crate::errors::Result<()> {
1176 let message_type = "
1177 message schema {
1178 repeated BYTE_ARRAY col_1 = 1;
1179 }
1180 ";
1181
1182 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
1183 let schema = SchemaDescriptor::new(parsed_input_schema);
1184
1185 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
1186
1187 let DataType::Struct(schema_fields) = &converted.arrow_type else {
1188 panic!("Expected struct from convert_schema");
1189 };
1190
1191 assert_eq!(schema_fields.len(), 1);
1192
1193 let expected_schema = DataType::Struct(Fields::from(vec![Arc::new(
1194 arrow_schema::Field::new(
1195 "col_1",
1196 DataType::List(Arc::new(arrow_schema::Field::new(
1197 "col_1",
1198 DataType::Binary,
1199 false,
1200 ))),
1201 false,
1202 )
1203 .with_metadata(schema_fields[0].metadata().clone()),
1204 )]));
1205
1206 assert_eq!(converted.arrow_type, expected_schema);
1207
1208 let utf8_instead_of_binary = Fields::from(vec![Arc::new(
1209 arrow_schema::Field::new(
1210 "col_1",
1211 DataType::List(Arc::new(arrow_schema::Field::new(
1212 "col_1",
1213 DataType::Utf8,
1214 false,
1215 ))),
1216 false,
1217 )
1218 .with_metadata(schema_fields[0].metadata().clone()),
1219 )]);
1220
1221 let converted_again = convert_schema(
1223 &schema,
1224 ProjectionMask::all(),
1225 Some(&utf8_instead_of_binary),
1226 )?
1227 .unwrap();
1228
1229 assert_eq!(
1231 converted_again.arrow_type,
1232 DataType::Struct(utf8_instead_of_binary)
1233 );
1234
1235 Ok(())
1236 }
1237
1238 #[test]
1239 fn convert_schema_with_repeated_primitive_should_use_inferred_schema_for_list_as_well()
1240 -> crate::errors::Result<()> {
1241 let message_type = "
1242 message schema {
1243 repeated BYTE_ARRAY col_1 = 1;
1244 }
1245 ";
1246
1247 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
1248 let schema = SchemaDescriptor::new(parsed_input_schema);
1249
1250 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
1251
1252 let DataType::Struct(schema_fields) = &converted.arrow_type else {
1253 panic!("Expected struct from convert_schema");
1254 };
1255
1256 assert_eq!(schema_fields.len(), 1);
1257
1258 let expected_schema = DataType::Struct(Fields::from(vec![Arc::new(
1259 arrow_schema::Field::new(
1260 "col_1",
1261 DataType::List(Arc::new(arrow_schema::Field::new(
1262 "col_1",
1263 DataType::Binary,
1264 false,
1265 ))),
1266 false,
1267 )
1268 .with_metadata(schema_fields[0].metadata().clone()),
1269 )]));
1270
1271 assert_eq!(converted.arrow_type, expected_schema);
1272
1273 let utf8_instead_of_binary = Fields::from(vec![Arc::new(
1274 arrow_schema::Field::new(
1275 "col_1",
1276 DataType::LargeList(Arc::new(arrow_schema::Field::new(
1278 "col_1",
1279 DataType::Utf8,
1280 false,
1281 ))),
1282 false,
1283 )
1284 .with_metadata(schema_fields[0].metadata().clone()),
1285 )]);
1286
1287 let converted_again = convert_schema(
1289 &schema,
1290 ProjectionMask::all(),
1291 Some(&utf8_instead_of_binary),
1292 )?
1293 .unwrap();
1294
1295 assert_eq!(
1297 converted_again.arrow_type,
1298 DataType::Struct(utf8_instead_of_binary)
1299 );
1300
1301 Ok(())
1302 }
1303
1304 #[test]
1305 fn convert_schema_with_repeated_struct_and_inferred_schema() -> crate::errors::Result<()> {
1306 test_roundtrip(
1307 "
1308 message schema {
1309 repeated group my_col_1 = 1 {
1310 optional binary my_col_2 = 2;
1311 optional binary my_col_3 = 3;
1312 optional group my_col_4 = 4 {
1313 optional int64 my_col_5 = 5;
1314 optional int32 my_col_6 = 6;
1315 }
1316 }
1317 }
1318 ",
1319 )
1320 }
1321
1322 #[test]
1323 fn convert_schema_with_repeated_struct_and_inferred_schema_and_field_id()
1324 -> crate::errors::Result<()> {
1325 let message_type = "
1326 message schema {
1327 repeated group my_col_1 = 1 {
1328 optional binary my_col_2 = 2;
1329 optional binary my_col_3 = 3;
1330 optional group my_col_4 = 4 {
1331 optional int64 my_col_5 = 5;
1332 optional int32 my_col_6 = 6;
1333 }
1334 }
1335 }
1336 ";
1337
1338 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
1339 let schema = SchemaDescriptor::new(parsed_input_schema);
1340
1341 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
1342
1343 let DataType::Struct(schema_fields) = &converted.arrow_type else {
1344 panic!("Expected struct from convert_schema");
1345 };
1346
1347 assert_eq!(schema_fields.len(), 1);
1348
1349 let converted_again =
1351 convert_schema(&schema, ProjectionMask::all(), Some(schema_fields))?.unwrap();
1352
1353 assert_eq!(converted_again.arrow_type, converted.arrow_type);
1355
1356 Ok(())
1357 }
1358
1359 #[test]
1360 fn convert_schema_with_nested_repeated_struct_and_primitives() -> crate::errors::Result<()> {
1361 let message_type = "
1362message schema {
1363 repeated group my_col_1 = 1 {
1364 optional binary my_col_2 = 2;
1365 repeated BYTE_ARRAY my_col_3 = 3;
1366 repeated group my_col_4 = 4 {
1367 optional int64 my_col_5 = 5;
1368 repeated binary my_col_6 = 6;
1369 }
1370 }
1371}
1372";
1373
1374 let parsed_input_schema = Arc::new(parse_message_type(message_type)?);
1375 let schema = SchemaDescriptor::new(parsed_input_schema);
1376
1377 let converted = convert_schema(&schema, ProjectionMask::all(), None)?.unwrap();
1378
1379 let DataType::Struct(schema_fields) = &converted.arrow_type else {
1380 panic!("Expected struct from convert_schema");
1381 };
1382
1383 assert_eq!(schema_fields.len(), 1);
1384
1385 let expected_schema = DataType::Struct(Fields::from(vec![Arc::new(
1387 arrow_schema::Field::new(
1388 "my_col_1",
1389 DataType::List(Arc::new(arrow_schema::Field::new(
1390 "my_col_1",
1391 DataType::Struct(Fields::from(vec![
1392 Arc::new(
1393 arrow_schema::Field::new("my_col_2", DataType::Binary, true)
1394 .with_field_id(2),
1395 ),
1396 Arc::new(
1397 arrow_schema::Field::new(
1398 "my_col_3",
1399 DataType::List(Arc::new(arrow_schema::Field::new(
1400 "my_col_3",
1401 DataType::Binary,
1402 false,
1403 ))),
1404 false,
1405 )
1406 .with_field_id(3),
1408 ),
1409 Arc::new(
1410 arrow_schema::Field::new(
1411 "my_col_4",
1412 DataType::List(Arc::new(arrow_schema::Field::new(
1413 "my_col_4",
1414 DataType::Struct(Fields::from(vec![
1415 Arc::new(
1416 arrow_schema::Field::new(
1417 "my_col_5",
1418 DataType::Int64,
1419 true,
1420 )
1421 .with_field_id(5),
1423 ),
1424 Arc::new(
1425 arrow_schema::Field::new(
1426 "my_col_6",
1427 DataType::List(Arc::new(arrow_schema::Field::new(
1428 "my_col_6",
1429 DataType::Binary,
1430 false,
1431 ))),
1432 false,
1433 )
1434 .with_field_id(6),
1436 ),
1437 ])),
1438 false,
1439 ))),
1440 false,
1441 )
1442 .with_field_id(4),
1444 ),
1445 ])),
1446 false,
1447 ))),
1448 false,
1449 )
1450 .with_field_id(1),
1452 )]));
1453
1454 assert_eq!(converted.arrow_type, expected_schema);
1455
1456 let converted_again =
1458 convert_schema(&schema, ProjectionMask::all(), Some(schema_fields))?.unwrap();
1459
1460 assert_eq!(converted_again.arrow_type, converted.arrow_type);
1461
1462 let modified_schema_fields = Fields::from(vec![Arc::new(
1465 arrow_schema::Field::new(
1466 "my_col_1",
1467 DataType::LargeList(Arc::new(arrow_schema::Field::new(
1468 "my_col_1",
1469 DataType::Struct(Fields::from(vec![
1470 Arc::new(
1471 arrow_schema::Field::new("my_col_2", DataType::LargeBinary, true)
1472 .with_field_id(2),
1473 ),
1474 Arc::new(
1475 arrow_schema::Field::new(
1476 "my_col_3",
1477 DataType::LargeList(Arc::new(arrow_schema::Field::new(
1478 "my_col_3",
1479 DataType::Utf8,
1480 false,
1481 ))),
1482 false,
1483 )
1484 .with_field_id(3),
1486 ),
1487 Arc::new(
1488 arrow_schema::Field::new(
1489 "my_col_4",
1490 DataType::FixedSizeList(
1491 Arc::new(arrow_schema::Field::new(
1492 "my_col_4",
1493 DataType::Struct(Fields::from(vec![
1494 Arc::new(
1495 arrow_schema::Field::new(
1496 "my_col_5",
1497 DataType::Int64,
1498 true,
1499 )
1500 .with_field_id(5),
1501 ),
1502 Arc::new(
1503 arrow_schema::Field::new(
1504 "my_col_6",
1505 DataType::LargeList(Arc::new(
1506 arrow_schema::Field::new(
1507 "my_col_6",
1508 DataType::BinaryView,
1509 false,
1510 ),
1511 )),
1512 false,
1513 )
1514 .with_field_id(6),
1516 ),
1517 ])),
1518 false,
1519 )),
1520 3,
1521 ),
1522 false,
1523 )
1524 .with_field_id(4),
1526 ),
1527 ])),
1528 false,
1529 ))),
1530 false,
1531 )
1532 .with_field_id(1),
1534 )]);
1535
1536 let converted_with_modified = convert_schema(
1537 &schema,
1538 ProjectionMask::all(),
1539 Some(&modified_schema_fields),
1540 )?
1541 .unwrap();
1542
1543 assert_eq!(
1544 converted_with_modified.arrow_type,
1545 DataType::Struct(modified_schema_fields)
1546 );
1547
1548 Ok(())
1549 }
1550
1551 #[test]
1554 fn list_nullable_element_standard() -> crate::errors::Result<()> {
1555 test_expected_type(
1556 "
1557 message root {
1558 optional group f1 (LIST) {
1559 repeated group list {
1560 optional int32 element;
1561 }
1562 }
1563 }",
1564 Fields::from(vec![Field::new(
1565 "f1",
1566 DataType::List(Arc::new(Field::new("element", DataType::Int32, true))),
1567 true,
1568 )]),
1569 )
1570 }
1571
1572 #[test]
1575 fn list_nullable_element_nested() -> crate::errors::Result<()> {
1576 test_expected_type(
1577 "
1578 message root {
1579 optional group f1 (LIST) {
1580 repeated group element {
1581 optional int32 num;
1582 }
1583 }
1584 }",
1585 Fields::from(vec![Field::new(
1586 "f1",
1587 DataType::List(Arc::new(Field::new("num", DataType::Int32, true))),
1588 true,
1589 )]),
1590 )
1591 }
1592
1593 #[test]
1596 fn list_required_element_standard() -> crate::errors::Result<()> {
1597 test_expected_type(
1598 "
1599 message root {
1600 optional group f1 (LIST) {
1601 repeated group list {
1602 required int32 element;
1603 }
1604 }
1605 }",
1606 Fields::from(vec![Field::new(
1607 "f1",
1608 DataType::List(Arc::new(Field::new("element", DataType::Int32, false))),
1609 true,
1610 )]),
1611 )
1612 }
1613
1614 #[test]
1617 fn list_required_element_nested() -> crate::errors::Result<()> {
1618 test_expected_type(
1619 "
1620 message root {
1621 optional group f1 (LIST) {
1622 repeated group element {
1623 required int32 num;
1624 }
1625 }
1626 }",
1627 Fields::from(vec![Field::new(
1628 "f1",
1629 DataType::List(Arc::new(Field::new("num", DataType::Int32, false))),
1630 true,
1631 )]),
1632 )
1633 }
1634
1635 #[test]
1638 fn list_required_element_primitive() -> crate::errors::Result<()> {
1639 test_expected_type(
1640 "
1641 message root {
1642 optional group f1 (LIST) {
1643 repeated int32 element;
1644 }
1645 }",
1646 Fields::from(vec![Field::new(
1647 "f1",
1648 DataType::List(Arc::new(Field::new("element", DataType::Int32, false))),
1649 true,
1650 )]),
1651 )
1652 }
1653
1654 #[test]
1657 fn list_required_element_struct() -> crate::errors::Result<()> {
1658 test_expected_type(
1659 "
1660 message root {
1661 optional group f1 (LIST) {
1662 repeated group element {
1663 required binary str (UTF8);
1664 required int32 num;
1665 }
1666 }
1667 }",
1668 Fields::from(vec![Field::new(
1669 "f1",
1670 DataType::List(Arc::new(Field::new(
1671 "element",
1672 DataType::Struct(Fields::from(vec![
1673 Field::new("str", DataType::Utf8, false),
1674 Field::new("num", DataType::Int32, false),
1675 ])),
1676 false,
1677 ))),
1678 true,
1679 )]),
1680 )
1681 }
1682
1683 #[test]
1686 fn list_required_element_avro_style() -> crate::errors::Result<()> {
1687 test_expected_type(
1688 "
1689 message root {
1690 optional group f1 (LIST) {
1691 repeated group array {
1692 required binary str (UTF8);
1693 }
1694 }
1695 }",
1696 Fields::from(vec![Field::new(
1697 "f1",
1698 DataType::List(Arc::new(Field::new(
1699 "array",
1700 DataType::Struct(Fields::from(vec![Field::new("str", DataType::Utf8, false)])),
1701 false,
1702 ))),
1703 true,
1704 )]),
1705 )
1706 }
1707
1708 #[test]
1711 fn list_required_element_thrift_style() -> crate::errors::Result<()> {
1712 test_expected_type(
1713 "
1714 message root {
1715 optional group f1 (LIST) {
1716 repeated group f1_tuple {
1717 required binary str (UTF8);
1718 }
1719 }
1720 }",
1721 Fields::from(vec![Field::new(
1722 "f1",
1723 DataType::List(Arc::new(Field::new(
1724 "f1_tuple",
1725 DataType::Struct(Fields::from(vec![Field::new("str", DataType::Utf8, false)])),
1726 false,
1727 ))),
1728 true,
1729 )]),
1730 )
1731 }
1732
1733 #[test]
1736 fn map_required_value_standard() -> crate::errors::Result<()> {
1737 test_expected_type(
1738 "
1739 message root {
1740 optional group f1 (MAP) {
1741 repeated group key_value {
1742 required int32 key;
1743 required binary value (UTF8);
1744 }
1745 }
1746 }",
1747 Fields::from(vec![Field::new_map(
1748 "f1",
1749 "key_value",
1750 Field::new("key", DataType::Int32, false),
1751 Field::new("value", DataType::Utf8, false),
1752 false,
1753 true,
1754 )]),
1755 )
1756 }
1757
1758 #[test]
1761 fn map_required_value_map_key_value() -> crate::errors::Result<()> {
1762 test_expected_type(
1763 "
1764 message root {
1765 optional group f1 (MAP_KEY_VALUE) {
1766 repeated group map {
1767 required int32 num;
1768 required binary str (UTF8);
1769 }
1770 }
1771 }",
1772 Fields::from(vec![Field::new_map(
1773 "f1",
1774 "map",
1775 Field::new("num", DataType::Int32, false),
1776 Field::new("str", DataType::Utf8, false),
1777 false,
1778 true,
1779 )]),
1780 )
1781 }
1782
1783 #[test]
1786 fn map_required_value_legacy() -> crate::errors::Result<()> {
1787 test_expected_type(
1788 "
1789 message root {
1790 optional group f1 (MAP) {
1791 repeated group map (MAP_KEY_VALUE) {
1792 required int32 key;
1793 required binary value (UTF8);
1794 }
1795 }
1796 }",
1797 Fields::from(vec![Field::new_map(
1798 "f1",
1799 "map",
1800 Field::new("key", DataType::Int32, false),
1801 Field::new("value", DataType::Utf8, false),
1802 false,
1803 true,
1804 )]),
1805 )
1806 }
1807
1808 #[test]
1811 fn map_optional_value_standard() -> crate::errors::Result<()> {
1812 test_expected_type(
1813 "
1814 message root {
1815 optional group f1 (MAP) {
1816 repeated group key_value {
1817 required int32 key;
1818 optional binary value (UTF8);
1819 }
1820 }
1821 }",
1822 Fields::from(vec![Field::new_map(
1823 "f1",
1824 "key_value",
1825 Field::new("key", DataType::Int32, false),
1826 Field::new("value", DataType::Utf8, true),
1827 false,
1828 true,
1829 )]),
1830 )
1831 }
1832
1833 #[test]
1836 fn map_optional_value_map_key_value() -> crate::errors::Result<()> {
1837 test_expected_type(
1838 "
1839 message root {
1840 optional group f1 (MAP_KEY_VALUE) {
1841 repeated group map {
1842 required int32 num;
1843 optional binary str (UTF8);
1844 }
1845 }
1846 }",
1847 Fields::from(vec![Field::new_map(
1848 "f1",
1849 "map",
1850 Field::new("num", DataType::Int32, false),
1851 Field::new("str", DataType::Utf8, true),
1852 false,
1853 true,
1854 )]),
1855 )
1856 }
1857
1858 #[test]
1861 fn map_optional_value_avro_style() -> crate::errors::Result<()> {
1862 test_expected_type(
1863 "
1864 message root {
1865 optional group f1 (MAP) {
1866 repeated group map (MAP_KEY_VALUE) {
1867 required int32 key;
1868 optional binary value (UTF8);
1869 }
1870 }
1871 }",
1872 Fields::from(vec![Field::new_map(
1873 "f1",
1874 "map",
1875 Field::new("key", DataType::Int32, false),
1876 Field::new("value", DataType::Utf8, true),
1877 false,
1878 true,
1879 )]),
1880 )
1881 }
1882}