1use std::{fmt, io};
47
48use crate::basic::{ConvertedType, LogicalType, TimeUnit, Type as PhysicalType};
49use crate::file::metadata::{ColumnChunkMetaData, FileMetaData, ParquetMetaData, RowGroupMetaData};
50use crate::schema::types::Type;
51
52#[allow(unused_must_use)]
54pub fn print_parquet_metadata(out: &mut dyn io::Write, metadata: &ParquetMetaData) {
55 print_file_metadata(out, metadata.file_metadata());
56 writeln!(out);
57 writeln!(out);
58 writeln!(out, "num of row groups: {}", metadata.num_row_groups());
59 writeln!(out, "row groups:");
60 writeln!(out);
61 for (i, rg) in metadata.row_groups().iter().enumerate() {
62 writeln!(out, "row group {i}:");
63 print_dashes(out, 80);
64 print_row_group_metadata(out, rg);
65 }
66}
67
68#[allow(unused_must_use)]
70pub fn print_file_metadata(out: &mut dyn io::Write, file_metadata: &FileMetaData) {
71 writeln!(out, "version: {}", file_metadata.version());
72 writeln!(out, "num of rows: {}", file_metadata.num_rows());
73 if let Some(created_by) = file_metadata.created_by().as_ref() {
74 writeln!(out, "created by: {created_by}");
75 }
76 if let Some(metadata) = file_metadata.key_value_metadata() {
77 writeln!(out, "metadata:");
78 for kv in metadata.iter() {
79 writeln!(
80 out,
81 " {}: {}",
82 &kv.key,
83 kv.value.as_ref().unwrap_or(&"".to_owned())
84 );
85 }
86 }
87 let schema = file_metadata.schema();
88 print_schema(out, schema);
89}
90
91#[allow(unused_must_use)]
93pub fn print_schema(out: &mut dyn io::Write, tp: &Type) {
94 let mut s = String::new();
97 {
98 let mut printer = Printer::new(&mut s);
99 printer.print(tp);
100 }
101 writeln!(out, "{s}");
102}
103
104#[allow(unused_must_use)]
105fn print_row_group_metadata(out: &mut dyn io::Write, rg_metadata: &RowGroupMetaData) {
106 writeln!(out, "total byte size: {}", rg_metadata.total_byte_size());
107 writeln!(out, "num of rows: {}", rg_metadata.num_rows());
108 writeln!(out);
109 writeln!(out, "num of columns: {}", rg_metadata.num_columns());
110 writeln!(out, "columns: ");
111 for (i, cc) in rg_metadata.columns().iter().enumerate() {
112 writeln!(out);
113 writeln!(out, "column {i}:");
114 print_dashes(out, 80);
115 print_column_chunk_metadata(out, cc);
116 }
117}
118
119#[allow(unused_must_use)]
120fn print_column_chunk_metadata(out: &mut dyn io::Write, cc_metadata: &ColumnChunkMetaData) {
121 writeln!(out, "column type: {}", cc_metadata.column_type());
122 writeln!(out, "column path: {}", cc_metadata.column_path());
123 let encoding_strs: Vec<_> = cc_metadata
124 .encodings()
125 .iter()
126 .map(|e| format!("{e}"))
127 .collect();
128 writeln!(out, "encodings: {}", encoding_strs.join(" "));
129 let file_path_str = cc_metadata.file_path().unwrap_or("N/A");
130 writeln!(out, "file path: {file_path_str}");
131 writeln!(out, "file offset: {}", cc_metadata.file_offset());
132 writeln!(out, "num of values: {}", cc_metadata.num_values());
133 writeln!(
134 out,
135 "compression: {}",
136 cc_metadata.compression().codec_to_string()
137 );
138 writeln!(
139 out,
140 "total compressed size (in bytes): {}",
141 cc_metadata.compressed_size()
142 );
143 writeln!(
144 out,
145 "total uncompressed size (in bytes): {}",
146 cc_metadata.uncompressed_size()
147 );
148 writeln!(out, "data page offset: {}", cc_metadata.data_page_offset());
149 let index_page_offset_str = match cc_metadata.index_page_offset() {
150 None => "N/A".to_owned(),
151 Some(ipo) => ipo.to_string(),
152 };
153 writeln!(out, "index page offset: {index_page_offset_str}");
154 let dict_page_offset_str = match cc_metadata.dictionary_page_offset() {
155 None => "N/A".to_owned(),
156 Some(dpo) => dpo.to_string(),
157 };
158 writeln!(out, "dictionary page offset: {dict_page_offset_str}");
159 let statistics_str = match cc_metadata.statistics() {
160 None => "N/A".to_owned(),
161 Some(stats) => stats.to_string(),
162 };
163 writeln!(out, "statistics: {statistics_str}");
164 let bloom_filter_offset_str = match cc_metadata.bloom_filter_offset() {
165 None => "N/A".to_owned(),
166 Some(bfo) => bfo.to_string(),
167 };
168 writeln!(out, "bloom filter offset: {bloom_filter_offset_str}");
169 let bloom_filter_length_str = match cc_metadata.bloom_filter_length() {
170 None => "N/A".to_owned(),
171 Some(bfo) => bfo.to_string(),
172 };
173 writeln!(out, "bloom filter length: {bloom_filter_length_str}");
174 let offset_index_offset_str = match cc_metadata.offset_index_offset() {
175 None => "N/A".to_owned(),
176 Some(oio) => oio.to_string(),
177 };
178 writeln!(out, "offset index offset: {offset_index_offset_str}");
179 let offset_index_length_str = match cc_metadata.offset_index_length() {
180 None => "N/A".to_owned(),
181 Some(oil) => oil.to_string(),
182 };
183 writeln!(out, "offset index length: {offset_index_length_str}");
184 let column_index_offset_str = match cc_metadata.column_index_offset() {
185 None => "N/A".to_owned(),
186 Some(cio) => cio.to_string(),
187 };
188 writeln!(out, "column index offset: {column_index_offset_str}");
189 let column_index_length_str = match cc_metadata.column_index_length() {
190 None => "N/A".to_owned(),
191 Some(cil) => cil.to_string(),
192 };
193 writeln!(out, "column index length: {column_index_length_str}");
194 writeln!(out);
195}
196
197#[allow(unused_must_use)]
198fn print_dashes(out: &mut dyn io::Write, num: i32) {
199 for _ in 0..num {
200 write!(out, "-");
201 }
202 writeln!(out);
203}
204
205const INDENT_WIDTH: i32 = 2;
206
207struct Printer<'a> {
209 output: &'a mut dyn fmt::Write,
210 indent: i32,
211}
212
213#[allow(unused_must_use)]
214impl<'a> Printer<'a> {
215 fn new(output: &'a mut dyn fmt::Write) -> Self {
216 Printer { output, indent: 0 }
217 }
218
219 fn print_indent(&mut self) {
220 for _ in 0..self.indent {
221 write!(self.output, " ");
222 }
223 }
224}
225
226#[inline]
227fn print_timeunit(unit: &TimeUnit) -> &str {
228 match unit {
229 TimeUnit::MILLIS(_) => "MILLIS",
230 TimeUnit::MICROS(_) => "MICROS",
231 TimeUnit::NANOS(_) => "NANOS",
232 }
233}
234
235#[inline]
236fn print_logical_and_converted(
237 logical_type: Option<&LogicalType>,
238 converted_type: ConvertedType,
239 precision: i32,
240 scale: i32,
241) -> String {
242 match logical_type {
243 Some(logical_type) => match logical_type {
244 LogicalType::Integer {
245 bit_width,
246 is_signed,
247 } => {
248 format!("INTEGER({bit_width},{is_signed})")
249 }
250 LogicalType::Decimal { scale, precision } => {
251 format!("DECIMAL({precision},{scale})")
252 }
253 LogicalType::Timestamp {
254 is_adjusted_to_u_t_c,
255 unit,
256 } => {
257 format!(
258 "TIMESTAMP({},{})",
259 print_timeunit(unit),
260 is_adjusted_to_u_t_c
261 )
262 }
263 LogicalType::Time {
264 is_adjusted_to_u_t_c,
265 unit,
266 } => {
267 format!("TIME({},{})", print_timeunit(unit), is_adjusted_to_u_t_c)
268 }
269 LogicalType::Date => "DATE".to_string(),
270 LogicalType::Bson => "BSON".to_string(),
271 LogicalType::Json => "JSON".to_string(),
272 LogicalType::String => "STRING".to_string(),
273 LogicalType::Uuid => "UUID".to_string(),
274 LogicalType::Enum => "ENUM".to_string(),
275 LogicalType::List => "LIST".to_string(),
276 LogicalType::Map => "MAP".to_string(),
277 LogicalType::Float16 => "FLOAT16".to_string(),
278 LogicalType::Unknown => "UNKNOWN".to_string(),
279 },
280 None => {
281 match converted_type {
283 ConvertedType::NONE => String::new(),
284 decimal @ ConvertedType::DECIMAL => {
285 let precision_scale = match (precision, scale) {
289 (p, s) if p > 0 && s > 0 => {
290 format!("({p},{s})")
291 }
292 (p, 0) if p > 0 => format!("({p})"),
293 _ => String::new(),
294 };
295 format!("{decimal}{precision_scale}")
296 }
297 other_converted_type => {
298 format!("{other_converted_type}")
299 }
300 }
301 }
302 }
303}
304
305#[allow(unused_must_use)]
306impl Printer<'_> {
307 pub fn print(&mut self, tp: &Type) {
308 self.print_indent();
309 match *tp {
310 Type::PrimitiveType {
311 ref basic_info,
312 physical_type,
313 type_length,
314 scale,
315 precision,
316 } => {
317 let phys_type_str = match physical_type {
318 PhysicalType::FIXED_LEN_BYTE_ARRAY => {
319 format!("{physical_type} ({type_length})")
321 }
322 _ => format!("{physical_type}"),
323 };
324 let logical_type_str = print_logical_and_converted(
327 basic_info.logical_type().as_ref(),
328 basic_info.converted_type(),
329 precision,
330 scale,
331 );
332 if logical_type_str.is_empty() {
333 write!(
334 self.output,
335 "{} {} {};",
336 basic_info.repetition(),
337 phys_type_str,
338 basic_info.name()
339 );
340 } else {
341 write!(
342 self.output,
343 "{} {} {} ({});",
344 basic_info.repetition(),
345 phys_type_str,
346 basic_info.name(),
347 logical_type_str
348 );
349 }
350 }
351 Type::GroupType {
352 ref basic_info,
353 ref fields,
354 } => {
355 if basic_info.has_repetition() {
356 let r = basic_info.repetition();
357 write!(self.output, "{} group {} ", r, basic_info.name());
358 let logical_str = print_logical_and_converted(
359 basic_info.logical_type().as_ref(),
360 basic_info.converted_type(),
361 0,
362 0,
363 );
364 if !logical_str.is_empty() {
365 write!(self.output, "({logical_str}) ");
366 }
367 writeln!(self.output, "{{");
368 } else {
369 writeln!(self.output, "message {} {{", basic_info.name());
370 }
371
372 self.indent += INDENT_WIDTH;
373 for c in fields {
374 self.print(c);
375 writeln!(self.output);
376 }
377 self.indent -= INDENT_WIDTH;
378 self.print_indent();
379 write!(self.output, "}}");
380 }
381 }
382 }
383}
384
385#[cfg(test)]
386mod tests {
387 use super::*;
388
389 use std::sync::Arc;
390
391 use crate::basic::{Repetition, Type as PhysicalType};
392 use crate::errors::Result;
393 use crate::schema::parser::parse_message_type;
394
395 fn assert_print_parse_message(message: Type) {
396 let mut s = String::new();
397 {
398 let mut p = Printer::new(&mut s);
399 p.print(&message);
400 }
401 println!("{}", &s);
402 let parsed = parse_message_type(&s).unwrap();
403 assert_eq!(message, parsed);
404 }
405
406 #[test]
407 fn test_print_primitive_type() {
408 let mut s = String::new();
409 {
410 let mut p = Printer::new(&mut s);
411 let field = Type::primitive_type_builder("field", PhysicalType::INT32)
412 .with_repetition(Repetition::REQUIRED)
413 .with_converted_type(ConvertedType::INT_32)
414 .build()
415 .unwrap();
416 p.print(&field);
417 }
418 assert_eq!(&mut s, "REQUIRED INT32 field (INT_32);");
419 }
420
421 #[inline]
422 fn build_primitive_type(
423 name: &str,
424 physical_type: PhysicalType,
425 logical_type: Option<LogicalType>,
426 converted_type: ConvertedType,
427 repetition: Repetition,
428 ) -> Result<Type> {
429 Type::primitive_type_builder(name, physical_type)
430 .with_repetition(repetition)
431 .with_logical_type(logical_type)
432 .with_converted_type(converted_type)
433 .build()
434 }
435
436 #[test]
437 fn test_print_logical_types() {
438 let types_and_strings = vec![
439 (
440 build_primitive_type(
441 "field",
442 PhysicalType::INT32,
443 Some(LogicalType::Integer {
444 bit_width: 32,
445 is_signed: true,
446 }),
447 ConvertedType::NONE,
448 Repetition::REQUIRED,
449 )
450 .unwrap(),
451 "REQUIRED INT32 field (INTEGER(32,true));",
452 ),
453 (
454 build_primitive_type(
455 "field",
456 PhysicalType::INT32,
457 Some(LogicalType::Integer {
458 bit_width: 8,
459 is_signed: false,
460 }),
461 ConvertedType::NONE,
462 Repetition::OPTIONAL,
463 )
464 .unwrap(),
465 "OPTIONAL INT32 field (INTEGER(8,false));",
466 ),
467 (
468 build_primitive_type(
469 "field",
470 PhysicalType::INT32,
471 Some(LogicalType::Integer {
472 bit_width: 16,
473 is_signed: true,
474 }),
475 ConvertedType::INT_16,
476 Repetition::REPEATED,
477 )
478 .unwrap(),
479 "REPEATED INT32 field (INTEGER(16,true));",
480 ),
481 (
482 build_primitive_type(
483 "field",
484 PhysicalType::INT64,
485 None,
486 ConvertedType::NONE,
487 Repetition::REPEATED,
488 )
489 .unwrap(),
490 "REPEATED INT64 field;",
491 ),
492 (
493 build_primitive_type(
494 "field",
495 PhysicalType::FLOAT,
496 None,
497 ConvertedType::NONE,
498 Repetition::REQUIRED,
499 )
500 .unwrap(),
501 "REQUIRED FLOAT field;",
502 ),
503 (
504 build_primitive_type(
505 "booleans",
506 PhysicalType::BOOLEAN,
507 None,
508 ConvertedType::NONE,
509 Repetition::OPTIONAL,
510 )
511 .unwrap(),
512 "OPTIONAL BOOLEAN booleans;",
513 ),
514 (
515 build_primitive_type(
516 "field",
517 PhysicalType::INT64,
518 Some(LogicalType::Timestamp {
519 is_adjusted_to_u_t_c: true,
520 unit: TimeUnit::MILLIS(Default::default()),
521 }),
522 ConvertedType::NONE,
523 Repetition::REQUIRED,
524 )
525 .unwrap(),
526 "REQUIRED INT64 field (TIMESTAMP(MILLIS,true));",
527 ),
528 (
529 build_primitive_type(
530 "field",
531 PhysicalType::INT32,
532 Some(LogicalType::Date),
533 ConvertedType::NONE,
534 Repetition::OPTIONAL,
535 )
536 .unwrap(),
537 "OPTIONAL INT32 field (DATE);",
538 ),
539 (
540 build_primitive_type(
541 "field",
542 PhysicalType::INT32,
543 Some(LogicalType::Time {
544 unit: TimeUnit::MILLIS(Default::default()),
545 is_adjusted_to_u_t_c: false,
546 }),
547 ConvertedType::TIME_MILLIS,
548 Repetition::REQUIRED,
549 )
550 .unwrap(),
551 "REQUIRED INT32 field (TIME(MILLIS,false));",
552 ),
553 (
554 build_primitive_type(
555 "field",
556 PhysicalType::BYTE_ARRAY,
557 None,
558 ConvertedType::NONE,
559 Repetition::REQUIRED,
560 )
561 .unwrap(),
562 "REQUIRED BYTE_ARRAY field;",
563 ),
564 (
565 build_primitive_type(
566 "field",
567 PhysicalType::BYTE_ARRAY,
568 None,
569 ConvertedType::UTF8,
570 Repetition::REQUIRED,
571 )
572 .unwrap(),
573 "REQUIRED BYTE_ARRAY field (UTF8);",
574 ),
575 (
576 build_primitive_type(
577 "field",
578 PhysicalType::BYTE_ARRAY,
579 Some(LogicalType::Json),
580 ConvertedType::JSON,
581 Repetition::REQUIRED,
582 )
583 .unwrap(),
584 "REQUIRED BYTE_ARRAY field (JSON);",
585 ),
586 (
587 build_primitive_type(
588 "field",
589 PhysicalType::BYTE_ARRAY,
590 Some(LogicalType::Bson),
591 ConvertedType::BSON,
592 Repetition::REQUIRED,
593 )
594 .unwrap(),
595 "REQUIRED BYTE_ARRAY field (BSON);",
596 ),
597 (
598 build_primitive_type(
599 "field",
600 PhysicalType::BYTE_ARRAY,
601 Some(LogicalType::String),
602 ConvertedType::NONE,
603 Repetition::REQUIRED,
604 )
605 .unwrap(),
606 "REQUIRED BYTE_ARRAY field (STRING);",
607 ),
608 ];
609
610 types_and_strings.into_iter().for_each(|(field, expected)| {
611 let mut s = String::new();
612 {
613 let mut p = Printer::new(&mut s);
614 p.print(&field);
615 }
616 assert_eq!(&s, expected)
617 });
618 }
619
620 #[inline]
621 fn decimal_length_from_precision(precision: usize) -> i32 {
622 let max_val = 10.0_f64.powi(precision as i32) - 1.0;
623 let bits_unsigned = max_val.log2().ceil();
624 let bits_signed = bits_unsigned + 1.0;
625 (bits_signed / 8.0).ceil() as i32
626 }
627
628 #[test]
629 fn test_print_flba_logical_types() {
630 let types_and_strings = vec![
631 (
632 Type::primitive_type_builder("field", PhysicalType::FIXED_LEN_BYTE_ARRAY)
633 .with_logical_type(None)
634 .with_converted_type(ConvertedType::INTERVAL)
635 .with_length(12)
636 .with_repetition(Repetition::REQUIRED)
637 .build()
638 .unwrap(),
639 "REQUIRED FIXED_LEN_BYTE_ARRAY (12) field (INTERVAL);",
640 ),
641 (
642 Type::primitive_type_builder("field", PhysicalType::FIXED_LEN_BYTE_ARRAY)
643 .with_logical_type(Some(LogicalType::Uuid))
644 .with_length(16)
645 .with_repetition(Repetition::REQUIRED)
646 .build()
647 .unwrap(),
648 "REQUIRED FIXED_LEN_BYTE_ARRAY (16) field (UUID);",
649 ),
650 (
651 Type::primitive_type_builder("decimal", PhysicalType::FIXED_LEN_BYTE_ARRAY)
652 .with_logical_type(Some(LogicalType::Decimal {
653 precision: 32,
654 scale: 20,
655 }))
656 .with_precision(32)
657 .with_scale(20)
658 .with_length(decimal_length_from_precision(32))
659 .with_repetition(Repetition::REPEATED)
660 .build()
661 .unwrap(),
662 "REPEATED FIXED_LEN_BYTE_ARRAY (14) decimal (DECIMAL(32,20));",
663 ),
664 (
665 Type::primitive_type_builder("decimal", PhysicalType::FIXED_LEN_BYTE_ARRAY)
666 .with_converted_type(ConvertedType::DECIMAL)
667 .with_precision(19)
668 .with_scale(4)
669 .with_length(decimal_length_from_precision(19))
670 .with_repetition(Repetition::OPTIONAL)
671 .build()
672 .unwrap(),
673 "OPTIONAL FIXED_LEN_BYTE_ARRAY (9) decimal (DECIMAL(19,4));",
674 ),
675 (
676 Type::primitive_type_builder("float16", PhysicalType::FIXED_LEN_BYTE_ARRAY)
677 .with_logical_type(Some(LogicalType::Float16))
678 .with_length(2)
679 .with_repetition(Repetition::REQUIRED)
680 .build()
681 .unwrap(),
682 "REQUIRED FIXED_LEN_BYTE_ARRAY (2) float16 (FLOAT16);",
683 ),
684 ];
685
686 types_and_strings.into_iter().for_each(|(field, expected)| {
687 let mut s = String::new();
688 {
689 let mut p = Printer::new(&mut s);
690 p.print(&field);
691 }
692 assert_eq!(&s, expected)
693 });
694 }
695
696 #[test]
697 fn test_print_group_type() {
698 let mut s = String::new();
699 {
700 let mut p = Printer::new(&mut s);
701 let f1 = Type::primitive_type_builder("f1", PhysicalType::INT32)
702 .with_repetition(Repetition::REQUIRED)
703 .with_converted_type(ConvertedType::INT_32)
704 .with_id(Some(0))
705 .build();
706 let f2 = Type::primitive_type_builder("f2", PhysicalType::BYTE_ARRAY)
707 .with_converted_type(ConvertedType::UTF8)
708 .with_id(Some(1))
709 .build();
710 let f3 = Type::primitive_type_builder("f3", PhysicalType::BYTE_ARRAY)
711 .with_logical_type(Some(LogicalType::String))
712 .with_id(Some(1))
713 .build();
714 let f4 = Type::primitive_type_builder("f4", PhysicalType::FIXED_LEN_BYTE_ARRAY)
715 .with_repetition(Repetition::REPEATED)
716 .with_converted_type(ConvertedType::INTERVAL)
717 .with_length(12)
718 .with_id(Some(2))
719 .build();
720
721 let struct_fields = vec![
722 Arc::new(f1.unwrap()),
723 Arc::new(f2.unwrap()),
724 Arc::new(f3.unwrap()),
725 ];
726 let field = Type::group_type_builder("field")
727 .with_repetition(Repetition::OPTIONAL)
728 .with_fields(struct_fields)
729 .with_id(Some(1))
730 .build()
731 .unwrap();
732
733 let fields = vec![Arc::new(field), Arc::new(f4.unwrap())];
734 let message = Type::group_type_builder("schema")
735 .with_fields(fields)
736 .with_id(Some(2))
737 .build()
738 .unwrap();
739 p.print(&message);
740 }
741 let expected = "message schema {
742 OPTIONAL group field {
743 REQUIRED INT32 f1 (INT_32);
744 OPTIONAL BYTE_ARRAY f2 (UTF8);
745 OPTIONAL BYTE_ARRAY f3 (STRING);
746 }
747 REPEATED FIXED_LEN_BYTE_ARRAY (12) f4 (INTERVAL);
748}";
749 assert_eq!(&mut s, expected);
750 }
751
752 #[test]
753 fn test_print_and_parse_primitive() {
754 let a2 = Type::primitive_type_builder("a2", PhysicalType::BYTE_ARRAY)
755 .with_repetition(Repetition::REPEATED)
756 .with_converted_type(ConvertedType::UTF8)
757 .build()
758 .unwrap();
759
760 let a1 = Type::group_type_builder("a1")
761 .with_repetition(Repetition::OPTIONAL)
762 .with_logical_type(Some(LogicalType::List))
763 .with_converted_type(ConvertedType::LIST)
764 .with_fields(vec![Arc::new(a2)])
765 .build()
766 .unwrap();
767
768 let b3 = Type::primitive_type_builder("b3", PhysicalType::INT32)
769 .with_repetition(Repetition::OPTIONAL)
770 .build()
771 .unwrap();
772
773 let b4 = Type::primitive_type_builder("b4", PhysicalType::DOUBLE)
774 .with_repetition(Repetition::OPTIONAL)
775 .build()
776 .unwrap();
777
778 let b2 = Type::group_type_builder("b2")
779 .with_repetition(Repetition::REPEATED)
780 .with_converted_type(ConvertedType::NONE)
781 .with_fields(vec![Arc::new(b3), Arc::new(b4)])
782 .build()
783 .unwrap();
784
785 let b1 = Type::group_type_builder("b1")
786 .with_repetition(Repetition::OPTIONAL)
787 .with_logical_type(Some(LogicalType::List))
788 .with_converted_type(ConvertedType::LIST)
789 .with_fields(vec![Arc::new(b2)])
790 .build()
791 .unwrap();
792
793 let a0 = Type::group_type_builder("a0")
794 .with_repetition(Repetition::REQUIRED)
795 .with_fields(vec![Arc::new(a1), Arc::new(b1)])
796 .build()
797 .unwrap();
798
799 let message = Type::group_type_builder("root")
800 .with_fields(vec![Arc::new(a0)])
801 .build()
802 .unwrap();
803
804 assert_print_parse_message(message);
805 }
806
807 #[test]
808 fn test_print_and_parse_nested() {
809 let f1 = Type::primitive_type_builder("f1", PhysicalType::INT32)
810 .with_repetition(Repetition::REQUIRED)
811 .with_converted_type(ConvertedType::INT_32)
812 .build()
813 .unwrap();
814
815 let f2 = Type::primitive_type_builder("f2", PhysicalType::BYTE_ARRAY)
816 .with_repetition(Repetition::OPTIONAL)
817 .with_converted_type(ConvertedType::UTF8)
818 .build()
819 .unwrap();
820
821 let field = Type::group_type_builder("field")
822 .with_repetition(Repetition::OPTIONAL)
823 .with_fields(vec![Arc::new(f1), Arc::new(f2)])
824 .build()
825 .unwrap();
826
827 let f3 = Type::primitive_type_builder("f3", PhysicalType::FIXED_LEN_BYTE_ARRAY)
828 .with_repetition(Repetition::REPEATED)
829 .with_converted_type(ConvertedType::INTERVAL)
830 .with_length(12)
831 .build()
832 .unwrap();
833
834 let message = Type::group_type_builder("schema")
835 .with_fields(vec![Arc::new(field), Arc::new(f3)])
836 .build()
837 .unwrap();
838
839 assert_print_parse_message(message);
840 }
841
842 #[test]
843 fn test_print_and_parse_decimal() {
844 let f1 = Type::primitive_type_builder("f1", PhysicalType::INT32)
845 .with_repetition(Repetition::OPTIONAL)
846 .with_logical_type(Some(LogicalType::Decimal {
847 precision: 9,
848 scale: 2,
849 }))
850 .with_converted_type(ConvertedType::DECIMAL)
851 .with_precision(9)
852 .with_scale(2)
853 .build()
854 .unwrap();
855
856 let f2 = Type::primitive_type_builder("f2", PhysicalType::INT32)
857 .with_repetition(Repetition::OPTIONAL)
858 .with_logical_type(Some(LogicalType::Decimal {
859 precision: 9,
860 scale: 0,
861 }))
862 .with_converted_type(ConvertedType::DECIMAL)
863 .with_precision(9)
864 .with_scale(0)
865 .build()
866 .unwrap();
867
868 let message = Type::group_type_builder("schema")
869 .with_fields(vec![Arc::new(f1), Arc::new(f2)])
870 .build()
871 .unwrap();
872
873 assert_print_parse_message(message);
874 }
875}