1mod parser;
82
83pub use parser::{
84 parse_type_name,
85 TypeAst,
86 TypeMeta,
87};
88
89use std::sync::Arc;
90
91pub trait ToType {
107 fn to_type() -> Type;
109}
110
111impl ToType for i8 {
113 fn to_type() -> Type {
114 Type::int8()
115 }
116}
117
118impl ToType for i16 {
119 fn to_type() -> Type {
120 Type::int16()
121 }
122}
123
124impl ToType for i32 {
125 fn to_type() -> Type {
126 Type::int32()
127 }
128}
129
130impl ToType for i64 {
131 fn to_type() -> Type {
132 Type::int64()
133 }
134}
135
136impl ToType for i128 {
137 fn to_type() -> Type {
138 Type::int128()
139 }
140}
141
142impl ToType for u8 {
143 fn to_type() -> Type {
144 Type::uint8()
145 }
146}
147
148impl ToType for u16 {
149 fn to_type() -> Type {
150 Type::uint16()
151 }
152}
153
154impl ToType for u32 {
155 fn to_type() -> Type {
156 Type::uint32()
157 }
158}
159
160impl ToType for u64 {
161 fn to_type() -> Type {
162 Type::uint64()
163 }
164}
165
166impl ToType for u128 {
167 fn to_type() -> Type {
168 Type::uint128()
169 }
170}
171
172impl ToType for f32 {
173 fn to_type() -> Type {
174 Type::float32()
175 }
176}
177
178impl ToType for f64 {
179 fn to_type() -> Type {
180 Type::float64()
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
190pub enum TypeCode {
191 Void = 0,
193 Int8,
195 Int16,
197 Int32,
199 Int64,
201 UInt8,
203 UInt16,
205 UInt32,
207 UInt64,
209 Float32,
211 Float64,
213 String,
215 FixedString,
217 DateTime,
219 Date,
221 Array,
223 Nullable,
225 Tuple,
227 Enum8,
229 Enum16,
231 UUID,
233 IPv4,
235 IPv6,
237 Int128,
239 UInt128,
241 Decimal,
243 Decimal32,
245 Decimal64,
247 Decimal128,
249 LowCardinality,
251 DateTime64,
254 Date32,
256 Map,
258 Point,
260 Ring,
262 Polygon,
264 MultiPolygon,
266}
267
268impl TypeCode {
269 pub fn name(&self) -> &'static str {
271 match self {
272 TypeCode::Void => "Void",
273 TypeCode::Int8 => "Int8",
274 TypeCode::Int16 => "Int16",
275 TypeCode::Int32 => "Int32",
276 TypeCode::Int64 => "Int64",
277 TypeCode::UInt8 => "UInt8",
278 TypeCode::UInt16 => "UInt16",
279 TypeCode::UInt32 => "UInt32",
280 TypeCode::UInt64 => "UInt64",
281 TypeCode::Float32 => "Float32",
282 TypeCode::Float64 => "Float64",
283 TypeCode::String => "String",
284 TypeCode::FixedString => "FixedString",
285 TypeCode::DateTime => "DateTime",
286 TypeCode::Date => "Date",
287 TypeCode::Array => "Array",
288 TypeCode::Nullable => "Nullable",
289 TypeCode::Tuple => "Tuple",
290 TypeCode::Enum8 => "Enum8",
291 TypeCode::Enum16 => "Enum16",
292 TypeCode::UUID => "UUID",
293 TypeCode::IPv4 => "IPv4",
294 TypeCode::IPv6 => "IPv6",
295 TypeCode::Int128 => "Int128",
296 TypeCode::UInt128 => "UInt128",
297 TypeCode::Decimal => "Decimal",
298 TypeCode::Decimal32 => "Decimal32",
299 TypeCode::Decimal64 => "Decimal64",
300 TypeCode::Decimal128 => "Decimal128",
301 TypeCode::LowCardinality => "LowCardinality",
302 TypeCode::DateTime64 => "DateTime64",
303 TypeCode::Date32 => "Date32",
304 TypeCode::Map => "Map",
305 TypeCode::Point => "Point",
306 TypeCode::Ring => "Ring",
307 TypeCode::Polygon => "Polygon",
308 TypeCode::MultiPolygon => "MultiPolygon",
309 }
310 }
311}
312
313#[derive(Debug, Clone, PartialEq, Eq)]
315pub struct EnumItem {
316 pub name: String,
318 pub value: i16,
320}
321
322#[derive(Debug, Clone)]
324pub enum Type {
325 Simple(TypeCode),
327 FixedString {
329 size: usize,
331 },
332 DateTime {
334 timezone: Option<String>,
336 },
337 DateTime64 {
340 precision: usize,
342 timezone: Option<String>,
344 },
345 Decimal {
347 precision: usize,
349 scale: usize,
351 },
352 Enum8 {
354 items: Vec<EnumItem>,
356 },
357 Enum16 {
359 items: Vec<EnumItem>,
361 },
362 Array {
364 item_type: Box<Type>,
366 },
367 Nullable {
369 nested_type: Box<Type>,
371 },
372 Tuple {
374 item_types: Vec<Type>,
376 },
377 LowCardinality {
379 nested_type: Box<Type>,
381 },
382 Map {
384 key_type: Box<Type>,
386 value_type: Box<Type>,
388 },
389}
390
391impl Type {
392 pub fn code(&self) -> TypeCode {
394 match self {
395 Type::Simple(code) => *code,
396 Type::FixedString { .. } => TypeCode::FixedString,
397 Type::DateTime { .. } => TypeCode::DateTime,
398 Type::DateTime64 { .. } => TypeCode::DateTime64,
399 Type::Decimal { .. } => TypeCode::Decimal,
400 Type::Enum8 { .. } => TypeCode::Enum8,
401 Type::Enum16 { .. } => TypeCode::Enum16,
402 Type::Array { .. } => TypeCode::Array,
403 Type::Nullable { .. } => TypeCode::Nullable,
404 Type::Tuple { .. } => TypeCode::Tuple,
405 Type::LowCardinality { .. } => TypeCode::LowCardinality,
406 Type::Map { .. } => TypeCode::Map,
407 }
408 }
409
410 pub fn name(&self) -> String {
412 match self {
413 Type::Simple(code) => code.name().to_string(),
414 Type::FixedString { size } => format!("FixedString({})", size),
415 Type::DateTime { timezone: None } => "DateTime".to_string(),
416 Type::DateTime { timezone: Some(tz) } => {
417 format!("DateTime('{}')", tz)
418 }
419 Type::DateTime64 { precision, timezone: None } => {
420 format!("DateTime64({})", precision)
421 }
422 Type::DateTime64 { precision, timezone: Some(tz) } => {
423 format!("DateTime64({}, '{}')", precision, tz)
424 }
425 Type::Decimal { precision, scale } => {
426 format!("Decimal({}, {})", precision, scale)
427 }
428 Type::Enum8 { items } => {
429 format!("Enum8({})", format_enum_items(items))
430 }
431 Type::Enum16 { items } => {
432 format!("Enum16({})", format_enum_items(items))
433 }
434 Type::Array { item_type } => {
435 format!("Array({})", item_type.name())
436 }
437 Type::Nullable { nested_type } => {
438 format!("Nullable({})", nested_type.name())
439 }
440 Type::Tuple { item_types } => {
441 let types: Vec<String> =
442 item_types.iter().map(|t| t.name()).collect();
443 format!("Tuple({})", types.join(", "))
444 }
445 Type::LowCardinality { nested_type } => {
446 format!("LowCardinality({})", nested_type.name())
447 }
448 Type::Map { key_type, value_type } => {
449 format!("Map({}, {})", key_type.name(), value_type.name())
450 }
451 }
452 }
453
454 pub fn storage_size_bytes(&self) -> Option<usize> {
470 match self {
471 Type::Simple(code) => match code {
472 TypeCode::Int8 | TypeCode::UInt8 => Some(1),
473 TypeCode::Int16 | TypeCode::UInt16 => Some(2),
474 TypeCode::Int32 | TypeCode::UInt32 | TypeCode::Float32 => {
475 Some(4)
476 }
477 TypeCode::Int64 | TypeCode::UInt64 | TypeCode::Float64 => {
478 Some(8)
479 }
480 TypeCode::Int128 | TypeCode::UInt128 | TypeCode::UUID => {
481 Some(16)
482 }
483 TypeCode::Date => Some(2), TypeCode::Date32 => Some(4), TypeCode::IPv4 => Some(4),
486 TypeCode::IPv6 => Some(16),
487 TypeCode::Point => Some(16), TypeCode::String => None, _ => None,
490 },
491 Type::FixedString { size } => Some(*size),
492 Type::DateTime { .. } => Some(4), Type::DateTime64 { .. } => Some(8), Type::Enum8 { .. } => Some(1), Type::Enum16 { .. } => Some(2), Type::Decimal { precision, .. } => {
497 if *precision <= 9 {
499 Some(4) } else if *precision <= 18 {
501 Some(8) } else {
503 Some(16) }
505 }
506 Type::Array { .. }
508 | Type::Nullable { .. }
509 | Type::Tuple { .. }
510 | Type::LowCardinality { .. }
511 | Type::Map { .. } => None,
512 }
513 }
514
515 pub fn int8() -> Self {
517 Type::Simple(TypeCode::Int8)
518 }
519
520 pub fn int16() -> Self {
522 Type::Simple(TypeCode::Int16)
523 }
524
525 pub fn int32() -> Self {
527 Type::Simple(TypeCode::Int32)
528 }
529
530 pub fn int64() -> Self {
532 Type::Simple(TypeCode::Int64)
533 }
534
535 pub fn int128() -> Self {
537 Type::Simple(TypeCode::Int128)
538 }
539
540 pub fn uint8() -> Self {
542 Type::Simple(TypeCode::UInt8)
543 }
544
545 pub fn uint16() -> Self {
547 Type::Simple(TypeCode::UInt16)
548 }
549
550 pub fn uint32() -> Self {
552 Type::Simple(TypeCode::UInt32)
553 }
554
555 pub fn uint64() -> Self {
557 Type::Simple(TypeCode::UInt64)
558 }
559
560 pub fn uint128() -> Self {
562 Type::Simple(TypeCode::UInt128)
563 }
564
565 pub fn float32() -> Self {
567 Type::Simple(TypeCode::Float32)
568 }
569
570 pub fn float64() -> Self {
572 Type::Simple(TypeCode::Float64)
573 }
574
575 pub fn string() -> Self {
577 Type::Simple(TypeCode::String)
578 }
579
580 pub fn fixed_string(size: usize) -> Self {
582 Type::FixedString { size }
583 }
584
585 pub fn date() -> Self {
587 Type::Simple(TypeCode::Date)
588 }
589
590 pub fn date32() -> Self {
592 Type::Simple(TypeCode::Date32)
593 }
594
595 pub fn datetime(timezone: Option<String>) -> Self {
597 Type::DateTime { timezone }
598 }
599
600 pub fn datetime64(precision: usize, timezone: Option<String>) -> Self {
603 Type::DateTime64 { precision, timezone }
604 }
605
606 pub fn decimal(precision: usize, scale: usize) -> Self {
608 Type::Decimal { precision, scale }
609 }
610
611 pub fn ipv4() -> Self {
613 Type::Simple(TypeCode::IPv4)
614 }
615
616 pub fn ipv6() -> Self {
618 Type::Simple(TypeCode::IPv6)
619 }
620
621 pub fn uuid() -> Self {
623 Type::Simple(TypeCode::UUID)
624 }
625
626 pub fn array(item_type: Type) -> Self {
628 Type::Array { item_type: Box::new(item_type) }
629 }
630
631 pub fn nullable(nested_type: Type) -> Self {
633 Type::Nullable { nested_type: Box::new(nested_type) }
634 }
635
636 pub fn tuple(item_types: Vec<Type>) -> Self {
638 Type::Tuple { item_types }
639 }
640
641 pub fn enum8(items: Vec<EnumItem>) -> Self {
643 Type::Enum8 { items }
644 }
645
646 pub fn enum16(items: Vec<EnumItem>) -> Self {
648 Type::Enum16 { items }
649 }
650
651 pub fn low_cardinality(nested_type: Type) -> Self {
653 Type::LowCardinality { nested_type: Box::new(nested_type) }
654 }
655
656 pub fn map(key_type: Type, value_type: Type) -> Self {
658 Type::Map {
659 key_type: Box::new(key_type),
660 value_type: Box::new(value_type),
661 }
662 }
663
664 pub fn has_enum_value(&self, value: i16) -> bool {
667 match self {
668 Type::Enum8 { items } => {
669 items.iter().any(|item| item.value == value)
670 }
671 Type::Enum16 { items } => {
672 items.iter().any(|item| item.value == value)
673 }
674 _ => false,
675 }
676 }
677
678 pub fn has_enum_name(&self, name: &str) -> bool {
680 match self {
681 Type::Enum8 { items } => {
682 items.iter().any(|item| item.name == name)
683 }
684 Type::Enum16 { items } => {
685 items.iter().any(|item| item.name == name)
686 }
687 _ => false,
688 }
689 }
690
691 pub fn get_enum_name(&self, value: i16) -> Option<&str> {
694 match self {
695 Type::Enum8 { items } => items
696 .iter()
697 .find(|item| item.value == value)
698 .map(|item| item.name.as_str()),
699 Type::Enum16 { items } => items
700 .iter()
701 .find(|item| item.value == value)
702 .map(|item| item.name.as_str()),
703 _ => None,
704 }
705 }
706
707 pub fn get_enum_value(&self, name: &str) -> Option<i16> {
710 match self {
711 Type::Enum8 { items } => items
712 .iter()
713 .find(|item| item.name == name)
714 .map(|item| item.value),
715 Type::Enum16 { items } => items
716 .iter()
717 .find(|item| item.name == name)
718 .map(|item| item.value),
719 _ => None,
720 }
721 }
722
723 pub fn enum_items(&self) -> Option<&[EnumItem]> {
726 match self {
727 Type::Enum8 { items } => Some(items),
728 Type::Enum16 { items } => Some(items),
729 _ => None,
730 }
731 }
732
733 pub fn point() -> Self {
735 Type::Simple(TypeCode::Point)
736 }
737
738 pub fn ring() -> Self {
740 Type::Simple(TypeCode::Ring)
741 }
742
743 pub fn polygon() -> Self {
745 Type::Simple(TypeCode::Polygon)
746 }
747
748 pub fn multi_polygon() -> Self {
750 Type::Simple(TypeCode::MultiPolygon)
751 }
752
753 pub fn nothing() -> Self {
755 Type::Simple(TypeCode::Void)
756 }
757
758 pub fn for_rust_type<T: ToType>() -> Self {
771 T::to_type()
772 }
773
774 pub fn from_ast(ast: &TypeAst) -> crate::Result<Self> {
777 match ast.meta {
778 TypeMeta::Terminal => {
779 match ast.code {
781 TypeCode::Void
782 | TypeCode::Int8
783 | TypeCode::Int16
784 | TypeCode::Int32
785 | TypeCode::Int64
786 | TypeCode::Int128
787 | TypeCode::UInt8
788 | TypeCode::UInt16
789 | TypeCode::UInt32
790 | TypeCode::UInt64
791 | TypeCode::UInt128
792 | TypeCode::Float32
793 | TypeCode::Float64
794 | TypeCode::String
795 | TypeCode::Date
796 | TypeCode::Date32
797 | TypeCode::UUID
798 | TypeCode::IPv4
799 | TypeCode::IPv6
800 | TypeCode::Point
801 | TypeCode::Ring
802 | TypeCode::Polygon
803 | TypeCode::MultiPolygon => Ok(Type::Simple(ast.code)),
804
805 TypeCode::FixedString => {
806 if ast.elements.is_empty() {
808 return Err(crate::Error::Protocol(
809 "FixedString requires size parameter"
810 .to_string(),
811 ));
812 }
813 let size = ast.elements[0].value as usize;
814 Ok(Type::FixedString { size })
815 }
816
817 TypeCode::DateTime => {
818 if ast.elements.is_empty() {
820 Ok(Type::DateTime { timezone: None })
821 } else {
822 let timezone =
823 Some(ast.elements[0].value_string.clone());
824 Ok(Type::DateTime { timezone })
825 }
826 }
827
828 TypeCode::DateTime64 => {
829 if ast.elements.is_empty() {
831 return Err(crate::Error::Protocol(
832 "DateTime64 requires precision parameter"
833 .to_string(),
834 ));
835 }
836 let precision = ast.elements[0].value as usize;
837 let timezone = if ast.elements.len() > 1 {
838 Some(ast.elements[1].value_string.clone())
839 } else {
840 None
841 };
842 Ok(Type::DateTime64 { precision, timezone })
843 }
844
845 TypeCode::Decimal
846 | TypeCode::Decimal32
847 | TypeCode::Decimal64
848 | TypeCode::Decimal128 => {
849 if ast.elements.len() >= 2 {
850 let precision = ast.elements[0].value as usize;
851 let scale = ast.elements[1].value as usize;
852 Ok(Type::Decimal { precision, scale })
853 } else if ast.elements.len() == 1 {
854 let scale = ast.elements[0].value as usize;
857 let precision = match ast.code {
858 TypeCode::Decimal32 => 9,
859 TypeCode::Decimal64 => 18,
860 TypeCode::Decimal128 => 38,
861 _ => scale,
862 };
863 Ok(Type::Decimal { precision, scale })
864 } else {
865 Err(crate::Error::Protocol(
866 "Decimal requires precision and scale parameters".to_string(),
867 ))
868 }
869 }
870
871 _ => Err(crate::Error::Protocol(format!(
872 "Unsupported terminal type: {:?}",
873 ast.code
874 ))),
875 }
876 }
877
878 TypeMeta::Array => {
879 if ast.elements.is_empty() {
880 return Err(crate::Error::Protocol(
881 "Array requires element type".to_string(),
882 ));
883 }
884 let item_type = Type::from_ast(&ast.elements[0])?;
885 Ok(Type::Array { item_type: Box::new(item_type) })
886 }
887
888 TypeMeta::Nullable => {
889 if ast.elements.is_empty() {
890 return Err(crate::Error::Protocol(
891 "Nullable requires nested type".to_string(),
892 ));
893 }
894 let nested_type = Type::from_ast(&ast.elements[0])?;
895 Ok(Type::Nullable { nested_type: Box::new(nested_type) })
896 }
897
898 TypeMeta::Tuple => {
899 let mut item_types = Vec::new();
900 for elem in &ast.elements {
901 item_types.push(Type::from_ast(elem)?);
902 }
903 Ok(Type::Tuple { item_types })
904 }
905
906 TypeMeta::Enum => {
907 let mut items = Vec::new();
910 for i in (0..ast.elements.len()).step_by(2) {
911 if i + 1 >= ast.elements.len() {
912 break;
913 }
914 let name = ast.elements[i].value_string.clone();
915 let value = ast.elements[i + 1].value as i16;
916 items.push(EnumItem { name, value });
917 }
918
919 match ast.code {
920 TypeCode::Enum8 => Ok(Type::Enum8 { items }),
921 TypeCode::Enum16 => Ok(Type::Enum16 { items }),
922 _ => Err(crate::Error::Protocol(format!(
923 "Invalid enum type code: {:?}",
924 ast.code
925 ))),
926 }
927 }
928
929 TypeMeta::LowCardinality => {
930 if ast.elements.is_empty() {
931 return Err(crate::Error::Protocol(
932 "LowCardinality requires nested type".to_string(),
933 ));
934 }
935 let nested_type = Type::from_ast(&ast.elements[0])?;
936 Ok(Type::LowCardinality { nested_type: Box::new(nested_type) })
937 }
938
939 TypeMeta::Map => {
940 if ast.elements.len() != 2 {
941 return Err(crate::Error::Protocol(
942 "Map requires exactly 2 type parameters".to_string(),
943 ));
944 }
945 let key_type = Type::from_ast(&ast.elements[0])?;
946 let value_type = Type::from_ast(&ast.elements[1])?;
947 Ok(Type::Map {
948 key_type: Box::new(key_type),
949 value_type: Box::new(value_type),
950 })
951 }
952
953 TypeMeta::SimpleAggregateFunction => {
954 if ast.elements.is_empty() {
957 return Err(crate::Error::Protocol(
958 "SimpleAggregateFunction requires type parameter"
959 .to_string(),
960 ));
961 }
962 let type_elem = ast.elements.last().unwrap();
963 Type::from_ast(type_elem)
964 }
965
966 TypeMeta::Number
967 | TypeMeta::String
968 | TypeMeta::Assign
969 | TypeMeta::Null => {
970 Err(crate::Error::Protocol(format!(
972 "Cannot convert AST meta {:?} to Type",
973 ast.meta
974 )))
975 }
976 }
977 }
978
979 pub fn parse(type_str: &str) -> crate::Result<Self> {
983 let ast = parse_type_name(type_str)?;
984 Type::from_ast(&ast)
985 }
986
987 #[allow(dead_code)]
990 fn parse_old(type_str: &str) -> crate::Result<Self> {
991 let type_str = type_str.trim();
992
993 if type_str.is_empty() {
995 return Err(crate::Error::Protocol(
996 "Empty type string".to_string(),
997 ));
998 }
999
1000 if let Some(paren_pos) = type_str.find('(') {
1002 if !type_str.ends_with(')') {
1003 return Err(crate::Error::Protocol(format!(
1004 "Mismatched parentheses in type: {}",
1005 type_str
1006 )));
1007 }
1008
1009 let type_name = &type_str[..paren_pos];
1010 let params_str = &type_str[paren_pos + 1..type_str.len() - 1];
1011
1012 return match type_name {
1013 "Nullable" => Ok(Type::nullable(Type::parse(params_str)?)),
1014 "Array" => Ok(Type::array(Type::parse(params_str)?)),
1015 "FixedString" => {
1016 let size = params_str.parse::<usize>().map_err(|_| {
1017 crate::Error::Protocol(format!(
1018 "Invalid FixedString size: {}",
1019 params_str
1020 ))
1021 })?;
1022 Ok(Type::fixed_string(size))
1023 }
1024 "DateTime" => {
1025 let tz = parse_string_literal(params_str)?;
1027 Ok(Type::datetime(Some(tz)))
1028 }
1029 "DateTime64" => {
1030 let params = parse_comma_separated(params_str)?;
1032 if params.is_empty() {
1033 return Err(crate::Error::Protocol(
1034 "DateTime64 requires precision parameter"
1035 .to_string(),
1036 ));
1037 }
1038 let precision =
1039 params[0].parse::<usize>().map_err(|_| {
1040 crate::Error::Protocol(format!(
1041 "Invalid DateTime64 precision: {}",
1042 params[0]
1043 ))
1044 })?;
1045 let timezone = if params.len() > 1 {
1046 Some(parse_string_literal(¶ms[1])?)
1047 } else {
1048 None
1049 };
1050 Ok(Type::datetime64(precision, timezone))
1051 }
1052 "Decimal" => {
1053 let params = parse_comma_separated(params_str)?;
1055 if params.len() != 2 {
1056 return Err(crate::Error::Protocol(format!(
1057 "Decimal requires 2 parameters, got {}",
1058 params.len()
1059 )));
1060 }
1061 let precision =
1062 params[0].parse::<usize>().map_err(|_| {
1063 crate::Error::Protocol(format!(
1064 "Invalid Decimal precision: {}",
1065 params[0]
1066 ))
1067 })?;
1068 let scale = params[1].parse::<usize>().map_err(|_| {
1069 crate::Error::Protocol(format!(
1070 "Invalid Decimal scale: {}",
1071 params[1]
1072 ))
1073 })?;
1074 Ok(Type::decimal(precision, scale))
1075 }
1076 "Decimal32" | "Decimal64" | "Decimal128" => {
1077 let precision =
1080 params_str.parse::<usize>().map_err(|_| {
1081 crate::Error::Protocol(format!(
1082 "Invalid {} precision: {}",
1083 type_name, params_str
1084 ))
1085 })?;
1086 Ok(Type::decimal(precision, 0))
1087 }
1088 "Enum8" => {
1089 let items = parse_enum_items(params_str)?;
1091 Ok(Type::enum8(items))
1092 }
1093 "Enum16" => {
1094 let items = parse_enum_items(params_str)?;
1096 Ok(Type::enum16(items))
1097 }
1098 "LowCardinality" => {
1099 Ok(Type::low_cardinality(Type::parse(params_str)?))
1100 }
1101 "Map" => {
1102 let params = parse_comma_separated(params_str)?;
1104 if params.len() != 2 {
1105 return Err(crate::Error::Protocol(format!(
1106 "Map requires 2 type parameters, got {}",
1107 params.len()
1108 )));
1109 }
1110 let key_type = Type::parse(¶ms[0])?;
1111 let value_type = Type::parse(¶ms[1])?;
1112 Ok(Type::map(key_type, value_type))
1113 }
1114 "Tuple" => {
1115 let params = parse_comma_separated(params_str)?;
1117 if params.is_empty() {
1118 return Err(crate::Error::Protocol(
1119 "Tuple requires at least one type parameter"
1120 .to_string(),
1121 ));
1122 }
1123 let mut item_types = Vec::new();
1124 for param in params {
1125 item_types.push(Type::parse(¶m)?);
1126 }
1127 Ok(Type::tuple(item_types))
1128 }
1129 "SimpleAggregateFunction" => {
1130 let params = parse_comma_separated(params_str)?;
1133 if params.len() < 2 {
1134 return Err(crate::Error::Protocol("SimpleAggregateFunction requires at least 2 parameters".to_string()));
1135 }
1136 Type::parse(¶ms[1])
1139 }
1140 "AggregateFunction" => {
1141 Err(crate::Error::Protocol(
1148 "AggregateFunction columns are not supported. Use SimpleAggregateFunction or finalize the aggregation with -State combinators.".to_string()
1149 ))
1150 }
1151 _ => Err(crate::Error::Protocol(format!(
1152 "Unknown parametric type: {}",
1153 type_name
1154 ))),
1155 };
1156 }
1157
1158 match type_str {
1160 "UInt8" => Ok(Type::uint8()),
1161 "UInt16" => Ok(Type::uint16()),
1162 "UInt32" => Ok(Type::uint32()),
1163 "UInt64" => Ok(Type::uint64()),
1164 "UInt128" => Ok(Type::Simple(TypeCode::UInt128)),
1165 "Int8" => Ok(Type::int8()),
1166 "Int16" => Ok(Type::int16()),
1167 "Int32" => Ok(Type::int32()),
1168 "Int64" => Ok(Type::int64()),
1169 "Int128" => Ok(Type::Simple(TypeCode::Int128)),
1170 "Float32" => Ok(Type::float32()),
1171 "Float64" => Ok(Type::float64()),
1172 "String" => Ok(Type::string()),
1173 "Date" => Ok(Type::date()),
1174 "Date32" => Ok(Type::date32()),
1175 "DateTime" => Ok(Type::datetime(None)),
1176 "UUID" => Ok(Type::uuid()),
1177 "IPv4" => Ok(Type::ipv4()),
1178 "IPv6" => Ok(Type::ipv6()),
1179 "Bool" => Ok(Type::uint8()), "Nothing" => Ok(Type::Simple(TypeCode::Void)), "Point" => Ok(Type::point()), "Ring" => Ok(Type::ring()), "Polygon" => Ok(Type::polygon()), "MultiPolygon" => Ok(Type::multi_polygon()), _ => Err(crate::Error::Protocol(format!(
1186 "Unknown type: {}",
1187 type_str
1188 ))),
1189 }
1190 }
1191}
1192
1193fn parse_string_literal(s: &str) -> crate::Result<String> {
1197 let s = s.trim();
1198 if (s.starts_with('\'') && s.ends_with('\''))
1199 || (s.starts_with('"') && s.ends_with('"'))
1200 {
1201 Ok(s[1..s.len() - 1].to_string())
1202 } else {
1203 Err(crate::Error::Protocol(format!(
1204 "Expected quoted string, got: {}",
1205 s
1206 )))
1207 }
1208}
1209
1210fn parse_comma_separated(s: &str) -> crate::Result<Vec<String>> {
1214 let mut params = Vec::new();
1215 let mut current = String::new();
1216 let mut paren_depth = 0;
1217 let mut in_quotes = false;
1218 let mut quote_char = '\0';
1219
1220 for ch in s.chars() {
1221 match ch {
1222 '\'' | '"' if !in_quotes => {
1223 in_quotes = true;
1224 quote_char = ch;
1225 current.push(ch);
1226 }
1227 ch if in_quotes && ch == quote_char => {
1228 in_quotes = false;
1229 current.push(ch);
1230 }
1231 '(' if !in_quotes => {
1232 paren_depth += 1;
1233 current.push(ch);
1234 }
1235 ')' if !in_quotes => {
1236 paren_depth -= 1;
1237 current.push(ch);
1238 }
1239 ',' if !in_quotes && paren_depth == 0 => {
1240 params.push(current.trim().to_string());
1241 current.clear();
1242 }
1243 _ => {
1244 current.push(ch);
1245 }
1246 }
1247 }
1248
1249 if !current.trim().is_empty() {
1250 params.push(current.trim().to_string());
1251 }
1252
1253 Ok(params)
1254}
1255
1256fn parse_enum_items(s: &str) -> crate::Result<Vec<EnumItem>> {
1258 let mut items = Vec::new();
1259 let parts = parse_comma_separated(s)?;
1260
1261 for part in parts {
1262 let eq_parts: Vec<&str> = part.split('=').collect();
1264 if eq_parts.len() != 2 {
1265 return Err(crate::Error::Protocol(format!(
1266 "Invalid enum item format (expected 'name' = value): {}",
1267 part
1268 )));
1269 }
1270
1271 let name = parse_string_literal(eq_parts[0].trim())?;
1272 let value = eq_parts[1].trim().parse::<i16>().map_err(|_| {
1273 crate::Error::Protocol(format!(
1274 "Invalid enum value: {}",
1275 eq_parts[1]
1276 ))
1277 })?;
1278
1279 items.push(EnumItem { name, value });
1280 }
1281
1282 Ok(items)
1283}
1284
1285impl PartialEq for Type {
1286 fn eq(&self, other: &Self) -> bool {
1287 match (self, other) {
1288 (Type::Simple(a), Type::Simple(b)) => a == b,
1289 (Type::FixedString { size: a }, Type::FixedString { size: b }) => {
1290 a == b
1291 }
1292 (
1293 Type::DateTime { timezone: tz_a },
1294 Type::DateTime { timezone: tz_b },
1295 ) => tz_a == tz_b,
1296 (
1297 Type::DateTime64 { precision: p_a, timezone: tz_a },
1298 Type::DateTime64 { precision: p_b, timezone: tz_b },
1299 ) => p_a == p_b && tz_a == tz_b,
1300 (
1301 Type::Decimal { precision: p_a, scale: s_a },
1302 Type::Decimal { precision: p_b, scale: s_b },
1303 ) => p_a == p_b && s_a == s_b,
1304 (Type::Enum8 { items: a }, Type::Enum8 { items: b }) => a == b,
1305 (Type::Enum16 { items: a }, Type::Enum16 { items: b }) => a == b,
1306 (Type::Array { item_type: a }, Type::Array { item_type: b }) => {
1307 a == b
1308 }
1309 (
1310 Type::Nullable { nested_type: a },
1311 Type::Nullable { nested_type: b },
1312 ) => a == b,
1313 (Type::Tuple { item_types: a }, Type::Tuple { item_types: b }) => {
1314 a == b
1315 }
1316 (
1317 Type::LowCardinality { nested_type: a },
1318 Type::LowCardinality { nested_type: b },
1319 ) => a == b,
1320 (
1321 Type::Map { key_type: k_a, value_type: v_a },
1322 Type::Map { key_type: k_b, value_type: v_b },
1323 ) => k_a == k_b && v_a == v_b,
1324 _ => false,
1325 }
1326 }
1327}
1328
1329impl Eq for Type {}
1330
1331pub type TypeRef = Arc<Type>;
1333
1334fn format_enum_items(items: &[EnumItem]) -> String {
1335 let formatted: Vec<String> = items
1336 .iter()
1337 .map(|item| format!("'{}' = {}", item.name, item.value))
1338 .collect();
1339 formatted.join(", ")
1340}
1341
1342#[cfg(test)]
1343#[cfg_attr(coverage_nightly, coverage(off))]
1344mod tests {
1345 use super::*;
1346
1347 #[test]
1348 fn test_type_code_name() {
1349 assert_eq!(TypeCode::Int32.name(), "Int32");
1350 assert_eq!(TypeCode::String.name(), "String");
1351 assert_eq!(TypeCode::DateTime.name(), "DateTime");
1352 }
1353
1354 #[test]
1355 fn test_simple_type_name() {
1356 assert_eq!(Type::int32().name(), "Int32");
1357 assert_eq!(Type::uint64().name(), "UInt64");
1358 assert_eq!(Type::string().name(), "String");
1359 }
1360
1361 #[test]
1362 fn test_fixed_string_type() {
1363 let t = Type::fixed_string(10);
1364 assert_eq!(t.code(), TypeCode::FixedString);
1365 assert_eq!(t.name(), "FixedString(10)");
1366 }
1367
1368 #[test]
1369 fn test_array_type() {
1370 let t = Type::array(Type::int32());
1371 assert_eq!(t.code(), TypeCode::Array);
1372 assert_eq!(t.name(), "Array(Int32)");
1373 }
1374
1375 #[test]
1376 fn test_nullable_type() {
1377 let t = Type::nullable(Type::string());
1378 assert_eq!(t.code(), TypeCode::Nullable);
1379 assert_eq!(t.name(), "Nullable(String)");
1380 }
1381
1382 #[test]
1383 fn test_tuple_type() {
1384 let t = Type::tuple(vec![Type::int32(), Type::string()]);
1385 assert_eq!(t.code(), TypeCode::Tuple);
1386 assert_eq!(t.name(), "Tuple(Int32, String)");
1387 }
1388
1389 #[test]
1390 fn test_map_type() {
1391 let t = Type::map(Type::string(), Type::int32());
1392 assert_eq!(t.code(), TypeCode::Map);
1393 assert_eq!(t.name(), "Map(String, Int32)");
1394 }
1395
1396 #[test]
1397 fn test_datetime_with_timezone() {
1398 let t = Type::datetime(Some("UTC".to_string()));
1399 assert_eq!(t.name(), "DateTime('UTC')");
1400 }
1401
1402 #[test]
1403 fn test_decimal_type() {
1404 let t = Type::decimal(10, 2);
1405 assert_eq!(t.name(), "Decimal(10, 2)");
1406 }
1407
1408 #[test]
1409 fn test_type_equality() {
1410 assert_eq!(Type::int32(), Type::int32());
1411 assert_eq!(Type::array(Type::string()), Type::array(Type::string()));
1412 assert_ne!(Type::int32(), Type::int64());
1413 assert_ne!(Type::fixed_string(10), Type::fixed_string(20));
1414 }
1415}