This is an automated email from the ASF dual-hosted git repository.

nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new f051e23  feat: Implement serde for boolean and array (#48)
f051e23 is described below

commit f051e23013a317ae4119a434c329e12095fe2d0f
Author: Xuanwo <[email protected]>
AuthorDate: Sat Aug 10 18:26:37 2024 +0800

    feat: Implement serde for boolean and array (#48)
---
 crates/paimon/src/spec/schema.rs |  10 +-
 crates/paimon/src/spec/types.rs  | 401 +++++++++++++++++++++------------------
 2 files changed, 216 insertions(+), 195 deletions(-)

diff --git a/crates/paimon/src/spec/schema.rs b/crates/paimon/src/spec/schema.rs
index c2c91a2..349652d 100644
--- a/crates/paimon/src/spec/schema.rs
+++ b/crates/paimon/src/spec/schema.rs
@@ -17,9 +17,8 @@
 
 use crate::spec::types::DataType;
 use serde::{Deserialize, Serialize};
-use serde_with::{serde_as, DisplayFromStr};
+use serde_with::serde_as;
 use std::collections::HashMap;
-use std::fmt::{Display, Formatter};
 
 /// The table schema for paimon table.
 ///
@@ -48,7 +47,6 @@ pub struct DataField {
     id: i32,
     name: String,
     #[serde(rename = "type")]
-    #[serde_as(as = "DisplayFromStr")]
     typ: DataType,
     description: Option<String>,
 }
@@ -95,12 +93,6 @@ impl DataField {
     }
 }
 
-impl Display for DataField {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{}", self.typ)
-    }
-}
-
 pub fn escape_identifier(identifier: &str) -> String {
     identifier.replace('"', "\"\"")
 }
diff --git a/crates/paimon/src/spec/types.rs b/crates/paimon/src/spec/types.rs
index 84d7115..5039caa 100644
--- a/crates/paimon/src/spec/types.rs
+++ b/crates/paimon/src/spec/types.rs
@@ -18,7 +18,11 @@
 use crate::error::*;
 use crate::spec::DataField;
 use bitflags::bitflags;
-use serde::{Deserialize, Serialize};
+use serde::de::{MapAccess, Visitor};
+use serde::ser::SerializeStruct;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use serde_with::{DeserializeFromStr, SerializeDisplay};
+use std::fmt;
 use std::fmt::{Debug, Display, Formatter};
 use std::str::FromStr;
 
@@ -47,7 +51,8 @@ bitflags! {
 /// Data type for paimon table.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L45>
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(untagged)]
 pub enum DataType {
     /// Data type of a boolean with a (possibly) three-valued logic of `TRUE`, 
`FALSE`, `UNKNOWN`.
     Boolean(BooleanType),
@@ -126,63 +131,17 @@ impl DataType {
     }
 }
 
-impl Display for DataType {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match self {
-            DataType::Boolean(v) => write!(f, "{v}"),
-            DataType::TinyInt(v) => write!(f, "{v}"),
-            DataType::SmallInt(v) => write!(f, "{v}"),
-            DataType::Int(v) => write!(f, "{v}"),
-            DataType::BigInt(v) => write!(f, "{v}"),
-            DataType::Decimal(v) => write!(f, "{v}"),
-            DataType::Double(v) => write!(f, "{v}"),
-            DataType::Float(v) => write!(f, "{v}"),
-            DataType::Binary(v) => write!(f, "{v}"),
-            DataType::VarBinary(v) => write!(f, "{v}"),
-            DataType::Char(v) => write!(f, "{v}"),
-            DataType::VarChar(v) => write!(f, "{v}"),
-            DataType::Date(v) => write!(f, "{v}"),
-            DataType::LocalZonedTimestamp(v) => write!(f, "{v}"),
-            DataType::Time(v) => write!(f, "{v}"),
-            DataType::Timestamp(v) => write!(f, "{v}"),
-            DataType::Array(v) => write!(f, "{v}"),
-            DataType::Map(v) => write!(f, "{v}"),
-            DataType::Multiset(v) => write!(f, "{v}"),
-            DataType::Row(v) => write!(f, "{v}"),
-        }
-    }
-}
-
-impl FromStr for DataType {
-    type Err = Error;
-
-    fn from_str(_: &str) -> Result<Self, Self::Err> {
-        todo!()
-    }
-}
-
 /// ArrayType for paimon.
 ///
 /// Data type of an array of elements with same subtype.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/ArrayType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
-#[serde(rename_all = "camelCase")]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ArrayType {
     nullable: bool,
     element_type: Box<DataType>,
 }
 
-impl Display for ArrayType {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "ARRAY<{}>", self.element_type)?;
-        if !self.nullable {
-            write!(f, " NOT NULL")?;
-        }
-        Ok(())
-    }
-}
-
 impl ArrayType {
     pub fn new(element_type: DataType) -> Self {
         Self::with_nullable(true, element_type)
@@ -200,12 +159,94 @@ impl ArrayType {
     }
 }
 
+impl Serialize for ArrayType {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, 
S::Error>
+    where
+        S: Serializer,
+    {
+        let mut s = serializer.serialize_struct("ArrayType", 2)?;
+        let typ = if self.nullable {
+            "ARRAY"
+        } else {
+            "ARRAY NOT NULL"
+        };
+        s.serialize_field("type", typ)?;
+        s.serialize_field("element", &self.element_type)?;
+        s.end()
+    }
+}
+
+impl<'de> Deserialize<'de> for ArrayType {
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        #[serde(field_identifier, rename_all = "lowercase")]
+        enum Field {
+            Type,
+            Element,
+        }
+
+        struct ArrayTypeVisitor;
+
+        impl<'de> Visitor<'de> for ArrayTypeVisitor {
+            type Value = ArrayType;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result 
{
+                formatter.write_str("ArrayType")
+            }
+
+            fn visit_map<V>(self, mut map: V) -> 
std::result::Result<ArrayType, V::Error>
+            where
+                V: MapAccess<'de>,
+            {
+                let mut nullable = None;
+                let mut element: Option<DataType> = None;
+                while let Some(key) = map.next_key()? {
+                    match key {
+                        Field::Type => {
+                            if nullable.is_some() {
+                                return 
Err(serde::de::Error::duplicate_field("type"));
+                            }
+                            match map.next_value()? {
+                                "ARRAY" => nullable = Some(true),
+                                "ARRAY NOT NULL" => nullable = Some(false),
+                                v => Err(serde::de::Error::invalid_value(
+                                    serde::de::Unexpected::Str(v),
+                                    &"ARRAY or ARRAY NOT NULL",
+                                ))?,
+                            }
+                        }
+                        Field::Element => {
+                            if element.is_some() {
+                                return 
Err(serde::de::Error::duplicate_field("element"));
+                            }
+                            element = Some(map.next_value()?);
+                        }
+                    }
+                }
+
+                Ok(ArrayType {
+                    nullable: nullable.ok_or_else(|| 
serde::de::Error::missing_field("type"))?,
+                    element_type: element
+                        .ok_or_else(|| 
serde::de::Error::missing_field("element"))?
+                        .into(),
+                })
+            }
+        }
+
+        const FIELDS: &[&str] = &["type", "element"];
+        deserializer.deserialize_struct("ArrayType", FIELDS, ArrayTypeVisitor)
+    }
+}
+
 /// BigIntType for paimon.
 ///
 /// Data type of an 8-byte (2^64) signed integer with values from 
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/BigIntType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct BigIntType {
     nullable: bool,
 }
@@ -248,7 +289,7 @@ impl BigIntType {
 /// Data type of a fixed-length binary string (=a sequence of bytes).
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/BinaryType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 #[serde(rename_all = "camelCase")]
 pub struct BinaryType {
     nullable: bool,
@@ -306,7 +347,7 @@ impl BinaryType {
 /// Data type of a boolean with a (possibly) three-valued logic of `TRUE`, 
`FALSE`, `UNKNOWN`.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/master/paimon-common/src/release-0.8.2/java/org/apache/paimon/types/BooleanType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, DeserializeFromStr, SerializeDisplay, 
Hash)]
 pub struct BooleanType {
     nullable: bool,
 }
@@ -321,6 +362,20 @@ impl Display for BooleanType {
     }
 }
 
+impl FromStr for BooleanType {
+    type Err = Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "BOOLEAN" => Ok(Self { nullable: true }),
+            "BOOLEAN NOT NULL" => Ok(Self { nullable: false }),
+            v => Err(Error::DataTypeInvalid {
+                message: format!("invalid boolean type: {v}"),
+            })?,
+        }
+    }
+}
+
 impl Default for BooleanType {
     fn default() -> Self {
         Self::new()
@@ -346,7 +401,7 @@ impl BooleanType {
 /// Data type of a fixed-length character string.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/CharType.java>.
-#[derive(Debug, Clone, PartialEq, Hash, Eq, Deserialize, Serialize)]
+#[derive(Debug, Clone, PartialEq, Hash, Eq, Deserialize, SerializeDisplay)]
 #[serde(rename_all = "camelCase")]
 pub struct CharType {
     nullable: bool,
@@ -404,7 +459,7 @@ impl CharType {
 /// Data type of a date consisting of `year-month-day` with values ranging 
from `0000-01-01` to `9999-12-31`
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/DateType.java>.
-#[derive(Debug, Clone, PartialEq, Hash, Eq, Deserialize, Serialize)]
+#[derive(Debug, Clone, PartialEq, Hash, Eq, Deserialize, SerializeDisplay)]
 pub struct DateType {
     nullable: bool,
 }
@@ -444,7 +499,7 @@ impl DateType {
 /// Data type of a decimal number with fixed precision and scale.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/DecimalType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct DecimalType {
     nullable: bool,
 
@@ -531,7 +586,7 @@ impl DecimalType {
 /// Data type of an 8-byte double precision floating point number.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/DoubleType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct DoubleType {
     nullable: bool,
 }
@@ -569,7 +624,7 @@ impl DoubleType {
 /// FloatType for paimon.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/FloatType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct FloatType {
     nullable: bool,
 }
@@ -609,7 +664,7 @@ impl FloatType {
 /// Data type of a 4-byte (2^32) signed integer with values from 
-2,147,483,648 to 2,147,483,647.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/IntType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct IntType {
     nullable: bool,
 }
@@ -652,7 +707,7 @@ impl IntType {
 /// Data type of a timestamp WITH LOCAL time zone consisting of 
`year-month-day hour:minute:second[.fractional] zone` with up to nanosecond 
precision and values ranging from `0000-01-01 00:00:00.000000000 +14:59` to 
`9999-12-31 23:59:59.999999999 -14:59`. Leap seconds (23:59:60 and 23:59:61) 
are not supported as the semantics are closer to a point in time than a 
wall-clock time.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/TimestampType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct LocalZonedTimestampType {
     nullable: bool,
     precision: u32,
@@ -720,7 +775,7 @@ impl LocalZonedTimestampType {
 /// Data type of a 2-byte (2^16) signed integer with values from -32,768 to 
32,767.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/SmallIntType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct SmallIntType {
     nullable: bool,
 }
@@ -764,7 +819,7 @@ impl SmallIntType {
 /// up to nanosecond precision and values ranging from `00:00:00.000000000` to 
`23:59:59.999999999`.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/TimeType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct TimeType {
     nullable: bool,
     precision: u32,
@@ -829,7 +884,7 @@ impl TimeType {
 /// Data type of a timestamp WITHOUT time zone consisting of `year-month-day 
hour:minute:second[.fractional]` with up to nanosecond precision and values 
ranging from `0000-01-01 00:00:00.000000000` to `9999-12-31 23:59:59.999999999`.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/TimestampType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct TimestampType {
     nullable: bool,
     precision: u32,
@@ -894,7 +949,7 @@ impl TimestampType {
 /// Data type of a 1-byte signed integer with values from -128 to 127.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/master/paimon-common/src/release-0.8.2/java/org/apache/paimon/types/TinyIntType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct TinyIntType {
     nullable: bool,
 }
@@ -937,7 +992,7 @@ impl TinyIntType {
 /// Data type of a variable-length binary string (=a sequence of bytes).
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/VarBinaryType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct VarBinaryType {
     nullable: bool,
     length: u32,
@@ -995,7 +1050,7 @@ impl VarBinaryType {
 /// Data type of a variable-length character string.
 ///
 /// Impl Reference: 
<https://github.com/apache/paimon/blob/release-0.8.2/paimon-common/src/main/java/org/apache/paimon/types/VarCharType.java>.
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, SerializeDisplay, Hash)]
 pub struct VarCharType {
     nullable: bool,
     length: u32,
@@ -1064,16 +1119,6 @@ pub struct MapType {
     value_type: Box<DataType>,
 }
 
-impl Display for MapType {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "MAP<{}, {}>", self.key_type, self.value_type)?;
-        if !self.nullable {
-            write!(f, " NOT NULL")?;
-        }
-        Ok(())
-    }
-}
-
 impl MapType {
     pub fn new(key_type: DataType, value_type: DataType) -> Self {
         Self::with_nullable(true, key_type, value_type)
@@ -1104,16 +1149,6 @@ pub struct MultisetType {
     element_type: Box<DataType>,
 }
 
-impl Display for MultisetType {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "MULTISET<{}>", self.element_type)?;
-        if !self.nullable {
-            write!(f, " NOT NULL")?;
-        }
-        Ok(())
-    }
-}
-
 impl MultisetType {
     pub fn new(element_type: DataType) -> Self {
         Self::with_nullable(true, element_type)
@@ -1145,22 +1180,6 @@ pub struct RowType {
     fields: Vec<DataField>,
 }
 
-impl Display for RowType {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        let fields = self
-            .fields
-            .iter()
-            .map(|field| field.to_string())
-            .collect::<Vec<String>>()
-            .join(", ");
-        write!(f, "ROW<{}>", fields)?;
-        if !self.nullable {
-            write!(f, " NOT NULL")?;
-        }
-        Ok(())
-    }
-}
-
 impl RowType {
     pub const fn new(fields: Vec<DataField>) -> Self {
         Self::with_nullable(true, fields)
@@ -1182,160 +1201,170 @@ mod tests {
 
     #[test]
     fn test_data_type_to_string() {
+        assert_eq!(BooleanType::with_nullable(true).to_string(), "BOOLEAN");
         assert_eq!(
-            DataType::Boolean(BooleanType::with_nullable(true)).to_string(),
-            "BOOLEAN"
-        );
-        assert_eq!(
-            DataType::Boolean(BooleanType::with_nullable(false)).to_string(),
+            BooleanType::with_nullable(false).to_string(),
             "BOOLEAN NOT NULL"
         );
+        assert_eq!(TinyIntType::with_nullable(true).to_string(), "TINYINT");
         assert_eq!(
-            DataType::TinyInt(TinyIntType::with_nullable(true)).to_string(),
-            "TINYINT"
-        );
-        assert_eq!(
-            DataType::TinyInt(TinyIntType::with_nullable(false)).to_string(),
+            TinyIntType::with_nullable(false).to_string(),
             "TINYINT NOT NULL"
         );
+        assert_eq!(SmallIntType::with_nullable(true).to_string(), "SMALLINT");
         assert_eq!(
-            DataType::SmallInt(SmallIntType::with_nullable(true)).to_string(),
-            "SMALLINT"
-        );
-        assert_eq!(
-            DataType::SmallInt(SmallIntType::with_nullable(false)).to_string(),
+            SmallIntType::with_nullable(false).to_string(),
             "SMALLINT NOT NULL"
         );
+        assert_eq!(IntType::with_nullable(true).to_string(), "INTEGER");
         assert_eq!(
-            DataType::Int(IntType::with_nullable(true)).to_string(),
-            "INTEGER"
-        );
-        assert_eq!(
-            DataType::Int(IntType::with_nullable(false)).to_string(),
+            IntType::with_nullable(false).to_string(),
             "INTEGER NOT NULL"
         );
+        assert_eq!(BigIntType::with_nullable(true).to_string(), "BIGINT");
         assert_eq!(
-            DataType::BigInt(BigIntType::with_nullable(true)).to_string(),
-            "BIGINT"
-        );
-        assert_eq!(
-            DataType::BigInt(BigIntType::with_nullable(false)).to_string(),
+            BigIntType::with_nullable(false).to_string(),
             "BIGINT NOT NULL"
         );
         assert_eq!(
-            DataType::Decimal(DecimalType::with_nullable(true, 10, 
2).unwrap()).to_string(),
+            DecimalType::with_nullable(true, 10, 2).unwrap().to_string(),
             "DECIMAL(10, 2)"
         );
         assert_eq!(
-            DataType::Decimal(DecimalType::with_nullable(false, 10, 
2).unwrap()).to_string(),
+            DecimalType::with_nullable(false, 10, 2)
+                .unwrap()
+                .to_string(),
             "DECIMAL(10, 2) NOT NULL"
         );
+        assert_eq!(DoubleType::with_nullable(true).to_string(), "DOUBLE");
         assert_eq!(
-            DataType::Double(DoubleType::with_nullable(true)).to_string(),
-            "DOUBLE"
-        );
-        assert_eq!(
-            DataType::Double(DoubleType::with_nullable(false)).to_string(),
+            DoubleType::with_nullable(false).to_string(),
             "DOUBLE NOT NULL"
         );
+        assert_eq!(FloatType::with_nullable(true).to_string(), "FLOAT");
         assert_eq!(
-            DataType::Float(FloatType::with_nullable(true)).to_string(),
-            "FLOAT"
-        );
-        assert_eq!(
-            DataType::Float(FloatType::with_nullable(false)).to_string(),
+            FloatType::with_nullable(false).to_string(),
             "FLOAT NOT NULL"
         );
         assert_eq!(
-            DataType::Binary(BinaryType::with_nullable(true, 
10).unwrap()).to_string(),
+            BinaryType::with_nullable(true, 10).unwrap().to_string(),
             "BINARY(10)"
         );
         assert_eq!(
-            DataType::Binary(BinaryType::with_nullable(false, 
10).unwrap()).to_string(),
+            BinaryType::with_nullable(false, 10).unwrap().to_string(),
             "BINARY(10) NOT NULL"
         );
         assert_eq!(
-            DataType::VarBinary(VarBinaryType::try_new(true, 
10).unwrap()).to_string(),
+            VarBinaryType::try_new(true, 10).unwrap().to_string(),
             "VARBINARY(10)"
         );
         assert_eq!(
-            DataType::VarBinary(VarBinaryType::try_new(false, 
10).unwrap()).to_string(),
+            VarBinaryType::try_new(false, 10).unwrap().to_string(),
             "VARBINARY(10) NOT NULL"
         );
         assert_eq!(
-            DataType::Char(CharType::with_nullable(true, 
10).unwrap()).to_string(),
+            CharType::with_nullable(true, 10).unwrap().to_string(),
             "CHAR(10)"
         );
         assert_eq!(
-            DataType::Char(CharType::with_nullable(false, 
10).unwrap()).to_string(),
+            CharType::with_nullable(false, 10).unwrap().to_string(),
             "CHAR(10) NOT NULL"
         );
         assert_eq!(
-            DataType::VarChar(VarCharType::with_nullable(true, 
10).unwrap()).to_string(),
+            VarCharType::with_nullable(true, 10).unwrap().to_string(),
             "VARCHAR(10)"
         );
         assert_eq!(
-            DataType::VarChar(VarCharType::with_nullable(false, 
10).unwrap()).to_string(),
+            VarCharType::with_nullable(false, 10).unwrap().to_string(),
             "VARCHAR(10) NOT NULL"
         );
+        assert_eq!(DateType::with_nullable(true).to_string(), "DATE");
+        assert_eq!(DateType::with_nullable(false).to_string(), "DATE NOT 
NULL");
         assert_eq!(
-            DataType::Date(DateType::with_nullable(true)).to_string(),
-            "DATE"
-        );
-        assert_eq!(
-            DataType::Date(DateType::with_nullable(false)).to_string(),
-            "DATE NOT NULL"
-        );
-        assert_eq!(
-            
DataType::LocalZonedTimestamp(LocalZonedTimestampType::with_nullable(true, 
6).unwrap())
+            LocalZonedTimestampType::with_nullable(true, 6)
+                .unwrap()
                 .to_string(),
             "TIMESTAMP WITH LOCAL TIME ZONE(6)"
         );
         assert_eq!(
-            DataType::LocalZonedTimestamp(
-                LocalZonedTimestampType::with_nullable(false, 6).unwrap()
-            )
-            .to_string(),
+            LocalZonedTimestampType::with_nullable(false, 6)
+                .unwrap()
+                .to_string(),
             "TIMESTAMP WITH LOCAL TIME ZONE(6) NOT NULL"
         );
         assert_eq!(
-            DataType::Time(TimeType::with_nullable(true, 
6).unwrap()).to_string(),
+            TimeType::with_nullable(true, 6).unwrap().to_string(),
             "TIME(6)"
         );
         assert_eq!(
-            DataType::Time(TimeType::with_nullable(false, 
6).unwrap()).to_string(),
+            TimeType::with_nullable(false, 6).unwrap().to_string(),
             "TIME(6) NOT NULL"
         );
         assert_eq!(
-            DataType::Timestamp(TimestampType::with_nullable(false, 
6).unwrap()).to_string(),
+            TimestampType::with_nullable(false, 6).unwrap().to_string(),
             "TIMESTAMP(6) NOT NULL"
         );
         assert_eq!(
-            DataType::Timestamp(TimestampType::with_nullable(true, 
6).unwrap()).to_string(),
+            TimestampType::with_nullable(true, 6).unwrap().to_string(),
             "TIMESTAMP(6)"
         );
-        let int_type = DataType::Int(IntType::with_nullable(true));
-        let arr_type = DataType::Array(ArrayType::with_nullable(true, 
int_type.clone()));
-        assert_eq!(arr_type.to_string(), "ARRAY<INTEGER>");
-        assert_eq!(
-            DataType::Array(ArrayType::with_nullable(true, 
arr_type.clone())).to_string(),
-            "ARRAY<ARRAY<INTEGER>>"
-        );
-        let map_type = DataType::Map(MapType::with_nullable(
-            true,
-            int_type.clone(),
-            arr_type.clone(),
-        ));
-        assert_eq!(map_type.to_string(), "MAP<INTEGER, ARRAY<INTEGER>>");
-        let multiset_type = 
DataType::Multiset(MultisetType::with_nullable(true, int_type.clone()));
-        assert_eq!(multiset_type.to_string(), "MULTISET<INTEGER>");
-        let row_type = DataType::Row(RowType::with_nullable(
-            true,
-            vec![
-                DataField::new(1, "a".to_string(), int_type.clone()),
-                DataField::new(2, "b".to_string(), arr_type.clone()),
-            ],
-        ));
-        assert_eq!(row_type.to_string(), "ROW<INTEGER, ARRAY<INTEGER>>");
+    }
+
+    /// TODO: replace expect with exist fixture.
+    #[test]
+    fn test_data_type_serialize() {
+        // name, input, expect.
+        let cases = vec![
+            (
+                "boolean",
+                DataType::Boolean(BooleanType::with_nullable(true)),
+                r#""BOOLEAN""#,
+            ),
+            (
+                "array with boolean",
+                DataType::Array(ArrayType {
+                    nullable: false,
+                    element_type: 
DataType::Boolean(BooleanType::with_nullable(false)).into(),
+                }),
+                r#"{"type":"ARRAY NOT NULL","element":"BOOLEAN NOT NULL"}"#,
+            ),
+        ];
+
+        for (name, input, expect) in cases {
+            assert_eq!(
+                serde_json::to_string(&input).unwrap(),
+                expect,
+                "test data type serialize for {name}"
+            )
+        }
+    }
+
+    /// TODO: replace expect with exist fixture.
+    #[test]
+    fn test_data_type_deserialize() {
+        // name, input, expect.
+        let cases = vec![
+            (
+                "boolean",
+                r#""BOOLEAN""#,
+                DataType::Boolean(BooleanType::with_nullable(true)),
+            ),
+            (
+                "array with boolean",
+                r#"{"type":"ARRAY NOT NULL","element":"BOOLEAN NOT NULL"}"#,
+                DataType::Array(ArrayType {
+                    nullable: false,
+                    element_type: 
DataType::Boolean(BooleanType::with_nullable(false)).into(),
+                }),
+            ),
+        ];
+
+        for (name, input, expect) in cases {
+            assert_eq!(
+                serde_json::from_str::<DataType>(input).unwrap(),
+                expect,
+                "test data type deserialize for {name}"
+            )
+        }
     }
 }

Reply via email to