1#[cfg(test)]
4mod tests;
5
6use std::{collections::BTreeMap, str::FromStr};
7
8use crate::error::Error;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Type {
13 UInt8,
15 UInt16,
17 UInt32,
19 UInt64,
21 UInt128,
23 UInt256,
25 Int8,
27 Int16,
29 Int32,
31 Int64,
33 Int128,
35 Int256,
37 Float32,
39 Float64,
41 Decimal(u8, u8),
43 Decimal32(u8),
45 Decimal64(u8),
47 Decimal128(u8),
49 Decimal256(u8),
51 Bool,
53 String,
55 FixedString(u8),
57 UUID,
59 Date,
61 Date32,
63 DateTime,
65 DateTime64(u8),
69 Enum8(BTreeMap<String, i8>),
73 Enum16(BTreeMap<String, i16>),
77 Array(Box<Type>),
81 Tuple(Vec<Type>),
85 Map(Box<Type>, Box<Type>),
90 Nested(Vec<(String, Type)>),
96 NullableUInt8,
98 NullableUInt16,
100 NullableUInt32,
102 NullableUInt64,
104 NullableUInt128,
106 NullableUInt256,
108 NullableInt8,
110 NullableInt16,
112 NullableInt32,
114 NullableInt64,
116 NullableInt128,
118 NullableInt256,
120 NullableFloat32,
122 NullableFloat64,
124 NullableDecimal(u8, u8),
126 NullableDecimal32(u8),
128 NullableDecimal64(u8),
130 NullableDecimal128(u8),
132 NullableDecimal256(u8),
134 NullableBool,
136 NullableString,
138 NullableFixedString(u8),
140 NullableUUID,
142 NullableDate,
144 NullableDate32,
146 NullableDateTime,
148 NullableDateTime64(u8),
150 NullableEnum8(BTreeMap<String, i8>),
152 NullableEnum16(BTreeMap<String, i16>),
154}
155
156impl std::fmt::Display for Type {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 let s: String = match self {
159 Type::UInt8 => "UInt8".into(),
160 Type::UInt16 => "UInt16".into(),
161 Type::UInt32 => "UInt32".into(),
162 Type::UInt64 => "UInt64".into(),
163 Type::UInt128 => "UInt128".into(),
164 Type::UInt256 => "UInt256".into(),
165 Type::Int8 => "Int8".into(),
166 Type::Int16 => "Int16".into(),
167 Type::Int32 => "Int32".into(),
168 Type::Int64 => "Int64".into(),
169 Type::Int128 => "Int128".into(),
170 Type::Int256 => "Int256".into(),
171 Type::Float32 => "Float32".into(),
172 Type::Float64 => "Float64".into(),
173 Type::Decimal(p, s) => format!("Decimal({p},{s})"),
174 Type::Decimal32(s) => format!("Decimal32({s})"),
175 Type::Decimal64(s) => format!("Decimal64({s})"),
176 Type::Decimal128(s) => format!("Decimal128({s})"),
177 Type::Decimal256(s) => format!("Decimal256({s})"),
178 Type::Bool => "Bool".into(),
179 Type::String => "String".into(),
180 Type::FixedString(n) => format!("FixedString({n})"),
181 Type::Date => "Date".into(),
182 Type::Date32 => "Date32".into(),
183 Type::DateTime => "DateTime".into(),
184 Type::DateTime64(p) => format!("DateTime64({p})"),
185 Type::UUID => "UUID".into(),
186 Type::Enum8(vars) => {
187 format!(
188 "Enum8({})",
189 vars.iter()
190 .map(|(key, idx)| { format!("'{key}' = {idx}") })
191 .collect::<Vec<_>>()
192 .join(", ")
193 )
194 }
195 Type::Enum16(vars) => {
196 format!(
197 "Enum16({})",
198 vars.iter()
199 .map(|(key, idx)| { format!("'{key}' = {idx}") })
200 .collect::<Vec<_>>()
201 .join(", ")
202 )
203 }
204 Type::Array(t) => format!("Array({t})"),
205 Type::Map(k, v) => format!("Map({k}, {v})"),
206 Type::Tuple(types) => {
207 format!(
208 "Tuple({})",
209 types
210 .iter()
211 .map(|ty| { format!("{ty}") })
212 .collect::<Vec<_>>()
213 .join(", ")
214 )
215 }
216 Type::Nested(fields) => {
217 format!(
218 "Nested({})",
219 fields
220 .iter()
221 .map(|(name, ty)| { format!("{} {}", name, ty) })
222 .collect::<Vec<_>>()
223 .join(", ")
224 )
225 }
226 Type::NullableUInt8 => "Nullable(UInt8)".into(),
227 Type::NullableUInt16 => "Nullable(UInt16)".into(),
228 Type::NullableUInt32 => "Nullable(UInt32)".into(),
229 Type::NullableUInt64 => "Nullable(UInt64)".into(),
230 Type::NullableUInt128 => "Nullable(UInt128)".into(),
231 Type::NullableUInt256 => "Nullable(UInt256)".into(),
232 Type::NullableInt8 => "Nullable(Int8)".into(),
233 Type::NullableInt16 => "Nullable(Int16)".into(),
234 Type::NullableInt32 => "Nullable(Int32)".into(),
235 Type::NullableInt64 => "Nullable(Int64)".into(),
236 Type::NullableInt128 => "Nullable(Int128)".into(),
237 Type::NullableInt256 => "Nullable(Int256)".into(),
238 Type::NullableFloat32 => "Nullable(Float32)".into(),
239 Type::NullableFloat64 => "Nullable(Float64)".into(),
240 Type::NullableDecimal(p, s) => format!("Nullable(Decimal({p},{s}))"),
241 Type::NullableDecimal32(s) => format!("Nullable(Decimal32({s}))"),
242 Type::NullableDecimal64(s) => format!("Nullable(Decimal64({s}))"),
243 Type::NullableDecimal128(s) => format!("Nullable(Decimal128({s}))"),
244 Type::NullableDecimal256(s) => format!("Nullable(Decimal256({s}))"),
245 Type::NullableBool => "Nullable(Bool)".into(),
246 Type::NullableString => "Nullable(String)".into(),
247 Type::NullableFixedString(n) => format!("Nullable(FixedString({n}))"),
248 Type::NullableDate => "Nullable(Date)".into(),
249 Type::NullableDate32 => "Nullable(Date32)".into(),
250 Type::NullableDateTime => "Nullable(DateTime)".into(),
251 Type::NullableDateTime64(p) => format!("Nullable(DateTime64({p}))"),
252 Type::NullableUUID => "Nullable(UUID)".into(),
253 Type::NullableEnum8(keys) => format!("Nullable({})", Type::Enum8(keys.clone())),
254 Type::NullableEnum16(keys) => format!("Nullable({})", Type::Enum16(keys.clone())),
255 };
256
257 write!(f, "{s}")
258 }
259}
260
261impl FromStr for Type {
262 type Err = Error;
263
264 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 match s {
267 "UInt8" => return Ok(Type::UInt8),
268 "UInt16" => return Ok(Type::UInt16),
269 "UInt32" => return Ok(Type::UInt32),
270 "UInt64" => return Ok(Type::UInt64),
271 "UInt128" => return Ok(Type::UInt128),
272 "UInt256" => return Ok(Type::UInt256),
273 "Int8" => return Ok(Type::Int8),
274 "Int16" => return Ok(Type::Int16),
275 "Int32" => return Ok(Type::Int32),
276 "Int64" => return Ok(Type::Int64),
277 "Int128" => return Ok(Type::Int128),
278 "Int256" => return Ok(Type::Int256),
279 "Float32" => return Ok(Type::Float32),
280 "Float64" => return Ok(Type::Float64),
281 "Bool" => return Ok(Type::Bool),
282 "String" => return Ok(Type::String),
283 "UUID" => return Ok(Type::UUID),
284 "Date" => return Ok(Type::Date),
285 "Date32" => return Ok(Type::Date32),
286 "DateTime" => return Ok(Type::DateTime),
287 _ => {}
288 }
289
290 if let Some(s) = s.strip_prefix("Decimal(") {
292 if let Some(s) = s.strip_suffix(')') {
293 let parts = s.split(',').collect::<Vec<_>>();
294 if parts.len() != 2 {
295 return Err(Error::new("invalid Decimal type"));
296 }
297 let p = parts[0].trim().parse::<u8>()?;
298 let s = parts[1].trim().parse::<u8>()?;
299 return Ok(Type::Decimal(p, s));
300 } else {
301 return Err(Error::new("invalid Decimal type"));
302 }
303 }
304
305 if let Some(s) = s.strip_prefix("Decimal32(") {
307 if let Some(s) = s.strip_suffix(')') {
308 let s = s.trim().parse::<u8>()?;
309 return Ok(Type::Decimal32(s));
310 } else {
311 return Err(Error::new("invalid Decimal32 type"));
312 }
313 }
314
315 if let Some(s) = s.strip_prefix("Decimal64(") {
317 if let Some(s) = s.strip_suffix(')') {
318 let s = s.trim().parse::<u8>()?;
319 return Ok(Type::Decimal64(s));
320 } else {
321 return Err(Error::new("invalid Decimal64 type"));
322 }
323 }
324
325 if let Some(s) = s.strip_prefix("Decimal128(") {
327 if let Some(s) = s.strip_suffix(')') {
328 let s = s.trim().parse::<u8>()?;
329 return Ok(Type::Decimal128(s));
330 } else {
331 return Err(Error::new("invalid Decimal128 type"));
332 }
333 }
334
335 if let Some(s) = s.strip_prefix("Decimal256(") {
337 if let Some(s) = s.strip_suffix(')') {
338 let s = s.trim().parse::<u8>()?;
339 return Ok(Type::Decimal256(s));
340 } else {
341 return Err(Error::new("invalid Decimal256 type"));
342 }
343 }
344
345 if let Some(s) = s.strip_prefix("FixedString(") {
347 if let Some(s) = s.strip_suffix(')') {
348 let n = s.trim().parse::<u8>()?;
349 return Ok(Type::FixedString(n));
350 } else {
351 return Err(Error::new("invalid FixedString type"));
352 }
353 }
354
355 if let Some(s) = s.strip_prefix("DateTime64(") {
357 if let Some(s) = s.strip_suffix(')') {
358 let p = s.trim().parse::<u8>()?;
359 return Ok(Type::DateTime64(p));
360 } else {
361 return Err(Error::new("invalid DateTime64 type"));
362 }
363 }
364
365 if let Some(s) = s.strip_prefix("Enum8(") {
367 if let Some(s) = s.strip_suffix(')') {
368 let mut map = BTreeMap::new();
369 for variant in s.split(',') {
370 let parts = variant.trim().split('=').collect::<Vec<_>>();
371 if parts.len() != 2 {
372 return Err(Error::new("invalid Enum8 type"));
373 }
374 let name = parts[0]
375 .trim()
376 .trim_start_matches('\'')
377 .trim_end_matches('\'')
378 .to_string();
379 let index = parts[1].trim().parse::<i8>()?;
380 map.insert(name, index);
381 }
382 return Ok(Type::Enum8(map));
383 } else {
384 return Err(Error::new("invalid DateTime64 type"));
385 }
386 }
387
388 if let Some(s) = s.strip_prefix("Enum16(") {
390 if let Some(s) = s.strip_suffix(')') {
391 let mut map = BTreeMap::new();
392 for variant in s.split(',') {
393 let parts = variant.trim().split('=').collect::<Vec<_>>();
394 if parts.len() != 2 {
395 return Err(Error::new("invalid Enum8 type"));
396 }
397 let name = parts[0]
398 .trim()
399 .trim_start_matches('\'')
400 .trim_end_matches('\'')
401 .to_string();
402 let index = parts[1].trim().parse::<i16>()?;
403 map.insert(name, index);
404 }
405 return Ok(Type::Enum16(map));
406 } else {
407 return Err(Error::new("invalid DateTime64 type"));
408 }
409 }
410
411 if let Some(s) = s.strip_prefix("Enum(") {
413 if let Some(s) = s.strip_suffix(')') {
414 let mut map = BTreeMap::new();
415 for variant in s.split(',') {
416 let parts = variant.trim().split('=').collect::<Vec<_>>();
417 if parts.len() != 2 {
418 return Err(Error::new("invalid Enum8 type"));
419 }
420 let name = parts[0]
421 .trim()
422 .trim_start_matches('\'')
423 .trim_end_matches('\'')
424 .to_string();
425 let index = parts[1].trim().parse::<i16>()?;
426 map.insert(name, index);
427 }
428 return Ok(Type::Enum16(map));
429 } else {
430 return Err(Error::new("invalid DateTime64 type"));
431 }
432 }
433
434 if let Some(s) = s.strip_prefix("Array(") {
436 if let Some(s) = s.strip_suffix(')') {
437 let ty = s.trim().parse::<Type>()?;
438 return Ok(Type::Array(Box::new(ty)));
439 } else {
440 return Err(Error::new("invalid Array type"));
441 }
442 }
443
444 if let Some(s) = s.strip_prefix("Tuple(") {
446 if let Some(s) = s.strip_suffix(')') {
447 let mut types = vec![];
448 for ty_str in s.split(',') {
449 let ty = ty_str.trim().parse::<Type>()?;
450 types.push(ty);
451 }
452 return Ok(Type::Tuple(types));
453 } else {
454 return Err(Error::new("invalid Tuple type"));
455 }
456 }
457
458 if let Some(s) = s.strip_prefix("Map(") {
460 if let Some(s) = s.strip_suffix(')') {
461 let parts = s.split(',').collect::<Vec<_>>();
462 if parts.len() != 2 {
463 return Err(Error::new("invalid Map type"));
464 }
465 let key_ty = parts[0].trim().parse::<Type>()?;
466 let val_ty = parts[1].trim().parse::<Type>()?;
467 return Ok(Type::Map(Box::new(key_ty), Box::new(val_ty)));
468 } else {
469 return Err(Error::new("invalid Map type"));
470 }
471 }
472
473 if let Some(s) = s.strip_prefix("Nested(") {
475 if let Some(s) = s.strip_suffix(')') {
476 let mut fields = vec![];
477 for field_str in s.split(',').collect::<Vec<_>>() {
478 let parts = field_str.trim().split(' ').collect::<Vec<_>>();
479 if parts.len() != 2 {
480 return Err(Error::new("invalid Nested type"));
481 }
482 let name = parts[0].trim();
483 let ty = parts[1].trim().parse::<Type>()?;
484 fields.push((name.to_string(), ty));
485 }
486
487 return Ok(Type::Nested(fields));
488 } else {
489 return Err(Error::new("invalid Nested type"));
490 }
491 }
492
493 if let Some(s) = s.strip_prefix("Nullable(") {
495 if let Some(s) = s.strip_suffix(')') {
496 let ty = s.parse::<Type>()?;
497 let ty = match ty {
498 Type::UInt8 => Type::NullableUInt8,
499 Type::UInt16 => Type::NullableUInt16,
500 Type::UInt32 => Type::NullableUInt32,
501 Type::UInt64 => Type::NullableUInt64,
502 Type::UInt128 => Type::NullableUInt128,
503 Type::UInt256 => Type::NullableUInt256,
504 Type::Int8 => Type::NullableInt8,
505 Type::Int16 => Type::NullableInt16,
506 Type::Int32 => Type::NullableInt32,
507 Type::Int64 => Type::NullableInt64,
508 Type::Int128 => Type::NullableInt128,
509 Type::Int256 => Type::NullableInt256,
510 Type::Float32 => Type::NullableFloat32,
511 Type::Float64 => Type::NullableFloat64,
512 Type::Decimal(p, s) => Type::NullableDecimal(p, s),
513 Type::Decimal32(s) => Type::NullableDecimal32(s),
514 Type::Decimal64(s) => Type::NullableDecimal64(s),
515 Type::Decimal128(s) => Type::NullableDecimal128(s),
516 Type::Decimal256(s) => Type::NullableDecimal256(s),
517 Type::Bool => Type::NullableBool,
518 Type::String => Type::NullableString,
519 Type::FixedString(n) => Type::NullableFixedString(n),
520 Type::UUID => Type::NullableUUID,
521 Type::Date => Type::NullableDate,
522 Type::Date32 => Type::NullableDate32,
523 Type::DateTime => Type::NullableDateTime,
524 Type::DateTime64(p) => Type::NullableDateTime64(p),
525 Type::Enum8(keys) => Type::NullableEnum8(keys),
526 Type::Enum16(keys) => Type::NullableEnum16(keys),
527 _ => return Err(Error::new("invalid Nullable type")),
528 };
529 return Ok(ty);
530 } else {
531 return Err(Error::new("invalid Nullable type"));
532 }
533 }
534
535 Err(Error::new(
536 format!("'{s}' is not a valid Clickhouse type").as_str(),
537 ))
538 }
539}