1use std::collections::BTreeMap;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9
10use spark_connect_core::error::{Result, SparkError};
11
12#[derive(Debug, Clone, PartialEq)]
18pub enum DataType {
19 Null,
21 Boolean,
23 Byte,
25 Short,
27 Integer,
29 Long,
31 Float,
33 Double,
35 Decimal { precision: i32, scale: i32 },
37 String { collation: String },
39 Char { length: i32 },
41 Varchar { length: i32 },
43 Binary,
45 Date,
47 Timestamp,
49 TimestampNtz,
51 Time { precision: i32 },
53 CalendarInterval,
55 YearMonthInterval { start_field: i32, end_field: i32 },
57 DayTimeInterval { start_field: i32, end_field: i32 },
59 Array {
61 element_type: Box<DataType>,
62 contains_null: bool,
63 },
64 Map {
66 key_type: Box<DataType>,
67 value_type: Box<DataType>,
68 value_contains_null: bool,
69 },
70 Struct { fields: Vec<StructField> },
72 Variant,
74 Geometry { srid: i32 },
76 Geography { srid: i32 },
78 Udt {
80 type_str: String,
81 jvm_class: Option<String>,
82 python_class: Option<String>,
83 serialized_python_class: Option<String>,
84 sql_type: Option<Box<DataType>>,
85 },
86 Unparsed { data_type_string: String },
89}
90
91#[derive(Debug, Clone, PartialEq)]
95pub struct StructField {
96 pub name: String,
97 pub data_type: DataType,
98 pub nullable: bool,
99 pub metadata: BTreeMap<String, serde_json::Value>,
100}
101
102impl DataType {
103 pub fn from_ddl(ddl_str: &str) -> Result<DataType> {
120 parse_datatype_string(ddl_str)
121 }
122
123 pub fn need_conversion(&self) -> bool {
138 match self {
139 DataType::Date
140 | DataType::Timestamp
141 | DataType::TimestampNtz
142 | DataType::Time { .. }
143 | DataType::DayTimeInterval { .. }
144 | DataType::YearMonthInterval { .. }
145 | DataType::CalendarInterval => true,
146 DataType::Array { element_type, .. } => element_type.need_conversion(),
147 DataType::Map {
148 key_type,
149 value_type,
150 ..
151 } => key_type.need_conversion() || value_type.need_conversion(),
152 DataType::Struct { .. } => true,
153 _ => false,
154 }
155 }
156
157 pub fn type_name(&self) -> String {
162 match self {
163 DataType::Null => "void".to_string(),
164 DataType::Boolean => "boolean".to_string(),
165 DataType::Byte => "byte".to_string(),
166 DataType::Short => "short".to_string(),
167 DataType::Integer => "integer".to_string(),
168 DataType::Long => "long".to_string(),
169 DataType::Float => "float".to_string(),
170 DataType::Double => "double".to_string(),
171 DataType::Decimal { .. } => "decimal".to_string(),
172 DataType::String { .. } => "string".to_string(),
173 DataType::Char { .. } => "char".to_string(),
174 DataType::Varchar { .. } => "varchar".to_string(),
175 DataType::Binary => "binary".to_string(),
176 DataType::Date => "date".to_string(),
177 DataType::Timestamp => "timestamp".to_string(),
178 DataType::TimestampNtz => "timestamp_ntz".to_string(),
179 DataType::Time { .. } => "time".to_string(),
180 DataType::CalendarInterval => "interval".to_string(),
181 DataType::YearMonthInterval { .. } => "interval".to_string(),
182 DataType::DayTimeInterval { .. } => "interval".to_string(),
183 DataType::Array { .. } => "array".to_string(),
184 DataType::Map { .. } => "map".to_string(),
185 DataType::Struct { .. } => "struct".to_string(),
186 DataType::Variant => "variant".to_string(),
187 DataType::Geometry { .. } => "geometry".to_string(),
188 DataType::Geography { .. } => "geography".to_string(),
189 DataType::Udt { .. } => "udt".to_string(),
190 DataType::Unparsed { .. } => "unparsed".to_string(),
191 }
192 }
193
194 pub fn simple_string(&self) -> String {
202 match self {
203 DataType::Null => "void".to_string(),
204 DataType::Boolean => "boolean".to_string(),
205 DataType::Byte => "tinyint".to_string(),
206 DataType::Short => "smallint".to_string(),
207 DataType::Integer => "int".to_string(),
208 DataType::Long => "bigint".to_string(),
209 DataType::Float => "float".to_string(),
210 DataType::Double => "double".to_string(),
211 DataType::Decimal { precision, scale } => {
212 format!("decimal({},{})", precision, scale)
213 }
214 DataType::String { collation } => {
215 if collation.is_empty() || collation == "UTF8_BINARY" {
219 "string".to_string()
220 } else {
221 format!("string collate {}", collation)
222 }
223 }
224 DataType::Char { length } => format!("char({})", length),
225 DataType::Varchar { length } => format!("varchar({})", length),
226 DataType::Binary => "binary".to_string(),
227 DataType::Date => "date".to_string(),
228 DataType::Timestamp => "timestamp".to_string(),
229 DataType::TimestampNtz => "timestamp_ntz".to_string(),
230 DataType::Time { precision } => format!("time({})", precision),
231 DataType::CalendarInterval => "interval".to_string(),
232 DataType::YearMonthInterval {
233 start_field,
234 end_field,
235 } => interval_string(*start_field, *end_field, YEAR_MONTH_FIELDS),
236 DataType::DayTimeInterval {
237 start_field,
238 end_field,
239 } => interval_string(*start_field, *end_field, DAY_TIME_FIELDS),
240 DataType::Array {
241 element_type,
242 contains_null: _,
243 } => {
244 format!("array<{}>", element_type.simple_string())
245 }
246 DataType::Map {
247 key_type,
248 value_type,
249 value_contains_null: _,
250 } => {
251 format!(
252 "map<{},{}>",
253 key_type.simple_string(),
254 value_type.simple_string()
255 )
256 }
257 DataType::Struct { fields } => {
258 let field_strs: Vec<String> = fields.iter().map(|f| f.simple_string()).collect();
259 format!("struct<{}>", field_strs.join(","))
260 }
261 DataType::Variant => "variant".to_string(),
262 DataType::Geometry { srid } => {
263 if *srid == -1 {
264 "geometry(any)".to_string()
265 } else {
266 format!("geometry({})", srid)
267 }
268 }
269 DataType::Geography { srid } => {
270 if *srid == -1 {
271 "geography(any)".to_string()
272 } else {
273 format!("geography({})", srid)
274 }
275 }
276 DataType::Udt { .. } => "udt".to_string(),
277 DataType::Unparsed { data_type_string } => {
278 format!("unparsed({})", data_type_string)
280 }
281 }
282 }
283
284 pub fn json_value(&self) -> serde_json::Value {
289 match self {
290 DataType::Null => serde_json::json!("void"),
291 DataType::Boolean => serde_json::json!("boolean"),
292 DataType::Byte => serde_json::json!("byte"),
293 DataType::Short => serde_json::json!("short"),
294 DataType::Integer => serde_json::json!("integer"),
295 DataType::Long => serde_json::json!("long"),
296 DataType::Float => serde_json::json!("float"),
297 DataType::Double => serde_json::json!("double"),
298 DataType::Decimal { precision, scale } => {
299 serde_json::json!(format!("decimal({},{})", precision, scale))
300 }
301 DataType::String { collation } => {
302 if collation == "UTF8_BINARY" {
303 serde_json::json!("string")
304 } else {
305 serde_json::json!(format!("string collate {}", collation))
306 }
307 }
308 DataType::Char { length } => {
309 serde_json::json!(format!("char({})", length))
310 }
311 DataType::Varchar { length } => {
312 serde_json::json!(format!("varchar({})", length))
313 }
314 DataType::Binary => serde_json::json!("binary"),
315 DataType::Date => serde_json::json!("date"),
316 DataType::Timestamp => serde_json::json!("timestamp"),
317 DataType::TimestampNtz => serde_json::json!("timestamp_ntz"),
318 DataType::Time { precision } => {
319 serde_json::json!(format!("time({})", precision))
320 }
321 DataType::CalendarInterval => serde_json::json!("interval"),
322 DataType::YearMonthInterval {
323 start_field,
324 end_field,
325 } => {
326 serde_json::json!(interval_string(*start_field, *end_field, YEAR_MONTH_FIELDS))
327 }
328 DataType::DayTimeInterval {
329 start_field,
330 end_field,
331 } => {
332 serde_json::json!(interval_string(*start_field, *end_field, DAY_TIME_FIELDS))
333 }
334 DataType::Array {
335 element_type,
336 contains_null,
337 } => {
338 serde_json::json!({
339 "type": "array",
340 "elementType": element_type.json_value(),
341 "containsNull": contains_null,
342 })
343 }
344 DataType::Map {
345 key_type,
346 value_type,
347 value_contains_null,
348 } => {
349 serde_json::json!({
350 "type": "map",
351 "keyType": key_type.json_value(),
352 "valueType": value_type.json_value(),
353 "valueContainsNull": value_contains_null,
354 })
355 }
356 DataType::Struct { fields } => {
357 let field_values: Vec<serde_json::Value> =
358 fields.iter().map(|f| f.json_value()).collect();
359 serde_json::json!({
360 "type": "struct",
361 "fields": field_values,
362 })
363 }
364 DataType::Variant => serde_json::json!("variant"),
365 DataType::Geometry { srid } => {
366 if *srid == -1 {
367 serde_json::json!("geometry(SRID:ANY)")
368 } else {
369 serde_json::json!(format!("geometry(OGC:CRS84)"))
370 }
371 }
372 DataType::Geography { srid } => {
373 if *srid == -1 {
374 serde_json::json!("geography(SRID:ANY, SPHERICAL)")
375 } else {
376 serde_json::json!(format!("geography(OGC:CRS84, SPHERICAL)"))
377 }
378 }
379 DataType::Udt {
380 type_str: _,
381 jvm_class,
382 python_class,
383 serialized_python_class,
384 sql_type,
385 } => {
386 let mut obj = serde_json::Map::new();
387 obj.insert("type".to_string(), serde_json::json!("udt"));
388 if let Some(jvm_cls) = jvm_class {
389 obj.insert("class".to_string(), serde_json::json!(jvm_cls));
390 }
391 if let Some(py_cls) = python_class {
392 obj.insert("pyClass".to_string(), serde_json::json!(py_cls));
393 }
394 if let Some(serialized) = serialized_python_class {
395 obj.insert("serializedClass".to_string(), serde_json::json!(serialized));
396 }
397 if let Some(sql_ty) = sql_type {
398 obj.insert("sqlType".to_string(), sql_ty.json_value());
399 }
400 serde_json::Value::Object(obj)
401 }
402 DataType::Unparsed { data_type_string } => {
403 serde_json::json!(format!("unparsed({})", data_type_string))
404 }
405 }
406 }
407
408 pub fn json(&self) -> String {
410 self.json_value().to_string()
411 }
412
413 pub fn from_json(value: &serde_json::Value) -> Result<DataType> {
415 parse_json_value(value, None)
416 }
417
418 pub fn from_json_str(s: &str) -> Result<DataType> {
420 let value: serde_json::Value = serde_json::from_str(s)
421 .map_err(|e| SparkError::value("INVALID_JSON", &[("detail", &e.to_string())]))?;
422 DataType::from_json(&value)
423 }
424
425 pub fn to_proto(&self) -> spark_connect_proto::DataType {
428 let mut proto = spark_connect_proto::DataType::default();
429
430 match self {
431 DataType::Null => {
432 proto.kind = Some(spark_connect_proto::data_type::Kind::Null(
433 spark_connect_proto::data_type::Null::default(),
434 ));
435 }
436 DataType::Boolean => {
437 proto.kind = Some(spark_connect_proto::data_type::Kind::Boolean(
438 spark_connect_proto::data_type::Boolean::default(),
439 ));
440 }
441 DataType::Byte => {
442 proto.kind = Some(spark_connect_proto::data_type::Kind::Byte(
443 spark_connect_proto::data_type::Byte::default(),
444 ));
445 }
446 DataType::Short => {
447 proto.kind = Some(spark_connect_proto::data_type::Kind::Short(
448 spark_connect_proto::data_type::Short::default(),
449 ));
450 }
451 DataType::Integer => {
452 proto.kind = Some(spark_connect_proto::data_type::Kind::Integer(
453 spark_connect_proto::data_type::Integer::default(),
454 ));
455 }
456 DataType::Long => {
457 proto.kind = Some(spark_connect_proto::data_type::Kind::Long(
458 spark_connect_proto::data_type::Long::default(),
459 ));
460 }
461 DataType::Float => {
462 proto.kind = Some(spark_connect_proto::data_type::Kind::Float(
463 spark_connect_proto::data_type::Float::default(),
464 ));
465 }
466 DataType::Double => {
467 proto.kind = Some(spark_connect_proto::data_type::Kind::Double(
468 spark_connect_proto::data_type::Double::default(),
469 ));
470 }
471 DataType::Decimal { precision, scale } => {
472 let mut decimal = spark_connect_proto::data_type::Decimal::default();
473 decimal.precision = Some(*precision);
474 decimal.scale = Some(*scale);
475 proto.kind = Some(spark_connect_proto::data_type::Kind::Decimal(decimal));
476 }
477 DataType::String { collation } => {
478 let mut string = spark_connect_proto::data_type::String::default();
479 string.collation = collation.clone();
480 proto.kind = Some(spark_connect_proto::data_type::Kind::String(string));
481 }
482 DataType::Char { length } => {
483 let mut char_type = spark_connect_proto::data_type::Char::default();
484 char_type.length = *length;
485 proto.kind = Some(spark_connect_proto::data_type::Kind::Char(char_type));
486 }
487 DataType::Varchar { length } => {
488 let mut varchar_type = spark_connect_proto::data_type::VarChar::default();
489 varchar_type.length = *length;
490 proto.kind = Some(spark_connect_proto::data_type::Kind::VarChar(varchar_type));
491 }
492 DataType::Binary => {
493 proto.kind = Some(spark_connect_proto::data_type::Kind::Binary(
494 spark_connect_proto::data_type::Binary::default(),
495 ));
496 }
497 DataType::Date => {
498 proto.kind = Some(spark_connect_proto::data_type::Kind::Date(
499 spark_connect_proto::data_type::Date::default(),
500 ));
501 }
502 DataType::Timestamp => {
503 proto.kind = Some(spark_connect_proto::data_type::Kind::Timestamp(
504 spark_connect_proto::data_type::Timestamp::default(),
505 ));
506 }
507 DataType::TimestampNtz => {
508 proto.kind = Some(spark_connect_proto::data_type::Kind::TimestampNtz(
509 spark_connect_proto::data_type::TimestampNtz::default(),
510 ));
511 }
512 DataType::Time { precision } => {
513 let mut time_type = spark_connect_proto::data_type::Time::default();
514 time_type.precision = Some(*precision);
515 proto.kind = Some(spark_connect_proto::data_type::Kind::Time(time_type));
516 }
517 DataType::CalendarInterval => {
518 proto.kind = Some(spark_connect_proto::data_type::Kind::CalendarInterval(
519 spark_connect_proto::data_type::CalendarInterval::default(),
520 ));
521 }
522 DataType::YearMonthInterval {
523 start_field,
524 end_field,
525 } => {
526 let mut ymi = spark_connect_proto::data_type::YearMonthInterval::default();
527 ymi.start_field = Some(*start_field);
528 ymi.end_field = Some(*end_field);
529 proto.kind = Some(spark_connect_proto::data_type::Kind::YearMonthInterval(ymi));
530 }
531 DataType::DayTimeInterval {
532 start_field,
533 end_field,
534 } => {
535 let mut dti = spark_connect_proto::data_type::DayTimeInterval::default();
536 dti.start_field = Some(*start_field);
537 dti.end_field = Some(*end_field);
538 proto.kind = Some(spark_connect_proto::data_type::Kind::DayTimeInterval(dti));
539 }
540 DataType::Array {
541 element_type,
542 contains_null,
543 } => {
544 let mut array = spark_connect_proto::data_type::Array::default();
545 array.element_type = Some(Box::new(element_type.to_proto()));
546 array.contains_null = *contains_null;
547 proto.kind = Some(spark_connect_proto::data_type::Kind::Array(Box::new(array)));
548 }
549 DataType::Map {
550 key_type,
551 value_type,
552 value_contains_null,
553 } => {
554 let mut map = spark_connect_proto::data_type::Map::default();
555 map.key_type = Some(Box::new(key_type.to_proto()));
556 map.value_type = Some(Box::new(value_type.to_proto()));
557 map.value_contains_null = *value_contains_null;
558 proto.kind = Some(spark_connect_proto::data_type::Kind::Map(Box::new(map)));
559 }
560 DataType::Struct { fields } => {
561 let mut struct_type = spark_connect_proto::data_type::Struct::default();
562 for field in fields {
563 let mut proto_field = spark_connect_proto::data_type::StructField::default();
564 proto_field.name = field.name.clone();
565 proto_field.data_type = Some(field.data_type.to_proto());
566 proto_field.nullable = field.nullable;
567 if !field.metadata.is_empty() {
568 proto_field.metadata =
569 Some(serde_json::to_string(&field.metadata).unwrap_or_default());
570 }
571 struct_type.fields.push(proto_field);
572 }
573 proto.kind = Some(spark_connect_proto::data_type::Kind::Struct(struct_type));
574 }
575 DataType::Variant => {
576 proto.kind = Some(spark_connect_proto::data_type::Kind::Variant(
577 spark_connect_proto::data_type::Variant::default(),
578 ));
579 }
580 DataType::Geometry { srid } => {
581 let mut geometry = spark_connect_proto::data_type::Geometry::default();
582 geometry.srid = *srid;
583 proto.kind = Some(spark_connect_proto::data_type::Kind::Geometry(geometry));
584 }
585 DataType::Geography { srid } => {
586 let mut geography = spark_connect_proto::data_type::Geography::default();
587 geography.srid = *srid;
588 proto.kind = Some(spark_connect_proto::data_type::Kind::Geography(geography));
589 }
590 DataType::Udt {
591 type_str: _,
592 jvm_class,
593 python_class,
594 serialized_python_class,
595 sql_type,
596 } => {
597 let mut udt = spark_connect_proto::data_type::Udt::default();
598 udt.r#type = "udt".to_string();
599 if let Some(jvm_cls) = jvm_class {
600 udt.jvm_class = Some(jvm_cls.clone());
601 }
602 if let Some(py_cls) = python_class {
603 udt.python_class = Some(py_cls.clone());
604 }
605 if let Some(serialized) = serialized_python_class {
606 udt.serialized_python_class = Some(serialized.clone());
607 }
608 if let Some(sql_ty) = sql_type {
609 udt.sql_type = Some(Box::new(sql_ty.to_proto()));
610 }
611 proto.kind = Some(spark_connect_proto::data_type::Kind::Udt(Box::new(udt)));
612 }
613 DataType::Unparsed { data_type_string } => {
614 let mut unparsed = spark_connect_proto::data_type::Unparsed::default();
615 unparsed.data_type_string = data_type_string.clone();
616 proto.kind = Some(spark_connect_proto::data_type::Kind::Unparsed(unparsed));
617 }
618 }
619
620 proto
621 }
622
623 pub fn from_proto(proto: &spark_connect_proto::DataType) -> Result<DataType> {
626 match &proto.kind {
627 Some(spark_connect_proto::data_type::Kind::Null(_)) => Ok(DataType::Null),
628 Some(spark_connect_proto::data_type::Kind::Boolean(_)) => Ok(DataType::Boolean),
629 Some(spark_connect_proto::data_type::Kind::Byte(_)) => Ok(DataType::Byte),
630 Some(spark_connect_proto::data_type::Kind::Short(_)) => Ok(DataType::Short),
631 Some(spark_connect_proto::data_type::Kind::Integer(_)) => Ok(DataType::Integer),
632 Some(spark_connect_proto::data_type::Kind::Long(_)) => Ok(DataType::Long),
633 Some(spark_connect_proto::data_type::Kind::Float(_)) => Ok(DataType::Float),
634 Some(spark_connect_proto::data_type::Kind::Double(_)) => Ok(DataType::Double),
635 Some(spark_connect_proto::data_type::Kind::Decimal(d)) => {
636 let precision = d.precision.unwrap_or(10);
637 let scale = d.scale.unwrap_or(0);
638 Ok(DataType::Decimal { precision, scale })
639 }
640 Some(spark_connect_proto::data_type::Kind::String(s)) => {
641 let collation = if s.collation.is_empty() {
642 "UTF8_BINARY".to_string()
643 } else {
644 s.collation.clone()
645 };
646 Ok(DataType::String { collation })
647 }
648 Some(spark_connect_proto::data_type::Kind::Char(c)) => {
649 Ok(DataType::Char { length: c.length })
650 }
651 Some(spark_connect_proto::data_type::Kind::VarChar(vc)) => {
652 Ok(DataType::Varchar { length: vc.length })
653 }
654 Some(spark_connect_proto::data_type::Kind::Binary(_)) => Ok(DataType::Binary),
655 Some(spark_connect_proto::data_type::Kind::Date(_)) => Ok(DataType::Date),
656 Some(spark_connect_proto::data_type::Kind::Timestamp(_)) => Ok(DataType::Timestamp),
657 Some(spark_connect_proto::data_type::Kind::TimestampNtz(_)) => {
658 Ok(DataType::TimestampNtz)
659 }
660 Some(spark_connect_proto::data_type::Kind::Time(t)) => {
661 let precision = t.precision.unwrap_or(6);
662 Ok(DataType::Time { precision })
663 }
664 Some(spark_connect_proto::data_type::Kind::CalendarInterval(_)) => {
665 Ok(DataType::CalendarInterval)
666 }
667 Some(spark_connect_proto::data_type::Kind::YearMonthInterval(ymi)) => {
668 let start_field = ymi.start_field.unwrap_or(0);
669 let end_field = ymi.end_field.unwrap_or(1);
670 Ok(DataType::YearMonthInterval {
671 start_field,
672 end_field,
673 })
674 }
675 Some(spark_connect_proto::data_type::Kind::DayTimeInterval(dti)) => {
676 let start_field = dti.start_field.unwrap_or(0);
677 let end_field = dti.end_field.unwrap_or(3);
678 Ok(DataType::DayTimeInterval {
679 start_field,
680 end_field,
681 })
682 }
683 Some(spark_connect_proto::data_type::Kind::Array(a)) => {
684 let element_type =
685 Box::new(DataType::from_proto(a.element_type.as_ref().ok_or_else(
686 || SparkError::connect_msg("Array element_type is missing"),
687 )?)?);
688 Ok(DataType::Array {
689 element_type,
690 contains_null: a.contains_null,
691 })
692 }
693 Some(spark_connect_proto::data_type::Kind::Struct(s)) => {
694 let mut fields = Vec::new();
695 for field_proto in &s.fields {
696 let data_type =
697 DataType::from_proto(field_proto.data_type.as_ref().ok_or_else(|| {
698 SparkError::connect_msg("StructField data_type is missing")
699 })?)?;
700 let metadata = if let Some(meta_str) = &field_proto.metadata {
701 serde_json::from_str(meta_str).unwrap_or_default()
702 } else {
703 BTreeMap::new()
704 };
705 fields.push(StructField {
706 name: field_proto.name.clone(),
707 data_type,
708 nullable: field_proto.nullable,
709 metadata,
710 });
711 }
712 Ok(DataType::Struct { fields })
713 }
714 Some(spark_connect_proto::data_type::Kind::Map(m)) => {
715 let key_type =
716 Box::new(DataType::from_proto(m.key_type.as_ref().ok_or_else(
717 || SparkError::connect_msg("Map key_type is missing"),
718 )?)?);
719 let value_type =
720 Box::new(DataType::from_proto(m.value_type.as_ref().ok_or_else(
721 || SparkError::connect_msg("Map value_type is missing"),
722 )?)?);
723 Ok(DataType::Map {
724 key_type,
725 value_type,
726 value_contains_null: m.value_contains_null,
727 })
728 }
729 Some(spark_connect_proto::data_type::Kind::Variant(_)) => Ok(DataType::Variant),
730 Some(spark_connect_proto::data_type::Kind::Geometry(g)) => {
731 Ok(DataType::Geometry { srid: g.srid })
732 }
733 Some(spark_connect_proto::data_type::Kind::Geography(g)) => {
734 Ok(DataType::Geography { srid: g.srid })
735 }
736 Some(spark_connect_proto::data_type::Kind::Udt(u)) => {
737 let sql_type = if let Some(ref st) = u.sql_type {
738 Some(Box::new(DataType::from_proto(st)?))
739 } else {
740 None
741 };
742 Ok(DataType::Udt {
743 type_str: u.r#type.clone(),
744 jvm_class: u.jvm_class.clone(),
745 python_class: u.python_class.clone(),
746 serialized_python_class: u.serialized_python_class.clone(),
747 sql_type,
748 })
749 }
750 Some(spark_connect_proto::data_type::Kind::Unparsed(u)) => Ok(DataType::Unparsed {
751 data_type_string: u.data_type_string.clone(),
752 }),
753 Some(spark_connect_proto::data_type::Kind::TimestampNtzNanos(tn)) => {
754 let precision = tn.precision.unwrap_or(9);
755 Ok(DataType::Time { precision })
756 }
757 Some(spark_connect_proto::data_type::Kind::TimestampLtzNanos(_)) => {
758 Ok(DataType::Timestamp)
759 }
760 None => Err(SparkError::connect_msg("DataType kind not set")),
761 }
762 }
763}
764
765impl StructField {
766 pub fn simple_string(&self) -> String {
770 format!("{}:{}", self.name, self.data_type.simple_string())
771 }
772
773 pub fn json_value(&self) -> serde_json::Value {
775 serde_json::json!({
776 "name": &self.name,
777 "type": self.data_type.json_value(),
778 "nullable": self.nullable,
779 "metadata": self.metadata,
780 })
781 }
782
783 pub fn from_json_str(s: &str) -> Result<StructField> {
785 let v: serde_json::Value = serde_json::from_str(s)
786 .map_err(|e| SparkError::value("INVALID_JSON", &[("detail", &e.to_string())]))?;
787 let name = v
788 .get("name")
789 .and_then(|x| x.as_str())
790 .ok_or_else(|| SparkError::value("INVALID_JSON", &[("detail", "missing field name")]))?
791 .to_string();
792 let nullable = v.get("nullable").and_then(|x| x.as_bool()).unwrap_or(true);
793 let data_type = DataType::from_json(v.get("type").unwrap_or(&serde_json::Value::Null))?;
794 let mut metadata = BTreeMap::new();
795 if let Some(md) = v.get("metadata").and_then(|x| x.as_object()) {
796 for (k, val) in md {
797 metadata.insert(k.clone(), val.clone());
798 }
799 }
800 Ok(StructField {
801 name,
802 data_type,
803 nullable,
804 metadata,
805 })
806 }
807}
808
809impl DataType {
813 pub fn field_names(&self) -> Result<Vec<String>> {
817 match self {
818 DataType::Struct { fields } => Ok(fields.iter().map(|f| f.name.clone()).collect()),
819 _ => Err(SparkError::value(
820 "INVALID_TYPE",
821 &[("detail", "fieldNames() can only be called on StructType")],
822 )),
823 }
824 }
825
826 pub fn names(&self) -> Result<Vec<String>> {
828 self.field_names()
829 }
830
831 pub fn to_ddl(&self) -> Result<String> {
834 match self {
835 DataType::Struct { fields } => Ok(fields
836 .iter()
837 .map(|f| {
838 let mut s = format!("{} {}", f.name, f.data_type.simple_string());
839 if !f.nullable {
840 s.push_str(" NOT NULL");
841 }
842 if let Some(comment) = f.metadata.get("comment").and_then(|c| c.as_str()) {
843 s.push_str(&format!(" COMMENT '{}'", comment.replace('\'', "\\'")));
844 }
845 s
846 })
847 .collect::<Vec<_>>()
848 .join(",")),
849 _ => Err(SparkError::value(
850 "INVALID_TYPE",
851 &[("detail", "toDDL() can only be called on StructType")],
852 )),
853 }
854 }
855
856 pub fn tree_string(&self) -> Result<String> {
858 self.tree_string_with_depth(i32::MAX)
859 }
860
861 pub fn tree_string_with_depth(&self, max_depth: i32) -> Result<String> {
865 match self {
866 DataType::Struct { .. } => {
867 let mut out = String::from("root\n");
868 self.append_tree(&mut out, " |", 1, max_depth);
869 Ok(out)
870 }
871 _ => Err(SparkError::value(
872 "INVALID_TYPE",
873 &[("detail", "treeString() can only be called on StructType")],
874 )),
875 }
876 }
877
878 fn append_tree(&self, out: &mut String, prefix: &str, depth: i32, max_depth: i32) {
879 if let DataType::Struct { fields } = self {
880 for f in fields {
881 let is_struct = matches!(f.data_type, DataType::Struct { .. });
887 let type_repr = if is_struct {
888 f.data_type.type_name()
889 } else {
890 f.data_type.simple_string()
891 };
892 out.push_str(&format!(
893 "{}-- {}: {} (nullable = {})\n",
894 prefix, f.name, type_repr, f.nullable
895 ));
896 if is_struct && depth < max_depth {
897 f.data_type.append_tree(
898 out,
899 &format!("{} |", prefix.trim_end_matches('|')),
900 depth + 1,
901 max_depth,
902 );
903 }
904 }
905 }
906 }
907
908 pub fn to_nullable(&self) -> DataType {
911 match self {
912 DataType::Struct { fields } => DataType::Struct {
913 fields: fields
914 .iter()
915 .map(|f| StructField {
916 name: f.name.clone(),
917 data_type: f.data_type.to_nullable(),
918 nullable: true,
919 metadata: f.metadata.clone(),
920 })
921 .collect(),
922 },
923 DataType::Array { element_type, .. } => DataType::Array {
924 element_type: Box::new(element_type.to_nullable()),
925 contains_null: true,
926 },
927 DataType::Map {
928 key_type,
929 value_type,
930 ..
931 } => DataType::Map {
932 key_type: Box::new(key_type.to_nullable()),
933 value_type: Box::new(value_type.to_nullable()),
934 value_contains_null: true,
935 },
936 other => other.clone(),
937 }
938 }
939
940 pub fn add(
956 &self,
957 field_name: &str,
958 field_type: DataType,
959 nullable: bool,
960 metadata: Option<BTreeMap<String, serde_json::Value>>,
961 ) -> Result<DataType> {
962 match self {
963 DataType::Struct { fields } => {
964 let mut new_fields = fields.clone();
965 new_fields.push(StructField {
966 name: field_name.to_string(),
967 data_type: field_type,
968 nullable,
969 metadata: metadata.unwrap_or_default(),
970 });
971 Ok(DataType::Struct { fields: new_fields })
972 }
973 _ => Err(SparkError::value(
974 "INVALID_TYPE",
975 &[("detail", "add() can only be called on StructType")],
976 )),
977 }
978 }
979}
980
981impl fmt::Display for DataType {
982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
983 write!(f, "{}", self.simple_string())
984 }
985}
986
987impl Hash for DataType {
988 fn hash<H: Hasher>(&self, state: &mut H) {
989 self.simple_string().hash(state);
990 }
991}
992
993const DAY_TIME_FIELDS: &[(&str, i32)] = &[("day", 0), ("hour", 1), ("minute", 2), ("second", 3)];
995
996const YEAR_MONTH_FIELDS: &[(&str, i32)] = &[("year", 0), ("month", 1)];
997
998fn interval_string(start_field: i32, end_field: i32, fields: &[(&str, i32)]) -> String {
1000 let field_map: std::collections::HashMap<i32, &str> =
1001 fields.iter().map(|(name, code)| (*code, *name)).collect();
1002
1003 if let (Some(&start_name), Some(&end_name)) =
1004 (field_map.get(&start_field), field_map.get(&end_field))
1005 {
1006 if start_name == end_name {
1007 format!("interval {}", start_name)
1008 } else {
1009 format!("interval {} to {}", start_name, end_name)
1010 }
1011 } else {
1012 "interval".to_string()
1013 }
1014}
1015
1016fn parse_json_value(value: &serde_json::Value, _field_name: Option<&str>) -> Result<DataType> {
1018 match value {
1019 serde_json::Value::String(s) => parse_json_type_string(s),
1020 serde_json::Value::Object(obj) => parse_json_object(obj),
1021 _ => Err(SparkError::value(
1022 "INVALID_DATATYPE_FORMAT",
1023 &[("detail", "Expected string or object for DataType")],
1024 )),
1025 }
1026}
1027
1028fn parse_json_type_string(s: &str) -> Result<DataType> {
1029 match s {
1030 "void" => Ok(DataType::Null),
1031 "boolean" => Ok(DataType::Boolean),
1032 "byte" => Ok(DataType::Byte),
1033 "short" => Ok(DataType::Short),
1034 "integer" => Ok(DataType::Integer),
1035 "long" => Ok(DataType::Long),
1036 "float" => Ok(DataType::Float),
1037 "double" => Ok(DataType::Double),
1038 "binary" => Ok(DataType::Binary),
1039 "date" => Ok(DataType::Date),
1040 "timestamp" => Ok(DataType::Timestamp),
1041 "timestamp_ntz" => Ok(DataType::TimestampNtz),
1042 "interval" => Ok(DataType::CalendarInterval),
1043 "variant" => Ok(DataType::Variant),
1044 s if s.starts_with("decimal(") => parse_decimal(s),
1045 s if s.starts_with("char(") => parse_char(s),
1046 s if s.starts_with("varchar(") => parse_varchar(s),
1047 s if s.starts_with("time(") => parse_time(s),
1048 s if s.starts_with("interval") => parse_interval_string(s),
1049 s if s.starts_with("string collate") => {
1050 let collation = s.trim_start_matches("string collate").trim().to_string();
1051 Ok(DataType::String { collation })
1052 }
1053 "string" => Ok(DataType::String {
1054 collation: "UTF8_BINARY".to_string(),
1055 }),
1056 s if s.starts_with("geometry(") => parse_geometry(s),
1057 s if s.starts_with("geography(") => parse_geography(s),
1058 s if s.starts_with("unparsed(") => Ok(DataType::Unparsed {
1059 data_type_string: s.to_string(),
1060 }),
1061 _ => Err(SparkError::value(
1062 "INVALID_DATATYPE_STRING",
1063 &[("detail", &format!("Unknown type string: {}", s))],
1064 )),
1065 }
1066}
1067
1068fn parse_json_object(obj: &serde_json::Map<String, serde_json::Value>) -> Result<DataType> {
1069 let type_field = obj.get("type").and_then(|v| v.as_str());
1070
1071 match type_field {
1072 Some("array") => {
1073 let element_type = obj.get("elementType").ok_or_else(|| {
1074 SparkError::value(
1075 "INVALID_DATATYPE_FORMAT",
1076 &[("detail", "Array missing elementType")],
1077 )
1078 })?;
1079 let contains_null = obj
1080 .get("containsNull")
1081 .and_then(|v| v.as_bool())
1082 .unwrap_or(true);
1083 Ok(DataType::Array {
1084 element_type: Box::new(parse_json_value(element_type, None)?),
1085 contains_null,
1086 })
1087 }
1088 Some("map") => {
1089 let key_type = obj.get("keyType").ok_or_else(|| {
1090 SparkError::value(
1091 "INVALID_DATATYPE_FORMAT",
1092 &[("detail", "Map missing keyType")],
1093 )
1094 })?;
1095 let value_type = obj.get("valueType").ok_or_else(|| {
1096 SparkError::value(
1097 "INVALID_DATATYPE_FORMAT",
1098 &[("detail", "Map missing valueType")],
1099 )
1100 })?;
1101 let value_contains_null = obj
1102 .get("valueContainsNull")
1103 .and_then(|v| v.as_bool())
1104 .unwrap_or(true);
1105 Ok(DataType::Map {
1106 key_type: Box::new(parse_json_value(key_type, None)?),
1107 value_type: Box::new(parse_json_value(value_type, None)?),
1108 value_contains_null,
1109 })
1110 }
1111 Some("struct") => {
1112 let fields_arr = obj
1113 .get("fields")
1114 .and_then(|v| v.as_array())
1115 .ok_or_else(|| {
1116 SparkError::value(
1117 "INVALID_DATATYPE_FORMAT",
1118 &[("detail", "Struct missing fields")],
1119 )
1120 })?;
1121
1122 let mut fields = Vec::new();
1123 for field_obj in fields_arr {
1124 if let Some(field_map) = field_obj.as_object() {
1125 let name = field_map
1126 .get("name")
1127 .and_then(|v| v.as_str())
1128 .ok_or_else(|| {
1129 SparkError::value(
1130 "INVALID_DATATYPE_FORMAT",
1131 &[("detail", "StructField missing name")],
1132 )
1133 })?
1134 .to_string();
1135 let field_type = field_map.get("type").ok_or_else(|| {
1136 SparkError::value(
1137 "INVALID_DATATYPE_FORMAT",
1138 &[("detail", "StructField missing type")],
1139 )
1140 })?;
1141 let data_type = parse_json_value(field_type, Some(&name))?;
1142 let nullable = field_map
1143 .get("nullable")
1144 .and_then(|v| v.as_bool())
1145 .unwrap_or(true);
1146 let metadata = field_map
1147 .get("metadata")
1148 .and_then(|v| v.as_object())
1149 .map(|m| m.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
1150 .unwrap_or_default();
1151
1152 fields.push(StructField {
1153 name,
1154 data_type,
1155 nullable,
1156 metadata,
1157 });
1158 }
1159 }
1160 Ok(DataType::Struct { fields })
1161 }
1162 _ => Err(SparkError::value(
1163 "INVALID_DATATYPE_FORMAT",
1164 &[("detail", "Unknown type in object")],
1165 )),
1166 }
1167}
1168
1169fn parse_decimal(s: &str) -> Result<DataType> {
1170 let inner = s
1171 .strip_prefix("decimal(")
1172 .and_then(|s| s.strip_suffix(")"))
1173 .ok_or_else(|| {
1174 SparkError::value(
1175 "INVALID_DATATYPE_FORMAT",
1176 &[("detail", "Invalid decimal format")],
1177 )
1178 })?;
1179
1180 let parts: Vec<&str> = inner.split(',').collect();
1181 if parts.len() != 2 {
1182 return Err(SparkError::value(
1183 "INVALID_DATATYPE_FORMAT",
1184 &[("detail", "Decimal requires precision and scale")],
1185 ));
1186 }
1187
1188 let precision = parts[0].trim().parse::<i32>().map_err(|_| {
1189 SparkError::value(
1190 "INVALID_DATATYPE_FORMAT",
1191 &[("detail", "Invalid precision")],
1192 )
1193 })?;
1194 let scale = parts[1].trim().parse::<i32>().map_err(|_| {
1195 SparkError::value("INVALID_DATATYPE_FORMAT", &[("detail", "Invalid scale")])
1196 })?;
1197
1198 Ok(DataType::Decimal { precision, scale })
1199}
1200
1201fn parse_char(s: &str) -> Result<DataType> {
1202 let inner = s
1203 .strip_prefix("char(")
1204 .and_then(|s| s.strip_suffix(")"))
1205 .ok_or_else(|| {
1206 SparkError::value(
1207 "INVALID_DATATYPE_FORMAT",
1208 &[("detail", "Invalid char format")],
1209 )
1210 })?;
1211
1212 let length = inner.trim().parse::<i32>().map_err(|_| {
1213 SparkError::value(
1214 "INVALID_DATATYPE_FORMAT",
1215 &[("detail", "Invalid char length")],
1216 )
1217 })?;
1218
1219 Ok(DataType::Char { length })
1220}
1221
1222fn parse_varchar(s: &str) -> Result<DataType> {
1223 let inner = s
1224 .strip_prefix("varchar(")
1225 .and_then(|s| s.strip_suffix(")"))
1226 .ok_or_else(|| {
1227 SparkError::value(
1228 "INVALID_DATATYPE_FORMAT",
1229 &[("detail", "Invalid varchar format")],
1230 )
1231 })?;
1232
1233 let length = inner.trim().parse::<i32>().map_err(|_| {
1234 SparkError::value(
1235 "INVALID_DATATYPE_FORMAT",
1236 &[("detail", "Invalid varchar length")],
1237 )
1238 })?;
1239
1240 Ok(DataType::Varchar { length })
1241}
1242
1243fn parse_time(s: &str) -> Result<DataType> {
1244 let inner = s
1245 .strip_prefix("time(")
1246 .and_then(|s| s.strip_suffix(")"))
1247 .ok_or_else(|| {
1248 SparkError::value(
1249 "INVALID_DATATYPE_FORMAT",
1250 &[("detail", "Invalid time format")],
1251 )
1252 })?;
1253
1254 let precision = inner.trim().parse::<i32>().map_err(|_| {
1255 SparkError::value(
1256 "INVALID_DATATYPE_FORMAT",
1257 &[("detail", "Invalid time precision")],
1258 )
1259 })?;
1260
1261 Ok(DataType::Time { precision })
1262}
1263
1264fn parse_interval_string(s: &str) -> Result<DataType> {
1265 if s == "interval" {
1266 return Ok(DataType::CalendarInterval);
1267 }
1268
1269 let parts: Vec<&str> = s.split_whitespace().collect();
1270 if parts.len() < 2 {
1271 return Ok(DataType::CalendarInterval);
1272 }
1273
1274 if parts.len() == 2 {
1275 let field_name = parts[1];
1277 for &(name, code) in YEAR_MONTH_FIELDS {
1278 if name == field_name {
1279 return Ok(DataType::YearMonthInterval {
1280 start_field: code,
1281 end_field: code,
1282 });
1283 }
1284 }
1285 for &(name, code) in DAY_TIME_FIELDS {
1286 if name == field_name {
1287 return Ok(DataType::DayTimeInterval {
1288 start_field: code,
1289 end_field: code,
1290 });
1291 }
1292 }
1293 } else if parts.len() == 4 && parts[2] == "to" {
1294 let start = parts[1];
1296 let end = parts[3];
1297
1298 if let (Some(&(_, start_code)), Some(&(_, end_code))) = (
1300 YEAR_MONTH_FIELDS.iter().find(|(name, _)| *name == start),
1301 YEAR_MONTH_FIELDS.iter().find(|(name, _)| *name == end),
1302 ) {
1303 return Ok(DataType::YearMonthInterval {
1304 start_field: start_code,
1305 end_field: end_code,
1306 });
1307 }
1308
1309 if let (Some(&(_, start_code)), Some(&(_, end_code))) = (
1311 DAY_TIME_FIELDS.iter().find(|(name, _)| *name == start),
1312 DAY_TIME_FIELDS.iter().find(|(name, _)| *name == end),
1313 ) {
1314 return Ok(DataType::DayTimeInterval {
1315 start_field: start_code,
1316 end_field: end_code,
1317 });
1318 }
1319 }
1320
1321 Ok(DataType::CalendarInterval)
1322}
1323
1324fn parse_geometry(s: &str) -> Result<DataType> {
1325 let inner = s
1326 .strip_prefix("geometry(")
1327 .and_then(|s| s.strip_suffix(")"))
1328 .ok_or_else(|| {
1329 SparkError::value(
1330 "INVALID_DATATYPE_FORMAT",
1331 &[("detail", "Invalid geometry format")],
1332 )
1333 })?;
1334
1335 let srid = if inner.to_lowercase() == "any" {
1336 -1
1337 } else {
1338 inner.parse::<i32>().map_err(|_| {
1339 SparkError::value(
1340 "INVALID_DATATYPE_FORMAT",
1341 &[("detail", "Invalid geometry srid")],
1342 )
1343 })?
1344 };
1345
1346 Ok(DataType::Geometry { srid })
1347}
1348
1349fn parse_geography(s: &str) -> Result<DataType> {
1350 let inner = s
1351 .strip_prefix("geography(")
1352 .and_then(|s| s.strip_suffix(")"))
1353 .ok_or_else(|| {
1354 SparkError::value(
1355 "INVALID_DATATYPE_FORMAT",
1356 &[("detail", "Invalid geography format")],
1357 )
1358 })?;
1359
1360 let srid = if inner.to_lowercase() == "any" {
1361 -1
1362 } else {
1363 inner
1364 .split(',')
1365 .next()
1366 .unwrap_or("4326")
1367 .parse::<i32>()
1368 .map_err(|_| {
1369 SparkError::value(
1370 "INVALID_DATATYPE_FORMAT",
1371 &[("detail", "Invalid geography srid")],
1372 )
1373 })?
1374 };
1375
1376 Ok(DataType::Geography { srid })
1377}
1378
1379fn parse_datatype_string(input: &str) -> Result<DataType> {
1382 let trimmed = input.trim();
1383
1384 if !trimmed.to_lowercase().starts_with("struct<")
1391 && (contains_top_level_comma(trimmed) || contains_top_level_whitespace(trimmed))
1392 {
1393 if let Ok(dt) = parse_top_level_schema(trimmed) {
1394 return Ok(dt);
1395 }
1396 }
1397
1398 parse_single_type(trimmed)
1399}
1400
1401fn contains_top_level_whitespace(s: &str) -> bool {
1404 let mut depth = 0;
1405 for c in s.chars() {
1406 match c {
1407 '<' | '(' => depth += 1,
1408 '>' | ')' => depth -= 1,
1409 _ if depth == 0 && c.is_whitespace() => return true,
1410 _ => {}
1411 }
1412 }
1413 false
1414}
1415
1416fn contains_top_level_comma(s: &str) -> bool {
1418 let mut depth = 0;
1419 for c in s.chars() {
1420 match c {
1421 '<' | '(' => depth += 1,
1422 '>' | ')' => depth -= 1,
1423 ',' if depth == 0 => return true,
1424 _ => {}
1425 }
1426 }
1427 false
1428}
1429
1430fn parse_top_level_schema(input: &str) -> Result<DataType> {
1432 let mut fields = Vec::new();
1433 let parts = split_top_level_comma(input);
1434
1435 for part in parts {
1436 let trimmed = part.trim();
1437 if trimmed.is_empty() {
1438 continue;
1439 }
1440
1441 let (name, type_str) = if let Some(colon_idx) = trimmed.find(':') {
1443 let name = trimmed[..colon_idx].trim();
1444 let type_str = trimmed[colon_idx + 1..].trim();
1445 (name, type_str)
1446 } else {
1447 let parts: Vec<&str> = trimmed.splitn(2, char::is_whitespace).collect();
1449 if parts.len() != 2 {
1450 return Err(SparkError::value(
1451 "INVALID_DATATYPE_FORMAT",
1452 &[("detail", &format!("Cannot parse field: {}", trimmed))],
1453 ));
1454 }
1455 (parts[0], parts[1])
1456 };
1457
1458 let data_type = parse_single_type(type_str)?;
1459 fields.push(StructField {
1460 name: name.to_string(),
1461 data_type,
1462 nullable: true,
1463 metadata: BTreeMap::new(),
1464 });
1465 }
1466
1467 Ok(DataType::Struct { fields })
1468}
1469
1470fn split_top_level_comma(s: &str) -> Vec<&str> {
1472 let mut result = Vec::new();
1473 let mut start = 0;
1474 let mut depth = 0;
1475 let bytes = s.as_bytes();
1476
1477 for (i, &b) in bytes.iter().enumerate() {
1478 match b {
1479 b'<' | b'(' => depth += 1,
1480 b'>' | b')' => depth -= 1,
1481 b',' if depth == 0 => {
1482 result.push(&s[start..i]);
1483 start = i + 1;
1484 }
1485 _ => {}
1486 }
1487 }
1488 result.push(&s[start..]);
1489 result
1490}
1491
1492fn parse_single_type(input: &str) -> Result<DataType> {
1494 let trimmed = input.trim().to_lowercase();
1495
1496 if trimmed.starts_with("array<") {
1498 return parse_array_type(input);
1499 }
1500 if trimmed.starts_with("map<") {
1501 return parse_map_type(input);
1502 }
1503 if trimmed.starts_with("struct<") {
1504 return parse_struct_type(input);
1505 }
1506
1507 match trimmed.as_str() {
1509 "null" | "void" => Ok(DataType::Null),
1510 "boolean" => Ok(DataType::Boolean),
1511 "byte" | "tinyint" => Ok(DataType::Byte),
1512 "short" | "smallint" => Ok(DataType::Short),
1513 "int" | "integer" => Ok(DataType::Integer),
1514 "long" | "bigint" => Ok(DataType::Long),
1515 "float" => Ok(DataType::Float),
1516 "double" => Ok(DataType::Double),
1517 "string" => Ok(DataType::String {
1518 collation: "UTF8_BINARY".to_string(),
1519 }),
1520 "binary" => Ok(DataType::Binary),
1521 "date" => Ok(DataType::Date),
1522 "timestamp" => Ok(DataType::Timestamp),
1523 "timestamp_ntz" => Ok(DataType::TimestampNtz),
1524 "interval" => Ok(DataType::CalendarInterval),
1525 "variant" => Ok(DataType::Variant),
1526 _ => {
1527 if trimmed.starts_with("decimal(") {
1529 parse_decimal(&trimmed)
1530 } else if trimmed.starts_with("char(") {
1531 parse_char(&trimmed)
1532 } else if trimmed.starts_with("varchar(") {
1533 parse_varchar(&trimmed)
1534 } else if trimmed.starts_with("time(") {
1535 parse_time(&trimmed)
1536 } else if trimmed.starts_with("interval") {
1537 parse_interval_string(&trimmed)
1538 } else if trimmed.starts_with("string collate") {
1539 let collation = trimmed
1540 .trim_start_matches("string")
1541 .trim_start_matches("collate")
1542 .trim()
1543 .to_string();
1544 Ok(DataType::String { collation })
1545 } else if trimmed.starts_with("geometry(") {
1546 parse_geometry(&trimmed)
1547 } else if trimmed.starts_with("geography(") {
1548 parse_geography(&trimmed)
1549 } else {
1550 Err(SparkError::value(
1551 "INVALID_DATATYPE_FORMAT",
1552 &[("detail", &format!("Unknown type: {}", input))],
1553 ))
1554 }
1555 }
1556 }
1557}
1558
1559fn parse_array_type(input: &str) -> Result<DataType> {
1561 let trimmed = input.trim();
1562 if !trimmed.to_lowercase().starts_with("array<") || !trimmed.ends_with('>') {
1563 return Err(SparkError::value(
1564 "INVALID_DATATYPE_FORMAT",
1565 &[("detail", "Invalid array type format")],
1566 ));
1567 }
1568
1569 let inner = &trimmed[6..trimmed.len() - 1];
1570 let element_type = parse_single_type(inner)?;
1571
1572 Ok(DataType::Array {
1573 element_type: Box::new(element_type),
1574 contains_null: true,
1575 })
1576}
1577
1578fn parse_map_type(input: &str) -> Result<DataType> {
1580 let trimmed = input.trim();
1581 if !trimmed.to_lowercase().starts_with("map<") || !trimmed.ends_with('>') {
1582 return Err(SparkError::value(
1583 "INVALID_DATATYPE_FORMAT",
1584 &[("detail", "Invalid map type format")],
1585 ));
1586 }
1587
1588 let inner = &trimmed[4..trimmed.len() - 1];
1589 let parts = split_map_parts(inner)?;
1590 if parts.len() != 2 {
1591 return Err(SparkError::value(
1592 "INVALID_DATATYPE_FORMAT",
1593 &[(
1594 "detail",
1595 "Map must have exactly 2 type parameters (key and value)",
1596 )],
1597 ));
1598 }
1599
1600 let key_type = parse_single_type(parts[0])?;
1601 let value_type = parse_single_type(parts[1])?;
1602
1603 Ok(DataType::Map {
1604 key_type: Box::new(key_type),
1605 value_type: Box::new(value_type),
1606 value_contains_null: true,
1607 })
1608}
1609
1610fn split_map_parts(s: &str) -> Result<Vec<&str>> {
1612 let mut depth = 0;
1613 let mut parts = Vec::new();
1614 let mut start = 0;
1615
1616 for (i, c) in s.char_indices() {
1617 match c {
1618 '<' | '(' => depth += 1,
1619 '>' | ')' => depth -= 1,
1620 ',' if depth == 0 => {
1621 parts.push(&s[start..i]);
1622 start = i + 1;
1623 }
1624 _ => {}
1625 }
1626 }
1627 parts.push(&s[start..]);
1628
1629 Ok(parts)
1630}
1631
1632fn parse_struct_type(input: &str) -> Result<DataType> {
1634 let trimmed = input.trim();
1635 if !trimmed.to_lowercase().starts_with("struct<") || !trimmed.ends_with('>') {
1636 return Err(SparkError::value(
1637 "INVALID_DATATYPE_FORMAT",
1638 &[("detail", "Invalid struct type format")],
1639 ));
1640 }
1641
1642 let inner = &trimmed[7..trimmed.len() - 1];
1643 if inner.trim().is_empty() {
1644 return Ok(DataType::Struct { fields: vec![] });
1645 }
1646
1647 let mut fields = Vec::new();
1648 let parts = split_struct_fields(inner);
1649
1650 for part in parts {
1651 let part_trimmed = part.trim();
1652 if part_trimmed.is_empty() {
1653 continue;
1654 }
1655
1656 if let Some(colon_idx) = find_unbracketed_colon(part_trimmed) {
1658 let name = part_trimmed[..colon_idx].trim();
1659 let type_str = part_trimmed[colon_idx + 1..].trim();
1660
1661 let data_type = parse_single_type(type_str)?;
1662 fields.push(StructField {
1663 name: name.to_string(),
1664 data_type,
1665 nullable: true,
1666 metadata: BTreeMap::new(),
1667 });
1668 } else {
1669 return Err(SparkError::value(
1670 "INVALID_DATATYPE_FORMAT",
1671 &[("detail", &format!("Invalid struct field: {}", part_trimmed))],
1672 ));
1673 }
1674 }
1675
1676 Ok(DataType::Struct { fields })
1677}
1678
1679fn split_struct_fields(s: &str) -> Vec<&str> {
1681 let mut depth = 0;
1682 let mut parts = Vec::new();
1683 let mut start = 0;
1684
1685 for (i, c) in s.char_indices() {
1686 match c {
1687 '<' | '(' => depth += 1,
1688 '>' | ')' => depth -= 1,
1689 ',' if depth == 0 => {
1690 parts.push(&s[start..i]);
1691 start = i + 1;
1692 }
1693 _ => {}
1694 }
1695 }
1696 parts.push(&s[start..]);
1697
1698 parts
1699}
1700
1701fn find_unbracketed_colon(s: &str) -> Option<usize> {
1703 let mut depth = 0;
1704 for (i, c) in s.char_indices() {
1705 match c {
1706 '<' | '(' => depth += 1,
1707 '>' | ')' => depth -= 1,
1708 ':' if depth == 0 => return Some(i),
1709 _ => {}
1710 }
1711 }
1712 None
1713}
1714
1715#[cfg(test)]
1716mod tests {
1717 use super::*;
1718
1719 #[test]
1720 fn test_null_type() {
1721 let dt = DataType::Null;
1722 assert_eq!(dt.type_name(), "void");
1723 assert_eq!(dt.simple_string(), "void");
1724 assert_eq!(dt.json(), "\"void\"");
1725 }
1726
1727 #[test]
1728 fn test_simple_types() {
1729 let tests = vec![
1730 (DataType::Boolean, "boolean", "boolean", "\"boolean\""),
1731 (DataType::Byte, "byte", "tinyint", "\"byte\""),
1732 (DataType::Short, "short", "smallint", "\"short\""),
1733 (DataType::Integer, "integer", "int", "\"integer\""),
1734 (DataType::Long, "long", "bigint", "\"long\""),
1735 (DataType::Float, "float", "float", "\"float\""),
1736 (DataType::Double, "double", "double", "\"double\""),
1737 (DataType::Binary, "binary", "binary", "\"binary\""),
1738 (DataType::Date, "date", "date", "\"date\""),
1739 (
1740 DataType::Timestamp,
1741 "timestamp",
1742 "timestamp",
1743 "\"timestamp\"",
1744 ),
1745 (
1746 DataType::TimestampNtz,
1747 "timestamp_ntz",
1748 "timestamp_ntz",
1749 "\"timestamp_ntz\"",
1750 ),
1751 (
1752 DataType::CalendarInterval,
1753 "interval",
1754 "interval",
1755 "\"interval\"",
1756 ),
1757 (DataType::Variant, "variant", "variant", "\"variant\""),
1758 ];
1759
1760 for (dt, expected_typename, expected_simple, expected_json) in tests {
1761 assert_eq!(dt.type_name(), expected_typename, "type_name for {:?}", dt);
1762 assert_eq!(
1763 dt.simple_string(),
1764 expected_simple,
1765 "simple_string for {:?}",
1766 dt
1767 );
1768 assert_eq!(dt.json(), expected_json, "json for {:?}", dt);
1769 }
1770 }
1771
1772 #[test]
1773 fn test_decimal_type() {
1774 let dt = DataType::Decimal {
1775 precision: 10,
1776 scale: 0,
1777 };
1778 assert_eq!(dt.simple_string(), "decimal(10,0)");
1779 assert_eq!(dt.json(), "\"decimal(10,0)\"");
1780
1781 let dt2 = DataType::Decimal {
1782 precision: 38,
1783 scale: 18,
1784 };
1785 assert_eq!(dt2.simple_string(), "decimal(38,18)");
1786 }
1787
1788 #[test]
1789 fn test_char_varchar_types() {
1790 let char_dt = DataType::Char { length: 50 };
1791 assert_eq!(char_dt.simple_string(), "char(50)");
1792 assert_eq!(char_dt.json(), "\"char(50)\"");
1793
1794 let varchar_dt = DataType::Varchar { length: 100 };
1795 assert_eq!(varchar_dt.simple_string(), "varchar(100)");
1796 assert_eq!(varchar_dt.json(), "\"varchar(100)\"");
1797 }
1798
1799 #[test]
1800 fn test_array_type() {
1801 let dt = DataType::Array {
1802 element_type: Box::new(DataType::String {
1803 collation: "UTF8_BINARY".to_string(),
1804 }),
1805 contains_null: true,
1806 };
1807 assert_eq!(dt.simple_string(), "array<string>");
1808
1809 let json_val = dt.json_value();
1810 assert_eq!(json_val["type"], "array");
1811 assert_eq!(json_val["containsNull"], true);
1812
1813 let dt2 = DataType::Array {
1814 element_type: Box::new(DataType::Integer),
1815 contains_null: false,
1816 };
1817 assert_eq!(dt2.simple_string(), "array<int>");
1818 }
1819
1820 #[test]
1821 fn test_map_type() {
1822 let dt = DataType::Map {
1823 key_type: Box::new(DataType::String {
1824 collation: "UTF8_BINARY".to_string(),
1825 }),
1826 value_type: Box::new(DataType::Integer),
1827 value_contains_null: true,
1828 };
1829 assert_eq!(dt.simple_string(), "map<string,int>");
1830
1831 let json_val = dt.json_value();
1832 assert_eq!(json_val["type"], "map");
1833 assert_eq!(json_val["valueContainsNull"], true);
1834 }
1835
1836 #[test]
1837 fn test_struct_type() {
1838 let dt = DataType::Struct {
1839 fields: vec![
1840 StructField {
1841 name: "name".to_string(),
1842 data_type: DataType::String {
1843 collation: "UTF8_BINARY".to_string(),
1844 },
1845 nullable: true,
1846 metadata: BTreeMap::new(),
1847 },
1848 StructField {
1849 name: "age".to_string(),
1850 data_type: DataType::Integer,
1851 nullable: true,
1852 metadata: BTreeMap::new(),
1853 },
1854 ],
1855 };
1856 assert_eq!(dt.simple_string(), "struct<name:string,age:int>");
1857
1858 let json_val = dt.json_value();
1859 assert_eq!(json_val["type"], "struct");
1860 assert_eq!(json_val["fields"].as_array().unwrap().len(), 2);
1861 }
1862
1863 #[test]
1864 fn test_interval_types() {
1865 let dti = DataType::DayTimeInterval {
1866 start_field: 0,
1867 end_field: 3,
1868 };
1869 assert_eq!(dti.simple_string(), "interval day to second");
1870
1871 let ymi = DataType::YearMonthInterval {
1872 start_field: 0,
1873 end_field: 1,
1874 };
1875 assert_eq!(ymi.simple_string(), "interval year to month");
1876 }
1877
1878 #[test]
1879 fn test_string_collation() {
1880 let dt = DataType::String {
1881 collation: "UTF8_BINARY".to_string(),
1882 };
1883 assert_eq!(dt.simple_string(), "string");
1884
1885 let dt2 = DataType::String {
1886 collation: "UNICODE".to_string(),
1887 };
1888 assert_eq!(dt2.simple_string(), "string collate UNICODE");
1889 }
1890
1891 #[test]
1892 fn test_time_type() {
1893 let dt = DataType::Time { precision: 6 };
1894 assert_eq!(dt.simple_string(), "time(6)");
1895 assert_eq!(dt.json(), "\"time(6)\"");
1896 }
1897
1898 #[test]
1899 fn test_proto_roundtrip_simple() {
1900 let types = vec![
1901 DataType::Null,
1902 DataType::Boolean,
1903 DataType::Byte,
1904 DataType::Integer,
1905 DataType::Long,
1906 DataType::Float,
1907 DataType::Double,
1908 DataType::Binary,
1909 DataType::Date,
1910 DataType::Timestamp,
1911 DataType::TimestampNtz,
1912 DataType::CalendarInterval,
1913 DataType::Variant,
1914 ];
1915
1916 for dt in types {
1917 let proto = dt.to_proto();
1918 let roundtrip = DataType::from_proto(&proto).unwrap();
1919 assert_eq!(dt, roundtrip, "proto roundtrip failed for {:?}", dt);
1920 }
1921 }
1922
1923 #[test]
1924 fn test_proto_roundtrip_decimal() {
1925 let dt = DataType::Decimal {
1926 precision: 38,
1927 scale: 18,
1928 };
1929 let proto = dt.to_proto();
1930 let roundtrip = DataType::from_proto(&proto).unwrap();
1931 assert_eq!(dt, roundtrip);
1932 }
1933
1934 #[test]
1935 fn test_proto_roundtrip_array() {
1936 let dt = DataType::Array {
1937 element_type: Box::new(DataType::String {
1938 collation: "UTF8_BINARY".to_string(),
1939 }),
1940 contains_null: false,
1941 };
1942 let proto = dt.to_proto();
1943 let roundtrip = DataType::from_proto(&proto).unwrap();
1944 assert_eq!(dt, roundtrip);
1945 }
1946
1947 #[test]
1948 fn test_proto_roundtrip_struct() {
1949 let dt = DataType::Struct {
1950 fields: vec![
1951 StructField {
1952 name: "a".to_string(),
1953 data_type: DataType::Integer,
1954 nullable: true,
1955 metadata: BTreeMap::new(),
1956 },
1957 StructField {
1958 name: "b".to_string(),
1959 data_type: DataType::String {
1960 collation: "UTF8_BINARY".to_string(),
1961 },
1962 nullable: false,
1963 metadata: BTreeMap::new(),
1964 },
1965 ],
1966 };
1967 let proto = dt.to_proto();
1968 let roundtrip = DataType::from_proto(&proto).unwrap();
1969 assert_eq!(dt, roundtrip);
1970 }
1971
1972 #[test]
1973 fn test_json_parse_decimal() {
1974 let dt = DataType::from_json(&serde_json::json!("decimal(10,0)")).unwrap();
1975 assert_eq!(dt.simple_string(), "decimal(10,0)");
1976 }
1977
1978 #[test]
1979 fn test_json_parse_array() {
1980 let json = serde_json::json!({
1981 "type": "array",
1982 "elementType": "string",
1983 "containsNull": true,
1984 });
1985 let dt = DataType::from_json(&json).unwrap();
1986 assert_eq!(dt.simple_string(), "array<string>");
1987 }
1988
1989 #[test]
1990 fn test_json_parse_struct() {
1991 let json = serde_json::json!({
1992 "type": "struct",
1993 "fields": [
1994 {
1995 "name": "name",
1996 "type": "string",
1997 "nullable": true,
1998 "metadata": {}
1999 },
2000 {
2001 "name": "age",
2002 "type": "integer",
2003 "nullable": true,
2004 "metadata": {}
2005 }
2006 ]
2007 });
2008 let dt = DataType::from_json(&json).unwrap();
2009 assert_eq!(dt.simple_string(), "struct<name:string,age:int>");
2010 }
2011
2012 #[test]
2013 fn test_hash_consistency() {
2014 let dt1 = DataType::Integer;
2015 let dt2 = DataType::Integer;
2016 let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
2017 let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
2018 dt1.hash(&mut hasher1);
2019 dt2.hash(&mut hasher2);
2020 assert_eq!(
2021 std::hash::Hasher::finish(&hasher1),
2022 std::hash::Hasher::finish(&hasher2)
2023 );
2024 }
2025
2026 #[test]
2027 fn test_equality() {
2028 let dt1 = DataType::Decimal {
2029 precision: 10,
2030 scale: 0,
2031 };
2032 let dt2 = DataType::Decimal {
2033 precision: 10,
2034 scale: 0,
2035 };
2036 assert_eq!(dt1, dt2);
2037
2038 let dt3 = DataType::Decimal {
2039 precision: 10,
2040 scale: 1,
2041 };
2042 assert_ne!(dt1, dt3);
2043 }
2044
2045 #[test]
2046 fn test_struct_field_simple_string() {
2047 let field = StructField {
2048 name: "field_name".to_string(),
2049 data_type: DataType::String {
2050 collation: "UTF8_BINARY".to_string(),
2051 },
2052 nullable: true,
2053 metadata: BTreeMap::new(),
2054 };
2055 assert_eq!(field.simple_string(), "field_name:string");
2056 }
2057
2058 #[test]
2059 fn test_geometry_type() {
2060 let dt = DataType::Geometry { srid: 4326 };
2061 assert_eq!(dt.simple_string(), "geometry(4326)");
2062
2063 let dt_any = DataType::Geometry { srid: -1 };
2064 assert_eq!(dt_any.simple_string(), "geometry(any)");
2065 }
2066
2067 #[test]
2068 fn test_geography_type() {
2069 let dt = DataType::Geography { srid: 4326 };
2070 assert_eq!(dt.simple_string(), "geography(4326)");
2071
2072 let dt_any = DataType::Geography { srid: -1 };
2073 assert_eq!(dt_any.simple_string(), "geography(any)");
2074 }
2075
2076 #[test]
2077 fn test_golden_values_simple_strings() {
2078 struct TestCase {
2080 dt: DataType,
2081 expected_simple: &'static str,
2082 expected_type_name: &'static str,
2083 }
2084
2085 let tests = vec![
2086 TestCase {
2087 dt: DataType::Null,
2088 expected_simple: "void",
2089 expected_type_name: "void",
2090 },
2091 TestCase {
2092 dt: DataType::String {
2093 collation: "UTF8_BINARY".to_string(),
2094 },
2095 expected_simple: "string",
2096 expected_type_name: "string",
2097 },
2098 TestCase {
2099 dt: DataType::Boolean,
2100 expected_simple: "boolean",
2101 expected_type_name: "boolean",
2102 },
2103 TestCase {
2104 dt: DataType::Byte,
2105 expected_simple: "tinyint",
2106 expected_type_name: "byte",
2107 },
2108 TestCase {
2109 dt: DataType::Short,
2110 expected_simple: "smallint",
2111 expected_type_name: "short",
2112 },
2113 TestCase {
2114 dt: DataType::Integer,
2115 expected_simple: "int",
2116 expected_type_name: "integer",
2117 },
2118 TestCase {
2119 dt: DataType::Long,
2120 expected_simple: "bigint",
2121 expected_type_name: "long",
2122 },
2123 TestCase {
2124 dt: DataType::Float,
2125 expected_simple: "float",
2126 expected_type_name: "float",
2127 },
2128 TestCase {
2129 dt: DataType::Double,
2130 expected_simple: "double",
2131 expected_type_name: "double",
2132 },
2133 TestCase {
2134 dt: DataType::Date,
2135 expected_simple: "date",
2136 expected_type_name: "date",
2137 },
2138 TestCase {
2139 dt: DataType::Timestamp,
2140 expected_simple: "timestamp",
2141 expected_type_name: "timestamp",
2142 },
2143 TestCase {
2144 dt: DataType::TimestampNtz,
2145 expected_simple: "timestamp_ntz",
2146 expected_type_name: "timestamp_ntz",
2147 },
2148 TestCase {
2149 dt: DataType::Binary,
2150 expected_simple: "binary",
2151 expected_type_name: "binary",
2152 },
2153 TestCase {
2154 dt: DataType::Decimal {
2155 precision: 10,
2156 scale: 0,
2157 },
2158 expected_simple: "decimal(10,0)",
2159 expected_type_name: "decimal",
2160 },
2161 TestCase {
2162 dt: DataType::Char { length: 50 },
2163 expected_simple: "char(50)",
2164 expected_type_name: "char",
2165 },
2166 TestCase {
2167 dt: DataType::Varchar { length: 100 },
2168 expected_simple: "varchar(100)",
2169 expected_type_name: "varchar",
2170 },
2171 TestCase {
2172 dt: DataType::CalendarInterval,
2173 expected_simple: "interval",
2174 expected_type_name: "interval",
2175 },
2176 TestCase {
2177 dt: DataType::DayTimeInterval {
2178 start_field: 0,
2179 end_field: 3,
2180 },
2181 expected_simple: "interval day to second",
2182 expected_type_name: "interval",
2183 },
2184 TestCase {
2185 dt: DataType::YearMonthInterval {
2186 start_field: 0,
2187 end_field: 1,
2188 },
2189 expected_simple: "interval year to month",
2190 expected_type_name: "interval",
2191 },
2192 TestCase {
2193 dt: DataType::Variant,
2194 expected_simple: "variant",
2195 expected_type_name: "variant",
2196 },
2197 ];
2198
2199 for test in tests {
2200 assert_eq!(
2201 test.dt.simple_string(),
2202 test.expected_simple,
2203 "simpleString mismatch for {:?}",
2204 test.dt
2205 );
2206 assert_eq!(
2207 test.dt.type_name(),
2208 test.expected_type_name,
2209 "typeName mismatch for {:?}",
2210 test.dt
2211 );
2212 }
2213 }
2214
2215 #[test]
2216 fn test_golden_values_complex_types() {
2217 let array_string = DataType::Array {
2219 element_type: Box::new(DataType::String {
2220 collation: "UTF8_BINARY".to_string(),
2221 }),
2222 contains_null: true,
2223 };
2224 assert_eq!(array_string.simple_string(), "array<string>");
2225
2226 let array_int = DataType::Array {
2228 element_type: Box::new(DataType::Integer),
2229 contains_null: false,
2230 };
2231 assert_eq!(array_int.simple_string(), "array<int>");
2232
2233 let map_type = DataType::Map {
2235 key_type: Box::new(DataType::String {
2236 collation: "UTF8_BINARY".to_string(),
2237 }),
2238 value_type: Box::new(DataType::Integer),
2239 value_contains_null: true,
2240 };
2241 assert_eq!(map_type.simple_string(), "map<string,int>");
2242
2243 let struct_type = DataType::Struct {
2245 fields: vec![
2246 StructField {
2247 name: "name".to_string(),
2248 data_type: DataType::String {
2249 collation: "UTF8_BINARY".to_string(),
2250 },
2251 nullable: true,
2252 metadata: BTreeMap::new(),
2253 },
2254 StructField {
2255 name: "age".to_string(),
2256 data_type: DataType::Integer,
2257 nullable: true,
2258 metadata: BTreeMap::new(),
2259 },
2260 ],
2261 };
2262 assert_eq!(struct_type.simple_string(), "struct<name:string,age:int>");
2263 }
2264
2265 #[test]
2266 fn test_golden_json_values() {
2267 let null_json = DataType::Null.json();
2269 assert_eq!(null_json, "\"void\"");
2270
2271 let string_json = DataType::String {
2272 collation: "UTF8_BINARY".to_string(),
2273 }
2274 .json();
2275 assert_eq!(string_json, "\"string\"");
2276
2277 let decimal_json = DataType::Decimal {
2278 precision: 10,
2279 scale: 0,
2280 }
2281 .json();
2282 assert_eq!(decimal_json, "\"decimal(10,0)\"");
2283
2284 let array_json = DataType::Array {
2286 element_type: Box::new(DataType::Integer),
2287 contains_null: false,
2288 };
2289 let json_val = array_json.json_value();
2290 assert_eq!(json_val["type"], "array");
2291 assert_eq!(json_val["containsNull"], false);
2292
2293 let map_json = DataType::Map {
2295 key_type: Box::new(DataType::String {
2296 collation: "UTF8_BINARY".to_string(),
2297 }),
2298 value_type: Box::new(DataType::Integer),
2299 value_contains_null: true,
2300 };
2301 let json_val = map_json.json_value();
2302 assert_eq!(json_val["type"], "map");
2303 assert_eq!(json_val["valueContainsNull"], true);
2304 }
2305
2306 #[test]
2307 fn test_from_ddl_primitive_types() {
2308 assert_eq!(DataType::from_ddl("int").unwrap(), DataType::Integer);
2310 assert_eq!(DataType::from_ddl("INT").unwrap(), DataType::Integer);
2311 assert_eq!(DataType::from_ddl("bigint").unwrap(), DataType::Long);
2312 assert_eq!(
2313 DataType::from_ddl("string").unwrap(),
2314 DataType::String {
2315 collation: "UTF8_BINARY".to_string()
2316 }
2317 );
2318 assert_eq!(DataType::from_ddl("double").unwrap(), DataType::Double);
2319 assert_eq!(DataType::from_ddl("boolean").unwrap(), DataType::Boolean);
2320 assert_eq!(DataType::from_ddl("date").unwrap(), DataType::Date);
2321 assert_eq!(
2322 DataType::from_ddl("timestamp").unwrap(),
2323 DataType::Timestamp
2324 );
2325 assert_eq!(DataType::from_ddl("binary").unwrap(), DataType::Binary);
2326 assert_eq!(DataType::from_ddl("tinyint").unwrap(), DataType::Byte);
2327 assert_eq!(DataType::from_ddl("smallint").unwrap(), DataType::Short);
2328 assert_eq!(DataType::from_ddl("float").unwrap(), DataType::Float);
2329 }
2330
2331 #[test]
2332 fn test_from_ddl_decimal_and_fixed_length() {
2333 assert_eq!(
2335 DataType::from_ddl("decimal(10,2)").unwrap(),
2336 DataType::Decimal {
2337 precision: 10,
2338 scale: 2
2339 }
2340 );
2341
2342 assert_eq!(
2344 DataType::from_ddl("char(50)").unwrap(),
2345 DataType::Char { length: 50 }
2346 );
2347
2348 assert_eq!(
2350 DataType::from_ddl("varchar(100)").unwrap(),
2351 DataType::Varchar { length: 100 }
2352 );
2353
2354 assert_eq!(
2356 DataType::from_ddl("time(6)").unwrap(),
2357 DataType::Time { precision: 6 }
2358 );
2359 }
2360
2361 #[test]
2362 fn test_from_ddl_array_type() {
2363 let dt = DataType::from_ddl("array<int>").unwrap();
2364 assert_eq!(dt.simple_string(), "array<int>");
2365
2366 let dt2 = DataType::from_ddl("array<string>").unwrap();
2367 assert_eq!(dt2.simple_string(), "array<string>");
2368
2369 let dt3 = DataType::from_ddl("array<array<int>>").unwrap();
2370 assert_eq!(dt3.simple_string(), "array<array<int>>");
2371 }
2372
2373 #[test]
2374 fn test_from_ddl_map_type() {
2375 let dt = DataType::from_ddl("map<string,int>").unwrap();
2376 assert_eq!(dt.simple_string(), "map<string,int>");
2377
2378 let dt2 = DataType::from_ddl("map<string,array<int>>").unwrap();
2379 assert_eq!(dt2.simple_string(), "map<string,array<int>>");
2380 }
2381
2382 #[test]
2383 fn test_from_ddl_struct_type() {
2384 let dt = DataType::from_ddl("struct<name:string,age:int>").unwrap();
2385 assert_eq!(dt.simple_string(), "struct<name:string,age:int>");
2386
2387 let dt2 = DataType::from_ddl("struct<a:int,b:array<string>>").unwrap();
2388 assert_eq!(dt2.simple_string(), "struct<a:int,b:array<string>>");
2389 }
2390
2391 #[test]
2392 fn test_from_ddl_top_level_schema() {
2393 let dt = DataType::from_ddl("a INT, b STRING").unwrap();
2395 assert_eq!(dt.simple_string(), "struct<a:int,b:string>");
2396
2397 let dt2 = DataType::from_ddl("a DOUBLE, b CHAR(50)").unwrap();
2398 assert_eq!(dt2.simple_string(), "struct<a:double,b:char(50)>");
2399
2400 let dt3 = DataType::from_ddl("name string, age int").unwrap();
2401 assert_eq!(dt3.simple_string(), "struct<name:string,age:int>");
2402 }
2403
2404 #[test]
2405 fn test_from_ddl_roundtrip() {
2406 let test_cases = vec![
2408 "int",
2409 "string",
2410 "array<int>",
2411 "map<string,int>",
2412 "struct<name:string,age:int>",
2413 "decimal(10,2)",
2414 "char(50)",
2415 "varchar(100)",
2416 "array<map<string,int>>",
2417 "struct<a:int,b:array<string>>",
2418 ];
2419
2420 for case in test_cases {
2421 let dt = DataType::from_ddl(case).expect(&format!("Failed to parse: {}", case));
2422 let simple = dt.simple_string();
2423 let dt2 =
2424 DataType::from_ddl(&simple).expect(&format!("Failed to roundtrip: {}", simple));
2425 assert_eq!(dt, dt2, "Roundtrip failed for: {}", case);
2426 }
2427 }
2428
2429 #[test]
2430 fn test_need_conversion() {
2431 assert!(DataType::Date.need_conversion());
2433 assert!(DataType::Timestamp.need_conversion());
2434 assert!(DataType::TimestampNtz.need_conversion());
2435 assert!(DataType::CalendarInterval.need_conversion());
2436 assert!(DataType::Time { precision: 6 }.need_conversion());
2437
2438 assert!(!DataType::Integer.need_conversion());
2440 assert!(!DataType::String {
2441 collation: "UTF8_BINARY".to_string()
2442 }
2443 .need_conversion());
2444 assert!(!DataType::Boolean.need_conversion());
2445 assert!(!DataType::Double.need_conversion());
2446
2447 let array_with_date = DataType::Array {
2449 element_type: Box::new(DataType::Date),
2450 contains_null: true,
2451 };
2452 assert!(array_with_date.need_conversion());
2453
2454 let array_without = DataType::Array {
2455 element_type: Box::new(DataType::Integer),
2456 contains_null: true,
2457 };
2458 assert!(!array_without.need_conversion());
2459
2460 let struct_type = DataType::Struct { fields: vec![] };
2462 assert!(struct_type.need_conversion());
2463
2464 let struct_with_primitives = DataType::Struct {
2465 fields: vec![
2466 StructField {
2467 name: "a".to_string(),
2468 data_type: DataType::Integer,
2469 nullable: true,
2470 metadata: BTreeMap::new(),
2471 },
2472 StructField {
2473 name: "b".to_string(),
2474 data_type: DataType::String {
2475 collation: "UTF8_BINARY".to_string(),
2476 },
2477 nullable: true,
2478 metadata: BTreeMap::new(),
2479 },
2480 ],
2481 };
2482 assert!(struct_with_primitives.need_conversion());
2483 }
2484
2485 #[test]
2486 fn test_field_names() {
2487 let struct_type = DataType::Struct {
2488 fields: vec![
2489 StructField {
2490 name: "name".to_string(),
2491 data_type: DataType::String {
2492 collation: "UTF8_BINARY".to_string(),
2493 },
2494 nullable: true,
2495 metadata: BTreeMap::new(),
2496 },
2497 StructField {
2498 name: "age".to_string(),
2499 data_type: DataType::Integer,
2500 nullable: true,
2501 metadata: BTreeMap::new(),
2502 },
2503 ],
2504 };
2505
2506 let names = struct_type.field_names().unwrap();
2507 assert_eq!(names, vec!["name", "age"]);
2508
2509 let names2 = struct_type.names().unwrap();
2511 assert_eq!(names2, vec!["name", "age"]);
2512
2513 let int_type = DataType::Integer;
2515 assert!(int_type.field_names().is_err());
2516 }
2517
2518 #[test]
2519 fn test_struct_add_builder() {
2520 let empty_struct = DataType::Struct { fields: vec![] };
2521
2522 let with_name = empty_struct
2524 .add(
2525 "name",
2526 DataType::String {
2527 collation: "UTF8_BINARY".to_string(),
2528 },
2529 true,
2530 None,
2531 )
2532 .unwrap();
2533
2534 assert_eq!(with_name.field_names().unwrap(), vec!["name"]);
2535
2536 let with_both = with_name.add("age", DataType::Integer, true, None).unwrap();
2538
2539 assert_eq!(with_both.field_names().unwrap(), vec!["name", "age"]);
2540 assert_eq!(with_both.simple_string(), "struct<name:string,age:int>");
2541
2542 let mut metadata = BTreeMap::new();
2544 metadata.insert(
2545 "key".to_string(),
2546 serde_json::Value::String("value".to_string()),
2547 );
2548 let with_metadata = with_both
2549 .add("score", DataType::Double, false, Some(metadata))
2550 .unwrap();
2551
2552 assert_eq!(
2553 with_metadata.field_names().unwrap(),
2554 vec!["name", "age", "score"]
2555 );
2556
2557 let int_type = DataType::Integer;
2559 assert!(int_type
2560 .add(
2561 "field",
2562 DataType::String {
2563 collation: "UTF8_BINARY".to_string(),
2564 },
2565 true,
2566 None
2567 )
2568 .is_err());
2569 }
2570
2571 #[test]
2572 fn test_from_ddl_intervals() {
2573 assert_eq!(
2575 DataType::from_ddl("interval").unwrap(),
2576 DataType::CalendarInterval
2577 );
2578
2579 assert_eq!(
2580 DataType::from_ddl("interval day").unwrap(),
2581 DataType::DayTimeInterval {
2582 start_field: 0,
2583 end_field: 0
2584 }
2585 );
2586
2587 assert_eq!(
2588 DataType::from_ddl("interval year to month").unwrap(),
2589 DataType::YearMonthInterval {
2590 start_field: 0,
2591 end_field: 1
2592 }
2593 );
2594
2595 assert_eq!(
2596 DataType::from_ddl("interval day to second").unwrap(),
2597 DataType::DayTimeInterval {
2598 start_field: 0,
2599 end_field: 3
2600 }
2601 );
2602 }
2603
2604 #[test]
2605 fn test_from_ddl_case_insensitive() {
2606 assert_eq!(
2608 DataType::from_ddl("INT").unwrap(),
2609 DataType::from_ddl("int").unwrap()
2610 );
2611
2612 assert_eq!(
2613 DataType::from_ddl("STRUCT<Name:STRING,Age:INT>")
2614 .unwrap()
2615 .simple_string(),
2616 "struct<Name:string,Age:int>"
2617 );
2618
2619 assert_eq!(
2620 DataType::from_ddl("ARRAY<INT>").unwrap(),
2621 DataType::from_ddl("array<int>").unwrap()
2622 );
2623 }
2624
2625 #[test]
2626 fn test_to_nullable_primitive_types() {
2627 let int_type = DataType::Integer;
2629 assert_eq!(int_type.to_nullable(), DataType::Integer);
2630
2631 let string_type = DataType::String {
2632 collation: "UTF8_BINARY".to_string(),
2633 };
2634 assert_eq!(string_type.to_nullable(), string_type);
2635
2636 let bool_type = DataType::Boolean;
2637 assert_eq!(bool_type.to_nullable(), bool_type);
2638
2639 let double_type = DataType::Double;
2640 assert_eq!(double_type.to_nullable(), double_type);
2641
2642 let date_type = DataType::Date;
2643 assert_eq!(date_type.to_nullable(), date_type);
2644
2645 let timestamp_type = DataType::Timestamp;
2646 assert_eq!(timestamp_type.to_nullable(), timestamp_type);
2647 }
2648
2649 #[test]
2650 fn test_to_nullable_array_type() {
2651 let array_type = DataType::Array {
2652 element_type: Box::new(DataType::Integer),
2653 contains_null: false,
2654 };
2655 let nullable = array_type.to_nullable();
2656
2657 if let DataType::Array {
2658 element_type: _,
2659 contains_null,
2660 } = nullable
2661 {
2662 assert!(contains_null);
2663 } else {
2664 panic!("Expected Array type");
2665 }
2666 }
2667
2668 #[test]
2669 fn test_to_nullable_array_nested() {
2670 let nested_array = DataType::Array {
2671 element_type: Box::new(DataType::Array {
2672 element_type: Box::new(DataType::Integer),
2673 contains_null: false,
2674 }),
2675 contains_null: false,
2676 };
2677 let nullable = nested_array.to_nullable();
2678
2679 if let DataType::Array {
2680 element_type,
2681 contains_null,
2682 } = nullable
2683 {
2684 assert!(contains_null);
2685 if let DataType::Array {
2686 contains_null: inner_null,
2687 ..
2688 } = element_type.as_ref()
2689 {
2690 assert!(inner_null);
2691 } else {
2692 panic!("Expected nested Array type");
2693 }
2694 } else {
2695 panic!("Expected Array type");
2696 }
2697 }
2698
2699 #[test]
2700 fn test_to_nullable_map_type() {
2701 let map_type = DataType::Map {
2702 key_type: Box::new(DataType::String {
2703 collation: "UTF8_BINARY".to_string(),
2704 }),
2705 value_type: Box::new(DataType::Integer),
2706 value_contains_null: false,
2707 };
2708 let nullable = map_type.to_nullable();
2709
2710 if let DataType::Map {
2711 key_type: _,
2712 value_type: _,
2713 value_contains_null,
2714 } = nullable
2715 {
2716 assert!(value_contains_null);
2717 } else {
2718 panic!("Expected Map type");
2719 }
2720 }
2721
2722 #[test]
2723 fn test_to_nullable_struct_type() {
2724 let struct_type = DataType::Struct {
2725 fields: vec![
2726 StructField {
2727 name: "a".to_string(),
2728 data_type: DataType::Integer,
2729 nullable: false,
2730 metadata: BTreeMap::new(),
2731 },
2732 StructField {
2733 name: "b".to_string(),
2734 data_type: DataType::String {
2735 collation: "UTF8_BINARY".to_string(),
2736 },
2737 nullable: false,
2738 metadata: BTreeMap::new(),
2739 },
2740 ],
2741 };
2742 let nullable = struct_type.to_nullable();
2743
2744 if let DataType::Struct { fields } = nullable {
2745 assert_eq!(fields.len(), 2);
2746 assert!(fields[0].nullable);
2747 assert!(fields[1].nullable);
2748 } else {
2749 panic!("Expected Struct type");
2750 }
2751 }
2752
2753 #[test]
2754 fn test_simple_string_all_types() {
2755 assert_eq!(DataType::Null.simple_string(), "void");
2757 assert_eq!(DataType::Boolean.simple_string(), "boolean");
2758 assert_eq!(DataType::Byte.simple_string(), "tinyint");
2759 assert_eq!(DataType::Short.simple_string(), "smallint");
2760 assert_eq!(DataType::Integer.simple_string(), "int");
2761 assert_eq!(DataType::Long.simple_string(), "bigint");
2762 assert_eq!(DataType::Float.simple_string(), "float");
2763 assert_eq!(DataType::Double.simple_string(), "double");
2764 assert_eq!(DataType::Binary.simple_string(), "binary");
2765 assert_eq!(DataType::Date.simple_string(), "date");
2766 assert_eq!(DataType::Timestamp.simple_string(), "timestamp");
2767 assert_eq!(DataType::TimestampNtz.simple_string(), "timestamp_ntz");
2768 assert_eq!(DataType::CalendarInterval.simple_string(), "interval");
2769 assert_eq!(DataType::Variant.simple_string(), "variant");
2770 }
2771
2772 #[test]
2773 fn test_simple_string_with_collation() {
2774 let string_default = DataType::String {
2775 collation: "".to_string(),
2776 };
2777 assert_eq!(string_default.simple_string(), "string");
2778
2779 let string_utf8 = DataType::String {
2780 collation: "UTF8_BINARY".to_string(),
2781 };
2782 assert_eq!(string_utf8.simple_string(), "string");
2783
2784 let string_custom = DataType::String {
2785 collation: "UNICODE".to_string(),
2786 };
2787 assert_eq!(string_custom.simple_string(), "string collate UNICODE");
2788 }
2789
2790 #[test]
2791 fn test_type_name_all_types() {
2792 assert_eq!(DataType::Null.type_name(), "void");
2793 assert_eq!(DataType::Boolean.type_name(), "boolean");
2794 assert_eq!(DataType::Byte.type_name(), "byte");
2795 assert_eq!(DataType::Integer.type_name(), "integer");
2796 assert_eq!(
2797 DataType::String {
2798 collation: "UTF8_BINARY".to_string()
2799 }
2800 .type_name(),
2801 "string"
2802 );
2803 }
2804
2805 #[test]
2806 fn test_from_json_string_types() {
2807 let json_int = serde_json::json!("integer");
2808 let dt = DataType::from_json(&json_int).unwrap();
2809 assert_eq!(dt, DataType::Integer);
2810
2811 let json_string = serde_json::json!("string");
2812 let dt = DataType::from_json(&json_string).unwrap();
2813 assert_eq!(
2814 dt,
2815 DataType::String {
2816 collation: "UTF8_BINARY".to_string()
2817 }
2818 );
2819
2820 let json_timestamp = serde_json::json!("timestamp");
2821 let dt = DataType::from_json(&json_timestamp).unwrap();
2822 assert_eq!(dt, DataType::Timestamp);
2823 }
2824
2825 #[test]
2826 fn test_from_json_str_simple() {
2827 let dt = DataType::from_json_str("\"integer\"").unwrap();
2828 assert_eq!(dt, DataType::Integer);
2829
2830 let dt = DataType::from_json_str("\"double\"").unwrap();
2831 assert_eq!(dt, DataType::Double);
2832
2833 let dt = DataType::from_json_str("\"boolean\"").unwrap();
2834 assert_eq!(dt, DataType::Boolean);
2835 }
2836
2837 #[test]
2838 fn test_from_json_complex_types() {
2839 let json_array = serde_json::json!({
2841 "type": "array",
2842 "elementType": "integer",
2843 "containsNull": true
2844 });
2845 let dt = DataType::from_json(&json_array).unwrap();
2846 match dt {
2847 DataType::Array {
2848 element_type,
2849 contains_null,
2850 } => {
2851 assert_eq!(*element_type, DataType::Integer);
2852 assert!(contains_null);
2853 }
2854 _ => panic!("Expected Array type"),
2855 }
2856
2857 let json_map = serde_json::json!({
2859 "type": "map",
2860 "keyType": "string",
2861 "valueType": "integer",
2862 "valueContainsNull": false
2863 });
2864 let dt = DataType::from_json(&json_map).unwrap();
2865 match dt {
2866 DataType::Map {
2867 key_type,
2868 value_type,
2869 value_contains_null,
2870 } => {
2871 assert_eq!(
2872 *key_type,
2873 DataType::String {
2874 collation: "UTF8_BINARY".to_string()
2875 }
2876 );
2877 assert_eq!(*value_type, DataType::Integer);
2878 assert!(!value_contains_null);
2879 }
2880 _ => panic!("Expected Map type"),
2881 }
2882
2883 let json_struct = serde_json::json!({
2885 "type": "struct",
2886 "fields": [
2887 {
2888 "name": "a",
2889 "type": "integer",
2890 "nullable": true,
2891 "metadata": {}
2892 },
2893 {
2894 "name": "b",
2895 "type": "string",
2896 "nullable": false,
2897 "metadata": {}
2898 }
2899 ]
2900 });
2901 let dt = DataType::from_json(&json_struct).unwrap();
2902 match dt {
2903 DataType::Struct { fields } => {
2904 assert_eq!(fields.len(), 2);
2905 assert_eq!(fields[0].name, "a");
2906 assert_eq!(fields[1].name, "b");
2907 }
2908 _ => panic!("Expected Struct type"),
2909 }
2910 }
2911
2912 #[test]
2913 fn test_from_json_decimal() {
2914 let json_decimal = serde_json::json!("decimal(10,2)");
2915 let dt = DataType::from_json(&json_decimal).unwrap();
2916 match dt {
2917 DataType::Decimal { precision, scale } => {
2918 assert_eq!(precision, 10);
2919 assert_eq!(scale, 2);
2920 }
2921 _ => panic!("Expected Decimal type"),
2922 }
2923 }
2924
2925 #[test]
2926 fn test_from_json_geometry() {
2927 let json_geom = serde_json::json!("geometry(any)");
2928 let dt = DataType::from_json(&json_geom).unwrap();
2929 match dt {
2930 DataType::Geometry { srid } => {
2931 assert_eq!(srid, -1);
2932 }
2933 _ => panic!("Expected Geometry type"),
2934 }
2935 }
2936
2937 #[test]
2938 fn test_json_value_simple_types() {
2939 let int_val = DataType::Integer.json_value();
2940 assert_eq!(int_val, serde_json::json!("integer"));
2941
2942 let string_val = DataType::String {
2943 collation: "UTF8_BINARY".to_string(),
2944 }
2945 .json_value();
2946 assert_eq!(string_val, serde_json::json!("string"));
2947
2948 let bool_val = DataType::Boolean.json_value();
2949 assert_eq!(bool_val, serde_json::json!("boolean"));
2950 }
2951
2952 #[test]
2953 fn test_json_value_complex_types() {
2954 let array_val = DataType::Array {
2955 element_type: Box::new(DataType::Integer),
2956 contains_null: true,
2957 }
2958 .json_value();
2959 assert!(array_val.is_object());
2960 assert_eq!(
2961 array_val.get("type").and_then(|v| v.as_str()),
2962 Some("array")
2963 );
2964 }
2965
2966 #[test]
2967 fn test_to_ddl() {
2968 let struct_type = DataType::Struct {
2969 fields: vec![
2970 StructField {
2971 name: "id".to_string(),
2972 data_type: DataType::Integer,
2973 nullable: false,
2974 metadata: BTreeMap::new(),
2975 },
2976 StructField {
2977 name: "name".to_string(),
2978 data_type: DataType::String {
2979 collation: "UTF8_BINARY".to_string(),
2980 },
2981 nullable: true,
2982 metadata: BTreeMap::new(),
2983 },
2984 ],
2985 };
2986 let ddl = struct_type.to_ddl().unwrap();
2987 assert!(ddl.contains("id"));
2988 assert!(ddl.contains("name"));
2989 assert!(ddl.to_uppercase().contains("INT") || ddl.contains("int"));
2990 assert!(ddl.to_uppercase().contains("STRING") || ddl.contains("string"));
2991 }
2992
2993 #[test]
2994 fn test_tree_string() {
2995 let struct_type = DataType::Struct {
2996 fields: vec![
2997 StructField {
2998 name: "id".to_string(),
2999 data_type: DataType::Integer,
3000 nullable: false,
3001 metadata: BTreeMap::new(),
3002 },
3003 StructField {
3004 name: "nested".to_string(),
3005 data_type: DataType::Struct {
3006 fields: vec![StructField {
3007 name: "x".to_string(),
3008 data_type: DataType::Double,
3009 nullable: true,
3010 metadata: BTreeMap::new(),
3011 }],
3012 },
3013 nullable: true,
3014 metadata: BTreeMap::new(),
3015 },
3016 ],
3017 };
3018 let tree = struct_type.tree_string().unwrap();
3019 assert!(tree.contains("id"));
3020 assert!(tree.contains("nested"));
3021 assert!(tree.contains("x"));
3022 }
3023
3024 #[test]
3025 fn test_to_proto_simple_types() {
3026 let int_proto = DataType::Integer.to_proto();
3027 assert!(int_proto.kind.is_some());
3028
3029 let string_proto = DataType::String {
3030 collation: "UTF8_BINARY".to_string(),
3031 }
3032 .to_proto();
3033 assert!(string_proto.kind.is_some());
3034
3035 let bool_proto = DataType::Boolean.to_proto();
3036 assert!(bool_proto.kind.is_some());
3037 }
3038
3039 #[test]
3040 fn test_to_proto_array_type() {
3041 let array_type = DataType::Array {
3042 element_type: Box::new(DataType::Integer),
3043 contains_null: false,
3044 };
3045 let proto = array_type.to_proto();
3046 assert!(proto.kind.is_some());
3047 }
3048
3049 #[test]
3050 fn test_to_proto_map_type() {
3051 let map_type = DataType::Map {
3052 key_type: Box::new(DataType::String {
3053 collation: "UTF8_BINARY".to_string(),
3054 }),
3055 value_type: Box::new(DataType::Integer),
3056 value_contains_null: true,
3057 };
3058 let proto = map_type.to_proto();
3059 assert!(proto.kind.is_some());
3060 }
3061
3062 #[test]
3063 fn test_to_proto_struct_type() {
3064 let struct_type = DataType::Struct {
3065 fields: vec![
3066 StructField {
3067 name: "a".to_string(),
3068 data_type: DataType::Integer,
3069 nullable: true,
3070 metadata: BTreeMap::new(),
3071 },
3072 StructField {
3073 name: "b".to_string(),
3074 data_type: DataType::String {
3075 collation: "UTF8_BINARY".to_string(),
3076 },
3077 nullable: false,
3078 metadata: BTreeMap::new(),
3079 },
3080 ],
3081 };
3082 let proto = struct_type.to_proto();
3083 assert!(proto.kind.is_some());
3084 }
3085
3086 #[test]
3087 fn test_display_trait() {
3088 let int_type = DataType::Integer;
3089 let display_str = format!("{}", int_type);
3090 assert_eq!(display_str, "int");
3091
3092 let array_type = DataType::Array {
3093 element_type: Box::new(DataType::Integer),
3094 contains_null: true,
3095 };
3096 let display_str = format!("{}", array_type);
3097 assert_eq!(display_str, "array<int>");
3098 }
3099
3100 #[test]
3101 fn test_interval_year_month() {
3102 let ym = DataType::YearMonthInterval {
3103 start_field: 0,
3104 end_field: 1,
3105 };
3106 assert_eq!(ym.simple_string(), "interval year to month");
3107 }
3108
3109 #[test]
3110 fn test_interval_day_time() {
3111 let dt = DataType::DayTimeInterval {
3112 start_field: 0,
3113 end_field: 3,
3114 };
3115 assert_eq!(dt.simple_string(), "interval day to second");
3116 }
3117
3118 #[test]
3119 fn test_udt_type() {
3120 let udt = DataType::Udt {
3121 type_str: "com.example.MyUDT".to_string(),
3122 jvm_class: Some("com.example.MyUDT".to_string()),
3123 python_class: None,
3124 serialized_python_class: None,
3125 sql_type: None,
3126 };
3127 assert_eq!(udt.simple_string(), "udt");
3128 assert_eq!(udt.type_name(), "udt");
3129 }
3130
3131 #[test]
3132 fn test_char_varchar() {
3133 let char_type = DataType::Char { length: 50 };
3134 assert_eq!(char_type.simple_string(), "char(50)");
3135
3136 let varchar_type = DataType::Varchar { length: 100 };
3137 assert_eq!(varchar_type.simple_string(), "varchar(100)");
3138 }
3139}