This is an automated email from the ASF dual-hosted git repository.
aitozi 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 ce42c78 feat(spec): Add primitive data types (#18)
ce42c78 is described below
commit ce42c78b2b263ac1d4c25762c0c5ca29e954a251
Author: ForwardXu <[email protected]>
AuthorDate: Thu Jul 25 16:13:45 2024 +0800
feat(spec): Add primitive data types (#18)
---
crates/paimon/Cargo.toml | 1 +
crates/paimon/src/spec/mod.rs | 3 +
crates/paimon/src/spec/schema.rs | 33 +-
crates/paimon/src/spec/types.rs | 1033 ++++++++++++++++++++++++++++++++++++++
4 files changed, 1038 insertions(+), 32 deletions(-)
diff --git a/crates/paimon/Cargo.toml b/crates/paimon/Cargo.toml
index 6d057d5..1e33ce0 100644
--- a/crates/paimon/Cargo.toml
+++ b/crates/paimon/Cargo.toml
@@ -27,6 +27,7 @@ license.workspace = true
version.workspace = true
[dependencies]
+bitflags = "2.6.0"
chrono = {version = "0.4.38", features = ["serde"]}
serde = { version = "1", features = ["derive"] }
serde_with = "3.8.3"
diff --git a/crates/paimon/src/spec/mod.rs b/crates/paimon/src/spec/mod.rs
index eb25755..fc09dcd 100644
--- a/crates/paimon/src/spec/mod.rs
+++ b/crates/paimon/src/spec/mod.rs
@@ -27,3 +27,6 @@ pub use schema::*;
mod snapshot;
pub use snapshot::*;
+
+mod types;
+pub use types::*;
diff --git a/crates/paimon/src/spec/schema.rs b/crates/paimon/src/spec/schema.rs
index b6a5498..7a9b0d0 100644
--- a/crates/paimon/src/spec/schema.rs
+++ b/crates/paimon/src/spec/schema.rs
@@ -15,12 +15,10 @@
// specific language governing permissions and limitations
// under the License.
-use crate::error::Error;
+use crate::spec::types::DataType;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use std::collections::HashMap;
-use std::fmt::{Display, Formatter};
-use std::str::FromStr;
/// The table schema for paimon table.
///
@@ -53,32 +51,3 @@ pub struct DataField {
typ: DataType,
description: Option<String>,
}
-
-/// Data type for paimon table.
-///
-/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L45>
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct DataType {
- is_nullable: bool,
- type_root: DataTypeRoot,
-}
-
-impl Display for DataType {
- fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result {
- todo!()
- }
-}
-
-impl FromStr for DataType {
- type Err = Error;
-
- fn from_str(_: &str) -> Result<Self, Self::Err> {
- todo!()
- }
-}
-
-/// The root of data type.
-///
-/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataTypeRoot.java#L49>
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum DataTypeRoot {}
diff --git a/crates/paimon/src/spec/types.rs b/crates/paimon/src/spec/types.rs
new file mode 100644
index 0000000..b44dc2d
--- /dev/null
+++ b/crates/paimon/src/spec/types.rs
@@ -0,0 +1,1033 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::error::Error;
+use bitflags::bitflags;
+use serde::{Deserialize, Serialize};
+use std::fmt::{Display, Formatter};
+use std::str::FromStr;
+
+bitflags! {
+/// An enumeration of Data type families for clustering {@link DataTypeRoot}s
into categories.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/DataTypeFamily.java>
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct DataTypeFamily: u32 {
+ const PREDEFINED = 1 << 0;
+ const CONSTRUCTED = 1 << 1;
+ const CHARACTER_STRING = 1 << 2;
+ const BINARY_STRING = 1 << 3;
+ const NUMERIC = 1 << 4;
+ const INTEGER_NUMERIC = 1 << 5;
+ const EXACT_NUMERIC = 1 << 6;
+ const APPROXIMATE_NUMERIC = 1 << 7;
+ const DATETIME = 1 << 8;
+ const TIME = 1 << 9;
+ const TIMESTAMP = 1 << 10;
+ const COLLECTION = 1 << 11;
+ const EXTENSION = 1 << 12;
+ }
+}
+
+/// The root of data type.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataTypeRoot.java#L49>
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub enum DataTypeRoot {
+ Char,
+ Varchar,
+ Boolean,
+ Binary,
+ Varbinary,
+ Decimal,
+ Tinyint,
+ Smallint,
+ Integer,
+ Bigint,
+ Float,
+ Double,
+ Date,
+ TimeWithoutTimeZone,
+ TimestampWithoutTimeZone,
+ TimestampWithLocalTimeZone,
+ Array,
+ Multiset,
+ Map,
+ Row,
+}
+
+impl DataTypeRoot {
+ pub fn families(&self) -> DataTypeFamily {
+ match self {
+ Self::Char => DataTypeFamily::PREDEFINED |
DataTypeFamily::CHARACTER_STRING,
+ Self::Varchar => DataTypeFamily::PREDEFINED |
DataTypeFamily::CHARACTER_STRING,
+ Self::Boolean => DataTypeFamily::PREDEFINED,
+ Self::Binary => DataTypeFamily::PREDEFINED |
DataTypeFamily::BINARY_STRING,
+ Self::Varbinary => DataTypeFamily::PREDEFINED |
DataTypeFamily::BINARY_STRING,
+ Self::Decimal => {
+ DataTypeFamily::PREDEFINED | DataTypeFamily::NUMERIC |
DataTypeFamily::EXACT_NUMERIC
+ }
+ Self::Tinyint => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::INTEGER_NUMERIC
+ | DataTypeFamily::EXACT_NUMERIC
+ }
+ Self::Smallint => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::INTEGER_NUMERIC
+ | DataTypeFamily::EXACT_NUMERIC
+ }
+ Self::Integer => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::INTEGER_NUMERIC
+ | DataTypeFamily::EXACT_NUMERIC
+ }
+ Self::Bigint => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::INTEGER_NUMERIC
+ | DataTypeFamily::EXACT_NUMERIC
+ }
+ Self::Float => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::APPROXIMATE_NUMERIC
+ }
+ Self::Double => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::NUMERIC
+ | DataTypeFamily::APPROXIMATE_NUMERIC
+ }
+ Self::Date => DataTypeFamily::PREDEFINED |
DataTypeFamily::DATETIME,
+ Self::TimeWithoutTimeZone => {
+ DataTypeFamily::PREDEFINED | DataTypeFamily::DATETIME |
DataTypeFamily::TIME
+ }
+ Self::TimestampWithoutTimeZone => {
+ DataTypeFamily::PREDEFINED | DataTypeFamily::DATETIME |
DataTypeFamily::TIMESTAMP
+ }
+ Self::TimestampWithLocalTimeZone => {
+ DataTypeFamily::PREDEFINED
+ | DataTypeFamily::DATETIME
+ | DataTypeFamily::TIMESTAMP
+ | DataTypeFamily::EXTENSION
+ }
+ Self::Array => DataTypeFamily::CONSTRUCTED |
DataTypeFamily::COLLECTION,
+ Self::Multiset => DataTypeFamily::CONSTRUCTED |
DataTypeFamily::COLLECTION,
+ Self::Map => DataTypeFamily::CONSTRUCTED |
DataTypeFamily::EXTENSION,
+ Self::Row => DataTypeFamily::CONSTRUCTED,
+ }
+ }
+}
+
+/// A visitor that can visit different data types.
+pub trait DataTypeVisitor<R> {
+ fn visit(&mut self, data_type: &DataType) -> R;
+}
+
+/// Data type for paimon table.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L45>
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct DataType {
+ is_nullable: bool,
+ type_root: DataTypeRoot,
+}
+
+impl Display for DataType {
+ fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+}
+
+impl FromStr for DataType {
+ type Err = Error;
+
+ fn from_str(_: &str) -> Result<Self, Self::Err> {
+ todo!()
+ }
+}
+
+#[allow(dead_code)]
+impl DataType {
+ fn new(is_nullable: bool, type_root: DataTypeRoot) -> Self {
+ Self {
+ is_nullable,
+ type_root,
+ }
+ }
+
+ /// Returns a deep copy of this type with possibly different nullability.
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L113>
+ fn with_nullable(&self, is_nullable: bool) -> Self {
+ Self {
+ is_nullable,
+ type_root: self.type_root,
+ }
+ }
+
+ /// Returns true if the data type is nullable.
+ ///
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L59>
+ fn is_nullable(&self) -> bool {
+ self.is_nullable
+ }
+
+ /// Returns the root of the data type.
+ ///
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L66>
+ fn type_root(&self) -> &DataTypeRoot {
+ &self.type_root
+ }
+
+ /// Returns whether the root of the type equals to the type_root or not.
+ ///
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L75>
+ fn is(&self, type_root: &DataTypeRoot) -> bool {
+ &self.type_root == type_root
+ }
+
+ /// Returns whether the family type of the type equals to the family or
not.
+ ///
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L103>
+ fn is_family(&self, family: DataTypeFamily) -> bool {
+ self.type_root.families().contains(family)
+ }
+
+ /// Returns whether the root of the type equals to at least on of the
type_roots or not.
+ ///
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L84>
+ fn is_any_of(&self, type_roots: &[DataTypeRoot]) -> bool {
+ type_roots.iter().any(|tr: &DataTypeRoot| self.is(tr))
+ }
+
+ /// Returns whether the root of the type is part of at least one family of
the families or not.
+ /// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/DataType.java#L94>
+ fn is_any_of_family(&self, families: &[DataTypeFamily]) -> bool {
+ families.iter().any(|f: &DataTypeFamily| self.is_family(*f))
+ }
+
+ fn accept<T>(&self, visitor: &mut T)
+ where
+ T: DataTypeVisitor<T>,
+ {
+ visitor.visit(self);
+ }
+}
+
+/// ArrayType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/ArrayType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[serde(rename_all = "camelCase")]
+pub struct ArrayType {
+ element_type: DataType,
+}
+
+impl Display for ArrayType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ if self.element_type.is_nullable() {
+ write!(f, "ARRAY")
+ } else {
+ write!(f, "ARRAY NOT NULL")
+ }
+ }
+}
+
+impl Default for ArrayType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl ArrayType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Array),
+ }
+ }
+}
+
+/// BigIntType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/BigIntType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct BigIntType {
+ element_type: DataType,
+}
+
+impl Display for BigIntType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "BIGINT")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for BigIntType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl BigIntType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Bigint),
+ }
+ }
+}
+
+/// BinaryType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/BinaryType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+#[serde(rename_all = "camelCase")]
+pub struct BinaryType {
+ element_type: DataType,
+ length: usize,
+}
+
+impl Display for BinaryType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "BINARY({})", self.length)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for BinaryType {
+ fn default() -> Self {
+ Self::new(true, Self::DEFAULT_LENGTH)
+ }
+}
+
+impl BinaryType {
+ pub const MIN_LENGTH: usize = 1;
+
+ pub const MAX_LENGTH: usize = usize::MAX;
+
+ pub const DEFAULT_LENGTH: usize = 1;
+
+ pub fn new(is_nullable: bool, length: usize) -> Self {
+ Self::try_new(is_nullable, length).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, length: usize) -> Result<Self, &'static
str> {
+ if length < Self::MIN_LENGTH {
+ return Err("Binary string length must be at least 1.");
+ }
+ Ok(Self {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::Binary,
+ },
+ length,
+ })
+ }
+
+ pub fn with_length(length: usize) -> Self {
+ Self::new(true, length)
+ }
+
+ pub fn length(&self) -> usize {
+ self.length
+ }
+}
+
+/// BooleanType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/BooleanType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct BooleanType {
+ pub element_type: DataType,
+}
+
+impl Display for BooleanType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "BOOLEAN")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for BooleanType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl BooleanType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Boolean),
+ }
+ }
+}
+
+/// CharType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/db8bcd7fdd9c2705435d2ab1d2341c52d1f67ee5/paimon-common/src/main/java/org/apache/paimon/types/CharType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CharType {
+ element_type: DataType,
+ length: usize,
+}
+
+impl Display for CharType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "CHAR({})", self.length)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for CharType {
+ fn default() -> Self {
+ Self::with_length(Self::DEFAULT_LENGTH)
+ }
+}
+
+impl CharType {
+ pub const DEFAULT_LENGTH: usize = 1;
+
+ pub const MIN_LENGTH: usize = 1;
+
+ pub const MAX_LENGTH: usize = 255;
+
+ pub fn new(is_nullable: bool, length: usize) -> Self {
+ Self::try_new(is_nullable, length).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, length: usize) -> Result<Self, &'static
str> {
+ if !(Self::MIN_LENGTH..=Self::MAX_LENGTH).contains(&length) {
+ return Err("Character string length must be between 1 and 255
(both inclusive).");
+ }
+ Ok(CharType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::Char,
+ },
+ length,
+ })
+ }
+
+ pub fn with_length(length: usize) -> Self {
+ Self::new(true, length)
+ }
+
+ pub fn length(&self) -> usize {
+ self.length
+ }
+}
+
+/// DateType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/DateType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
+pub struct DateType {
+ element_type: DataType,
+}
+
+impl Display for DateType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "DATE")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for DateType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl DateType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Date),
+ }
+ }
+}
+
+/// DecimalType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/DecimalType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct DecimalType {
+ element_type: DataType,
+ precision: u32,
+ scale: u32,
+}
+
+impl Display for DecimalType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "DECIMAL({}, {})", self.precision, self.scale)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for DecimalType {
+ fn default() -> Self {
+ Self::with_precision_and_scale(Self::DEFAULT_PRECISION,
Self::DEFAULT_SCALE)
+ }
+}
+
+impl DecimalType {
+ pub const MIN_PRECISION: u32 = 1;
+
+ pub const MAX_PRECISION: u32 = 38;
+
+ pub const DEFAULT_PRECISION: u32 = 10;
+
+ pub const MIN_SCALE: u32 = 0;
+
+ pub const DEFAULT_SCALE: u32 = 0;
+
+ pub fn new(is_nullable: bool, precision: u32, scale: u32) -> Self {
+ Self::try_new(is_nullable, precision, scale).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, precision: u32, scale: u32) ->
Result<Self, String> {
+ if !(Self::MIN_PRECISION..=Self::MAX_PRECISION).contains(&precision) {
+ return Err(format!(
+ "Decimal precision must be between {} and {} (both
inclusive).",
+ Self::MIN_PRECISION,
+ Self::MAX_PRECISION
+ ));
+ }
+
+ if !(Self::MIN_SCALE..=precision).contains(&scale) {
+ return Err(format!(
+ "Decimal scale must be between {} and the precision {} (both
inclusive).",
+ Self::MIN_SCALE,
+ precision
+ ));
+ }
+
+ Ok(DecimalType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::Decimal,
+ },
+ precision,
+ scale,
+ })
+ }
+
+ pub fn with_precision_and_scale(precision: u32, scale: u32) -> Self {
+ Self::new(true, precision, scale)
+ }
+
+ pub fn precision(&self) -> u32 {
+ self.precision
+ }
+
+ pub fn scale(&self) -> u32 {
+ self.scale
+ }
+}
+
+/// DoubleType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/DoubleType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct DoubleType {
+ element_type: DataType,
+}
+
+impl Display for DoubleType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "DOUBLE")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for DoubleType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl DoubleType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Double),
+ }
+ }
+}
+
+/// FloatType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/FloatType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct FloatType {
+ element_type: DataType,
+}
+
+impl Display for FloatType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "FLOAT")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for FloatType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl FloatType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Float),
+ }
+ }
+}
+
+/// IntType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/IntType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct IntType {
+ element_type: DataType,
+}
+
+impl Display for IntType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "INTEGER")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for IntType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl IntType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Integer),
+ }
+ }
+}
+
+/// LocalZonedTimestampType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/TimestampType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct LocalZonedTimestampType {
+ element_type: DataType,
+ precision: u32,
+}
+
+impl Display for LocalZonedTimestampType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "TIMESTAMP WITH LOCAL TIME ZONE({})", self.precision)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for LocalZonedTimestampType {
+ fn default() -> Self {
+ Self::with_precision(Self::DEFAULT_PRECISION)
+ }
+}
+
+impl LocalZonedTimestampType {
+ pub const MIN_PRECISION: u32 = TimestampType::MIN_PRECISION;
+
+ pub const MAX_PRECISION: u32 = TimestampType::MAX_PRECISION;
+
+ pub const DEFAULT_PRECISION: u32 = TimestampType::DEFAULT_PRECISION;
+
+ pub fn new(is_nullable: bool, precision: u32) -> Self {
+ LocalZonedTimestampType::try_new(is_nullable, precision).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, precision: u32) -> Result<Self, String> {
+ if !(Self::MIN_PRECISION..=Self::MAX_PRECISION).contains(&precision) {
+ return Err(format!(
+ "Timestamp precision must be between {} and {} (both
inclusive).",
+ Self::MIN_PRECISION,
+ Self::MAX_PRECISION
+ ));
+ }
+
+ Ok(LocalZonedTimestampType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::TimestampWithLocalTimeZone,
+ },
+ precision,
+ })
+ }
+
+ pub fn with_precision(precision: u32) -> Self {
+ Self::new(true, precision)
+ }
+
+ pub fn precision(&self) -> u32 {
+ self.precision
+ }
+}
+
+/// Next TODO: MapType、MultisetType、RowType
+
+/// SmallIntType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/SmallIntType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct SmallIntType {
+ element_type: DataType,
+}
+
+impl Display for SmallIntType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "SMALLINT")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for SmallIntType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl SmallIntType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Smallint),
+ }
+ }
+}
+
+/// TimeType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/TimeType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct TimeType {
+ element_type: DataType,
+ precision: u32,
+}
+
+impl Display for TimeType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "TIME({})", self.precision)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for TimeType {
+ fn default() -> Self {
+ Self::with_precision(TimeType::DEFAULT_PRECISION)
+ }
+}
+
+impl TimeType {
+ pub const MIN_PRECISION: u32 = 0;
+
+ pub const MAX_PRECISION: u32 = 9;
+
+ pub const DEFAULT_PRECISION: u32 = 0;
+
+ pub fn new(is_nullable: bool, precision: u32) -> Self {
+ Self::try_new(is_nullable, precision).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, precision: u32) -> Result<Self, String> {
+ if !(Self::MIN_PRECISION..=Self::MAX_PRECISION).contains(&precision) {
+ return Err(format!(
+ "Time precision must be between {} and {} (both inclusive).",
+ Self::MIN_PRECISION,
+ Self::MAX_PRECISION
+ ));
+ }
+
+ Ok(TimeType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::TimeWithoutTimeZone,
+ },
+ precision,
+ })
+ }
+
+ pub fn with_precision(precision: u32) -> Self {
+ Self::new(true, precision)
+ }
+
+ pub fn precision(&self) -> u32 {
+ self.precision
+ }
+}
+
+/// TimestampType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/TimestampType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct TimestampType {
+ element_type: DataType,
+ precision: u32,
+}
+
+impl Display for TimestampType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "TIMESTAMP({})", self.precision)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for TimestampType {
+ fn default() -> Self {
+ Self::with_precision(Self::DEFAULT_PRECISION)
+ }
+}
+
+impl TimestampType {
+ pub const MIN_PRECISION: u32 = 0;
+
+ pub const MAX_PRECISION: u32 = 9;
+
+ pub const DEFAULT_PRECISION: u32 = 6;
+
+ pub fn new(is_nullable: bool, precision: u32) -> Self {
+ Self::try_new(is_nullable, precision).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, precision: u32) -> Result<Self, String> {
+ if !(Self::MIN_PRECISION..=Self::MAX_PRECISION).contains(&precision) {
+ return Err(format!(
+ "Timestamp precision must be between {} and {} (both
inclusive).",
+ Self::MIN_PRECISION,
+ Self::MAX_PRECISION
+ ));
+ }
+
+ Ok(TimestampType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::TimestampWithoutTimeZone,
+ },
+ precision,
+ })
+ }
+
+ pub fn with_precision(precision: u32) -> Self {
+ Self::new(true, precision)
+ }
+
+ pub fn precision(&self) -> u32 {
+ self.precision
+ }
+}
+
+/// TinyIntType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/TinyIntType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct TinyIntType {
+ element_type: DataType,
+}
+
+impl Display for TinyIntType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "TINYINT")?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for TinyIntType {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl TinyIntType {
+ pub fn new(is_nullable: bool) -> Self {
+ Self {
+ element_type: DataType::new(is_nullable, DataTypeRoot::Tinyint),
+ }
+ }
+}
+
+/// VarBinaryType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/VarBinaryType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct VarBinaryType {
+ element_type: DataType,
+ length: u32,
+}
+
+impl Display for VarBinaryType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "VARBINARY({})", self.length)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for VarBinaryType {
+ fn default() -> Self {
+ Self::with_length(Self::DEFAULT_LENGTH)
+ }
+}
+
+impl VarBinaryType {
+ pub const MIN_LENGTH: u32 = 1;
+
+ pub const MAX_LENGTH: u32 = isize::MAX as u32;
+
+ pub const DEFAULT_LENGTH: u32 = 1;
+
+ pub fn new(is_nullable: bool, length: u32) -> Self {
+ Self::try_new(is_nullable, length).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, length: u32) -> Result<Self, String> {
+ if length < Self::MIN_LENGTH {
+ return Err("Binary string length must be at least 1.".to_string());
+ }
+
+ Ok(VarBinaryType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::Varbinary,
+ },
+ length,
+ })
+ }
+
+ pub fn with_length(length: u32) -> Self {
+ Self::new(true, length)
+ }
+
+ pub fn length(&self) -> u32 {
+ self.length
+ }
+}
+
+/// VarCharType for paimon.
+///
+/// Impl Reference:
<https://github.com/apache/paimon/blob/master/paimon-common/src/main/java/org/apache/paimon/types/VarCharType.java>.
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
+pub struct VarCharType {
+ element_type: DataType,
+ length: u32,
+}
+
+impl Display for VarCharType {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "VARCHAR({})", self.length)?;
+ if !self.element_type.is_nullable() {
+ write!(f, " NOT NULL")?;
+ }
+ Ok(())
+ }
+}
+
+impl Default for VarCharType {
+ fn default() -> Self {
+ Self::with_length(Self::DEFAULT_LENGTH)
+ }
+}
+
+impl VarCharType {
+ pub const MIN_LENGTH: u32 = 1;
+
+ pub const MAX_LENGTH: u32 = isize::MAX as u32;
+
+ pub const DEFAULT_LENGTH: u32 = 1;
+
+ pub fn new(is_nullable: bool, length: u32) -> Self {
+ Self::try_new(is_nullable, length).unwrap()
+ }
+
+ pub fn try_new(is_nullable: bool, length: u32) -> Result<Self, String> {
+ if !(Self::MIN_LENGTH..=Self::MAX_LENGTH).contains(&length) {
+ return Err(format!(
+ "Character string length must be between {} and {} (both
inclusive).",
+ Self::MIN_LENGTH,
+ Self::MAX_LENGTH
+ ));
+ }
+
+ Ok(VarCharType {
+ element_type: DataType {
+ is_nullable,
+ type_root: DataTypeRoot::Varchar,
+ },
+ length,
+ })
+ }
+
+ pub fn with_length(length: u32) -> Self {
+ Self::new(true, length)
+ }
+
+ pub fn length(&self) -> u32 {
+ self.length
+ }
+}