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

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 26d2cfe5ed [#8614] feat(client-python): add table and table dto (#8763)
26d2cfe5ed is described below

commit 26d2cfe5edbe08cd412a7a9868a38027c1adb6b8
Author: George T. C. Lai <[email protected]>
AuthorDate: Mon Oct 13 11:57:01 2025 +0800

    [#8614] feat(client-python): add table and table dto (#8763)
    
    ### What changes were proposed in this pull request?
    
    This PR is aimed at implementing classes `Table` and `TableDTO`.
    Furthermore, a refactor of moving package `expressions` into
    `gravitino.api.rel` has been done in this PR as well.
    
    ### Why are the changes needed?
    
    We need to support table operations.
    
    Fix: #8614
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Unit tests
    
    ---------
    
    Signed-off-by: George T. C. Lai <[email protected]>
---
 clients/client-python/gravitino/api/rel/column.py  |   4 +-
 .../api/{ => rel}/expressions/__init__.py          |   0
 .../expressions/distributions/distribution.py      |   4 +-
 .../expressions/distributions/distributions.py     |   8 +-
 .../expressions/distributions/strategy.py          |   0
 .../api/{ => rel}/expressions/expression.py        |   3 +-
 .../{ => rel}/expressions/function_expression.py   |   3 +-
 .../api/{ => rel}/expressions/literals/__init__.py |   0
 .../api/{ => rel}/expressions/literals/literal.py  |   2 +-
 .../api/{ => rel}/expressions/literals/literals.py |   2 +-
 .../api/{ => rel}/expressions/named_reference.py   |   2 +-
 .../api/{ => rel}/expressions/sorts/__init__.py    |   0
 .../{ => rel}/expressions/sorts/null_ordering.py   |   0
 .../{ => rel}/expressions/sorts/sort_direction.py  |   3 +-
 .../api/{ => rel}/expressions/sorts/sort_order.py  |   6 +-
 .../api/{ => rel}/expressions/sorts/sort_orders.py |   8 +-
 .../{ => rel}/expressions/transforms/__init__.py   |   0
 .../{ => rel}/expressions/transforms/transform.py  |   4 +-
 .../{ => rel}/expressions/transforms/transforms.py |  10 +-
 .../{ => rel}/expressions/unparsed_expression.py   |   2 +-
 .../api/rel/partitions/identity_partition.py       |   2 +-
 .../gravitino/api/rel/partitions/list_partition.py |   2 +-
 .../gravitino/api/rel/partitions/partitions.py     |   2 +-
 .../api/rel/partitions/range_partition.py          |   2 +-
 clients/client-python/gravitino/api/rel/table.py   | 112 ++++++
 .../gravitino/api/rel/table_change.py              |   2 +-
 .../gravitino/api/rel/types/json_serdes/base.py    |   6 +-
 .../client-python/gravitino/dto/rel/column_dto.py  |   2 +-
 .../gravitino/dto/rel/distribution_dto.py          |   4 +-
 .../dto/rel/expressions/field_reference_dto.py     |   2 +-
 .../dto/rel/expressions/func_expression_dto.py     |   4 +-
 .../gravitino/dto/rel/expressions/function_arg.py  |   2 +-
 .../json_serdes/column_default_value_serdes.py     |   2 +-
 .../gravitino/dto/rel/expressions/literal_dto.py   |   2 +-
 .../dto/rel/expressions/unparsed_expression_dto.py |   2 +-
 .../dto/rel/json_serdes/distribution_serdes.py     |   2 +-
 .../dto/rel/json_serdes/sort_order_serdes.py       |   4 +-
 .../rel/partitioning/bucket_partitioning_dto.py    |   4 +-
 .../rel/partitioning/function_partitioning_dto.py  |   2 +-
 .../dto/rel/partitioning/list_partitioning_dto.py  |   4 +-
 .../gravitino/dto/rel/partitioning/partitioning.py |   6 +-
 .../dto/rel/partitioning/range_partitioning_dto.py |   4 +-
 .../rel/partitioning/truncate_partitioning_dto.py  |   4 +-
 .../gravitino/dto/rel/sort_order_dto.py            |   8 +-
 .../client-python/gravitino/dto/rel/table_dto.py   | 140 +++++++
 .../tests/unittests/{ => api}/rel/__init__.py      |   0
 .../tests/unittests/{ => api/rel}/test_column.py   |   4 +-
 .../unittests/{ => api}/rel/test_distributions.py  |   6 +-
 .../unittests/{ => api}/rel/test_expressions.py    |   5 +-
 .../{ => api}/rel/test_function_expression.py      |   7 +-
 .../tests/unittests/{ => api}/rel/test_indexes.py  |   0
 .../tests/unittests/{ => api}/rel/test_literals.py |   2 +-
 .../unittests/{ => api}/rel/test_partitions.py     |   2 +-
 .../tests/unittests/{ => api}/rel/test_sorts.py    |  12 +-
 .../unittests/{ => api}/rel/test_table_change.py   |   2 +-
 .../unittests/{ => api}/rel/test_transforms.py     |   6 +-
 .../tests/unittests/{ => api}/rel/test_types.py    |   0
 .../unittests/dto/rel/test_distribution_dto.py     |   2 +-
 .../unittests/dto/rel/test_distribution_serdes.py  |   2 +-
 .../rel/test_non_single_field_partitioning_dto.py  |   4 +-
 .../tests/unittests/dto/rel/test_partitioning.py   |   2 +-
 .../dto/rel/test_single_field_partitioning_dto.py  |   2 +-
 .../tests/unittests/dto/rel/test_sort_order_dto.py |   4 +-
 .../unittests/dto/rel/test_sort_order_serdes.py    |   4 +-
 .../tests/unittests/dto/rel/test_table_dto.py      | 446 +++++++++++++++++++++
 .../tests/unittests/test_named_reference.py        |   3 +-
 .../tests/unittests/test_unparsed_expression.py    |   3 +-
 67 files changed, 805 insertions(+), 100 deletions(-)

diff --git a/clients/client-python/gravitino/api/rel/column.py 
b/clients/client-python/gravitino/api/rel/column.py
index b540a23c22..2a5b4ca52d 100644
--- a/clients/client-python/gravitino/api/rel/column.py
+++ b/clients/client-python/gravitino/api/rel/column.py
@@ -21,8 +21,8 @@ from __future__ import annotations
 from abc import ABC, abstractmethod
 from typing import Optional
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.function_expression import FunctionExpression
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.function_expression import 
FunctionExpression
 from gravitino.api.rel.types.type import Type
 from gravitino.api.tag.supports_tags import SupportsTags
 from gravitino.exceptions.base import UnsupportedOperationException
diff --git a/clients/client-python/gravitino/api/expressions/__init__.py 
b/clients/client-python/gravitino/api/rel/expressions/__init__.py
similarity index 100%
rename from clients/client-python/gravitino/api/expressions/__init__.py
rename to clients/client-python/gravitino/api/rel/expressions/__init__.py
diff --git 
a/clients/client-python/gravitino/api/expressions/distributions/distribution.py 
b/clients/client-python/gravitino/api/rel/expressions/distributions/distribution.py
similarity index 94%
rename from 
clients/client-python/gravitino/api/expressions/distributions/distribution.py
rename to 
clients/client-python/gravitino/api/rel/expressions/distributions/distribution.py
index f0d26e39ac..5c780f572f 100644
--- 
a/clients/client-python/gravitino/api/expressions/distributions/distribution.py
+++ 
b/clients/client-python/gravitino/api/rel/expressions/distributions/distribution.py
@@ -17,8 +17,8 @@
 from abc import abstractmethod
 from typing import List
 
-from gravitino.api.expressions.distributions.strategy import Strategy
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.expression import Expression
 
 
 class Distribution(Expression):
diff --git 
a/clients/client-python/gravitino/api/expressions/distributions/distributions.py
 
b/clients/client-python/gravitino/api/rel/expressions/distributions/distributions.py
similarity index 94%
rename from 
clients/client-python/gravitino/api/expressions/distributions/distributions.py
rename to 
clients/client-python/gravitino/api/rel/expressions/distributions/distributions.py
index a4d4bbd967..3b3b3e3a66 100644
--- 
a/clients/client-python/gravitino/api/expressions/distributions/distributions.py
+++ 
b/clients/client-python/gravitino/api/rel/expressions/distributions/distributions.py
@@ -16,10 +16,10 @@
 # under the License.
 from typing import List
 
-from gravitino.api.expressions.distributions.strategy import Strategy
-from gravitino.api.expressions.distributions.distribution import Distribution
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.distributions.distribution import 
Distribution
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
 
 
 class DistributionImpl(Distribution):
diff --git 
a/clients/client-python/gravitino/api/expressions/distributions/strategy.py 
b/clients/client-python/gravitino/api/rel/expressions/distributions/strategy.py
similarity index 100%
rename from 
clients/client-python/gravitino/api/expressions/distributions/strategy.py
rename to 
clients/client-python/gravitino/api/rel/expressions/distributions/strategy.py
diff --git a/clients/client-python/gravitino/api/expressions/expression.py 
b/clients/client-python/gravitino/api/rel/expressions/expression.py
similarity index 95%
rename from clients/client-python/gravitino/api/expressions/expression.py
rename to clients/client-python/gravitino/api/rel/expressions/expression.py
index 185db2ef43..1f7dd03058 100644
--- a/clients/client-python/gravitino/api/expressions/expression.py
+++ b/clients/client-python/gravitino/api/rel/expressions/expression.py
@@ -16,11 +16,12 @@
 # under the License.
 
 from __future__ import annotations
+
 from abc import ABC, abstractmethod
 from typing import TYPE_CHECKING, List
 
 if TYPE_CHECKING:
-    from gravitino.api.expressions.named_reference import NamedReference
+    from gravitino.api.rel.expressions.named_reference import NamedReference
 
 
 class Expression(ABC):
diff --git 
a/clients/client-python/gravitino/api/expressions/function_expression.py 
b/clients/client-python/gravitino/api/rel/expressions/function_expression.py
similarity index 97%
rename from 
clients/client-python/gravitino/api/expressions/function_expression.py
rename to 
clients/client-python/gravitino/api/rel/expressions/function_expression.py
index 7664cf9bf8..98bd5ef3a3 100644
--- a/clients/client-python/gravitino/api/expressions/function_expression.py
+++ b/clients/client-python/gravitino/api/rel/expressions/function_expression.py
@@ -16,9 +16,10 @@
 # under the License.
 
 from __future__ import annotations
+
 from abc import abstractmethod
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 
 
 class FunctionExpression(Expression):
diff --git 
a/clients/client-python/gravitino/api/expressions/literals/__init__.py 
b/clients/client-python/gravitino/api/rel/expressions/literals/__init__.py
similarity index 100%
rename from clients/client-python/gravitino/api/expressions/literals/__init__.py
rename to 
clients/client-python/gravitino/api/rel/expressions/literals/__init__.py
diff --git 
a/clients/client-python/gravitino/api/expressions/literals/literal.py 
b/clients/client-python/gravitino/api/rel/expressions/literals/literal.py
similarity index 95%
rename from clients/client-python/gravitino/api/expressions/literals/literal.py
rename to 
clients/client-python/gravitino/api/rel/expressions/literals/literal.py
index b1edbc5068..ffd0cfb090 100644
--- a/clients/client-python/gravitino/api/expressions/literals/literal.py
+++ b/clients/client-python/gravitino/api/rel/expressions/literals/literal.py
@@ -18,7 +18,7 @@
 from abc import abstractmethod
 from typing import Generic, List, TypeVar
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.api.rel.types.type import Type
 
 T = TypeVar("T")
diff --git 
a/clients/client-python/gravitino/api/expressions/literals/literals.py 
b/clients/client-python/gravitino/api/rel/expressions/literals/literals.py
similarity index 98%
rename from clients/client-python/gravitino/api/expressions/literals/literals.py
rename to 
clients/client-python/gravitino/api/rel/expressions/literals/literals.py
index e5c85f1568..e45fb7fb2e 100644
--- a/clients/client-python/gravitino/api/expressions/literals/literals.py
+++ b/clients/client-python/gravitino/api/rel/expressions/literals/literals.py
@@ -18,7 +18,7 @@ import decimal
 from datetime import date, datetime, time
 from typing import TypeVar
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.types.type import Type
 from gravitino.api.rel.types.types import Types
 
diff --git a/clients/client-python/gravitino/api/expressions/named_reference.py 
b/clients/client-python/gravitino/api/rel/expressions/named_reference.py
similarity index 97%
rename from clients/client-python/gravitino/api/expressions/named_reference.py
rename to clients/client-python/gravitino/api/rel/expressions/named_reference.py
index 3b766b4ac2..48c8c935fa 100644
--- a/clients/client-python/gravitino/api/expressions/named_reference.py
+++ b/clients/client-python/gravitino/api/rel/expressions/named_reference.py
@@ -17,7 +17,7 @@
 
 from __future__ import annotations
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 
 
 class NamedReference(Expression):
diff --git a/clients/client-python/gravitino/api/expressions/sorts/__init__.py 
b/clients/client-python/gravitino/api/rel/expressions/sorts/__init__.py
similarity index 100%
rename from clients/client-python/gravitino/api/expressions/sorts/__init__.py
rename to clients/client-python/gravitino/api/rel/expressions/sorts/__init__.py
diff --git 
a/clients/client-python/gravitino/api/expressions/sorts/null_ordering.py 
b/clients/client-python/gravitino/api/rel/expressions/sorts/null_ordering.py
similarity index 100%
rename from 
clients/client-python/gravitino/api/expressions/sorts/null_ordering.py
rename to 
clients/client-python/gravitino/api/rel/expressions/sorts/null_ordering.py
diff --git 
a/clients/client-python/gravitino/api/expressions/sorts/sort_direction.py 
b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_direction.py
similarity index 97%
rename from 
clients/client-python/gravitino/api/expressions/sorts/sort_direction.py
rename to 
clients/client-python/gravitino/api/rel/expressions/sorts/sort_direction.py
index 23694b019c..f594a2809f 100644
--- a/clients/client-python/gravitino/api/expressions/sorts/sort_direction.py
+++ 
b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_direction.py
@@ -15,7 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 from enum import Enum
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
+
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
 
 
 class SortDirection(Enum):
diff --git 
a/clients/client-python/gravitino/api/expressions/sorts/sort_order.py 
b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_order.py
similarity index 87%
rename from clients/client-python/gravitino/api/expressions/sorts/sort_order.py
rename to 
clients/client-python/gravitino/api/rel/expressions/sorts/sort_order.py
index ae7a1bb27b..3aa87ba572 100644
--- a/clients/client-python/gravitino/api/expressions/sorts/sort_order.py
+++ b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_order.py
@@ -17,9 +17,9 @@
 from abc import ABC, abstractmethod
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
 
 
 class SortOrder(Expression, ABC):
diff --git 
a/clients/client-python/gravitino/api/expressions/sorts/sort_orders.py 
b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_orders.py
similarity index 91%
rename from clients/client-python/gravitino/api/expressions/sorts/sort_orders.py
rename to 
clients/client-python/gravitino/api/rel/expressions/sorts/sort_orders.py
index 4d01cb1421..8a08f5eed9 100644
--- a/clients/client-python/gravitino/api/expressions/sorts/sort_orders.py
+++ b/clients/client-python/gravitino/api/rel/expressions/sorts/sort_orders.py
@@ -16,10 +16,10 @@
 # under the License.
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
-from gravitino.api.expressions.sorts.sort_order import SortOrder
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.sort_order import SortOrder
 
 
 class SortImpl(SortOrder):
diff --git 
a/clients/client-python/gravitino/api/expressions/transforms/__init__.py 
b/clients/client-python/gravitino/api/rel/expressions/transforms/__init__.py
similarity index 100%
rename from 
clients/client-python/gravitino/api/expressions/transforms/__init__.py
rename to 
clients/client-python/gravitino/api/rel/expressions/transforms/__init__.py
diff --git 
a/clients/client-python/gravitino/api/expressions/transforms/transform.py 
b/clients/client-python/gravitino/api/rel/expressions/transforms/transform.py
similarity index 95%
rename from 
clients/client-python/gravitino/api/expressions/transforms/transform.py
rename to 
clients/client-python/gravitino/api/rel/expressions/transforms/transform.py
index e653be0988..50a193dd9a 100644
--- a/clients/client-python/gravitino/api/expressions/transforms/transform.py
+++ 
b/clients/client-python/gravitino/api/rel/expressions/transforms/transform.py
@@ -18,8 +18,8 @@
 from abc import ABC, abstractmethod
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.api.rel.partitions.partition import Partition
 from gravitino.api.rel.partitions.partitions import Partitions
 
diff --git 
a/clients/client-python/gravitino/api/expressions/transforms/transforms.py 
b/clients/client-python/gravitino/api/rel/expressions/transforms/transforms.py
similarity index 97%
rename from 
clients/client-python/gravitino/api/expressions/transforms/transforms.py
rename to 
clients/client-python/gravitino/api/rel/expressions/transforms/transforms.py
index 8d587ead45..a928e241d3 100644
--- a/clients/client-python/gravitino/api/expressions/transforms/transforms.py
+++ 
b/clients/client-python/gravitino/api/rel/expressions/transforms/transforms.py
@@ -17,11 +17,11 @@
 
 from typing import ClassVar, List, Optional, Union, overload
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.expressions.literals.literals import Literals
-from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.transforms.transform import (
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literals import Literals
+from gravitino.api.rel.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.transforms.transform import (
     SingleFieldTransform,
     Transform,
 )
diff --git 
a/clients/client-python/gravitino/api/expressions/unparsed_expression.py 
b/clients/client-python/gravitino/api/rel/expressions/unparsed_expression.py
similarity index 97%
rename from 
clients/client-python/gravitino/api/expressions/unparsed_expression.py
rename to 
clients/client-python/gravitino/api/rel/expressions/unparsed_expression.py
index 55ca327567..0057cfc243 100644
--- a/clients/client-python/gravitino/api/expressions/unparsed_expression.py
+++ b/clients/client-python/gravitino/api/rel/expressions/unparsed_expression.py
@@ -17,7 +17,7 @@
 
 from __future__ import annotations
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 
 
 class UnparsedExpression(Expression):
diff --git 
a/clients/client-python/gravitino/api/rel/partitions/identity_partition.py 
b/clients/client-python/gravitino/api/rel/partitions/identity_partition.py
index 75e175dedc..93cb8aa12b 100644
--- a/clients/client-python/gravitino/api/rel/partitions/identity_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/identity_partition.py
@@ -18,7 +18,7 @@
 from abc import abstractmethod
 from typing import Any, List
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.partitions.partition import Partition
 
 
diff --git 
a/clients/client-python/gravitino/api/rel/partitions/list_partition.py 
b/clients/client-python/gravitino/api/rel/partitions/list_partition.py
index 4f30020ee8..1b1dda422a 100644
--- a/clients/client-python/gravitino/api/rel/partitions/list_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/list_partition.py
@@ -18,7 +18,7 @@
 from abc import abstractmethod
 from typing import Any, List
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.partitions.partition import Partition
 
 
diff --git a/clients/client-python/gravitino/api/rel/partitions/partitions.py 
b/clients/client-python/gravitino/api/rel/partitions/partitions.py
index 10b2a43698..3e156dbc9b 100644
--- a/clients/client-python/gravitino/api/rel/partitions/partitions.py
+++ b/clients/client-python/gravitino/api/rel/partitions/partitions.py
@@ -17,7 +17,7 @@
 
 from typing import Any, Dict, List, Optional
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.partitions.identity_partition import IdentityPartition
 from gravitino.api.rel.partitions.list_partition import ListPartition
 from gravitino.api.rel.partitions.partition import Partition
diff --git 
a/clients/client-python/gravitino/api/rel/partitions/range_partition.py 
b/clients/client-python/gravitino/api/rel/partitions/range_partition.py
index b3f4e0af80..8f3180191a 100644
--- a/clients/client-python/gravitino/api/rel/partitions/range_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/range_partition.py
@@ -18,7 +18,7 @@
 from abc import abstractmethod
 from typing import Any
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.partitions.partition import Partition
 
 
diff --git a/clients/client-python/gravitino/api/rel/table.py 
b/clients/client-python/gravitino/api/rel/table.py
new file mode 100644
index 0000000000..f0f5af9147
--- /dev/null
+++ b/clients/client-python/gravitino/api/rel/table.py
@@ -0,0 +1,112 @@
+# 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.
+
+from abc import abstractmethod
+from typing import Optional
+
+from gravitino.api.auditable import Auditable
+from gravitino.api.rel.column import Column
+from gravitino.api.rel.expressions.distributions.distribution import 
Distribution
+from gravitino.api.rel.expressions.distributions.distributions import 
Distributions
+from gravitino.api.rel.expressions.sorts.sort_order import SortOrder
+from gravitino.api.rel.expressions.transforms.transform import Transform
+from gravitino.api.rel.expressions.transforms.transforms import Transforms
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.indexes.indexes import Indexes
+
+
+class Table(Auditable):
+    """An interface representing a table in a `Namespace`.
+
+    It defines the basic properties of a table. A catalog implementation with 
`TableCatalog`
+    should implement this interface.
+    """
+
+    @abstractmethod
+    def name(self) -> str:
+        """Gets name of the table.
+
+        Returns:
+            str: Name of the table.
+        """
+
+    @abstractmethod
+    def columns(self) -> list[Column]:
+        """Gets the columns of the table.
+
+        Returns:
+            list[Column]: The columns of the table.
+        """
+
+    def partitioning(self) -> list[Transform]:
+        """Gets the physical partitioning of the table.
+
+        Returns:
+            list[Transform]: The physical partitioning of the table.
+        """
+
+        return Transforms.EMPTY_TRANSFORM
+
+    def sort_order(self) -> list[SortOrder]:
+        """Gets the sort order of the table.
+
+        Returns:
+            list[SortOrder]:
+                The sort order of the table. If no sort order is specified, an 
empty list is returned.
+        """
+
+        return []
+
+    def distribution(self) -> Distribution:
+        """Gets the bucketing of the table.
+
+        Returns:
+            Distribution:
+                The bucketing of the table. If no bucketing is specified, 
`Distribution.NONE` is returned.
+        """
+
+        return Distributions.NONE
+
+    def index(self) -> list[Index]:
+        """Gets the indexes of the table.
+
+        Returns:
+            list[Index]:
+                The indexes of the table. If no indexes are specified, 
`Indexes.EMPTY_INDEXES` is returned.
+        """
+
+        return Indexes.EMPTY_INDEXES
+
+    def comment(self) -> Optional[str]:
+        """Gets the comment of the table.
+
+        Returns:
+            str (optional):
+                The comment of the table. `None` is returned if no comment is 
set.
+        """
+
+        return None
+
+    def properties(self) -> dict[str, str]:
+        """Gets the properties of the table.
+
+        Returns:
+            dict[str, str]:
+                The properties of the table. Empty dictionary is returned if 
no properties are set.
+        """
+
+        return {}
diff --git a/clients/client-python/gravitino/api/rel/table_change.py 
b/clients/client-python/gravitino/api/rel/table_change.py
index 8c1de696a8..8b79ef0393 100644
--- a/clients/client-python/gravitino/api/rel/table_change.py
+++ b/clients/client-python/gravitino/api/rel/table_change.py
@@ -21,8 +21,8 @@ from typing import Optional, cast, final
 
 from dataclasses_json import config
 
-from gravitino.api.expressions.expression import Expression
 from gravitino.api.rel.column import Column
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.api.rel.indexes.index import Index
 from gravitino.api.rel.types.type import Type
 
diff --git a/clients/client-python/gravitino/api/rel/types/json_serdes/base.py 
b/clients/client-python/gravitino/api/rel/types/json_serdes/base.py
index aa20d76ba7..c04f4f23ed 100644
--- a/clients/client-python/gravitino/api/rel/types/json_serdes/base.py
+++ b/clients/client-python/gravitino/api/rel/types/json_serdes/base.py
@@ -20,9 +20,9 @@ from typing import Generic, TypeVar, Union
 
 from dataclasses_json.core import Json
 
-from gravitino.api.expressions.distributions.distribution import Distribution
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.sorts.sort_order import SortOrder
+from gravitino.api.rel.expressions.distributions.distribution import 
Distribution
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.sorts.sort_order import SortOrder
 from gravitino.api.rel.indexes.index import Index
 from gravitino.api.rel.types.types import Type
 from gravitino.dto.rel.partitioning.partitioning import Partitioning
diff --git a/clients/client-python/gravitino/dto/rel/column_dto.py 
b/clients/client-python/gravitino/dto/rel/column_dto.py
index fba28be2ec..521348c7c0 100644
--- a/clients/client-python/gravitino/dto/rel/column_dto.py
+++ b/clients/client-python/gravitino/dto/rel/column_dto.py
@@ -22,8 +22,8 @@ from typing import List, Optional, Union, cast
 
 from dataclasses_json import DataClassJsonMixin, config
 
-from gravitino.api.expressions.expression import Expression
 from gravitino.api.rel.column import Column
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.api.rel.types.json_serdes.type_serdes import TypeSerdes
 from gravitino.api.rel.types.type import Type
 from gravitino.api.rel.types.types import Types
diff --git a/clients/client-python/gravitino/dto/rel/distribution_dto.py 
b/clients/client-python/gravitino/dto/rel/distribution_dto.py
index 3bbb1339bc..ab6b196dcd 100644
--- a/clients/client-python/gravitino/dto/rel/distribution_dto.py
+++ b/clients/client-python/gravitino/dto/rel/distribution_dto.py
@@ -17,8 +17,8 @@
 
 from typing import List
 
-from gravitino.api.expressions.distributions.distribution import Distribution
-from gravitino.api.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.distributions.distribution import 
Distribution
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 from gravitino.utils.precondition import Precondition
diff --git 
a/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py 
b/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
index 633a216376..57ad0bc5f8 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
@@ -19,7 +19,7 @@ from __future__ import annotations
 
 from typing import List
 
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 
 
diff --git 
a/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py 
b/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
index a61f08ee52..4fdde585a1 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
@@ -19,8 +19,8 @@ from __future__ import annotations
 
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.function_expression import FunctionExpression
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.function_expression import 
FunctionExpression
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 
 
diff --git 
a/clients/client-python/gravitino/dto/rel/expressions/function_arg.py 
b/clients/client-python/gravitino/dto/rel/expressions/function_arg.py
index 5c53a365cd..b45a1ba019 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/function_arg.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/function_arg.py
@@ -21,7 +21,7 @@ from abc import abstractmethod
 from enum import Enum, unique
 from typing import TYPE_CHECKING, ClassVar, List
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.dto.rel.partition_utils import PartitionUtils
 
 if TYPE_CHECKING:
diff --git 
a/clients/client-python/gravitino/dto/rel/expressions/json_serdes/column_default_value_serdes.py
 
b/clients/client-python/gravitino/dto/rel/expressions/json_serdes/column_default_value_serdes.py
index 2b6905619b..541eeaaf7d 100644
--- 
a/clients/client-python/gravitino/dto/rel/expressions/json_serdes/column_default_value_serdes.py
+++ 
b/clients/client-python/gravitino/dto/rel/expressions/json_serdes/column_default_value_serdes.py
@@ -19,8 +19,8 @@ from typing import overload
 
 from dataclasses_json.core import Json
 
-from gravitino.api.expressions.expression import Expression
 from gravitino.api.rel.column import Column
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.api.rel.types.json_serdes.base import JsonSerializable
 from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import 
SerdesUtils
 
diff --git a/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py 
b/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
index 31dc1cc2cc..1fc513bcea 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
@@ -19,7 +19,7 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, ClassVar
 
-from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.expressions.literals.literal import Literal
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 
diff --git 
a/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
 
b/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
index 420b80c1b1..dedbeac4c5 100644
--- 
a/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
@@ -17,7 +17,7 @@
 
 from __future__ import annotations
 
-from gravitino.api.expressions.unparsed_expression import UnparsedExpression
+from gravitino.api.rel.expressions.unparsed_expression import 
UnparsedExpression
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 
 
diff --git 
a/clients/client-python/gravitino/dto/rel/json_serdes/distribution_serdes.py 
b/clients/client-python/gravitino/dto/rel/json_serdes/distribution_serdes.py
index eb0993a433..196d5bfe1e 100644
--- a/clients/client-python/gravitino/dto/rel/json_serdes/distribution_serdes.py
+++ b/clients/client-python/gravitino/dto/rel/json_serdes/distribution_serdes.py
@@ -18,7 +18,7 @@
 
 from typing import Any
 
-from gravitino.api.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
 from gravitino.api.rel.types.json_serdes.base import JsonSerializable
 from gravitino.dto.rel.distribution_dto import DistributionDTO
 from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import 
SerdesUtils
diff --git 
a/clients/client-python/gravitino/dto/rel/json_serdes/sort_order_serdes.py 
b/clients/client-python/gravitino/dto/rel/json_serdes/sort_order_serdes.py
index bd457066aa..29d956c1bd 100644
--- a/clients/client-python/gravitino/dto/rel/json_serdes/sort_order_serdes.py
+++ b/clients/client-python/gravitino/dto/rel/json_serdes/sort_order_serdes.py
@@ -17,8 +17,8 @@
 
 from typing import Any, Dict
 
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
 from gravitino.api.rel.types.json_serdes import JsonSerializable
 from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import 
SerdesUtils
 from gravitino.dto.rel.sort_order_dto import SortOrderDTO
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/bucket_partitioning_dto.py
 
b/clients/client-python/gravitino/dto/rel/partitioning/bucket_partitioning_dto.py
index ca845f460f..373076e3a1 100644
--- 
a/clients/client-python/gravitino/dto/rel/partitioning/bucket_partitioning_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/partitioning/bucket_partitioning_dto.py
@@ -17,8 +17,8 @@
 
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.transforms.transforms import Transforms
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.transforms.transforms import Transforms
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partition_utils import PartitionUtils
 from gravitino.dto.rel.partitioning.partitioning import Partitioning
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/function_partitioning_dto.py
 
b/clients/client-python/gravitino/dto/rel/partitioning/function_partitioning_dto.py
index 0289925f3e..a2ad06146f 100644
--- 
a/clients/client-python/gravitino/dto/rel/partitioning/function_partitioning_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/partitioning/function_partitioning_dto.py
@@ -17,7 +17,7 @@
 
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 from gravitino.dto.rel.partition_utils import PartitionUtils
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/list_partitioning_dto.py 
b/clients/client-python/gravitino/dto/rel/partitioning/list_partitioning_dto.py
index 8dcee8fd7b..a979265d07 100644
--- 
a/clients/client-python/gravitino/dto/rel/partitioning/list_partitioning_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/partitioning/list_partitioning_dto.py
@@ -17,8 +17,8 @@
 
 from typing import List, Optional
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partition_utils import PartitionUtils
 from gravitino.dto.rel.partitioning.partitioning import Partitioning
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/partitioning.py 
b/clients/client-python/gravitino/dto/rel/partitioning/partitioning.py
index f505cfcdbb..753df0467b 100644
--- a/clients/client-python/gravitino/dto/rel/partitioning/partitioning.py
+++ b/clients/client-python/gravitino/dto/rel/partitioning/partitioning.py
@@ -19,9 +19,9 @@ from abc import abstractmethod
 from enum import Enum, unique
 from typing import Final, List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.transforms.transform import Transform
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.transforms.transform import Transform
 from gravitino.dto.rel.partition_utils import PartitionUtils
 from gravitino.exceptions.base import IllegalArgumentException
 from gravitino.utils.precondition import Precondition
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/range_partitioning_dto.py
 
b/clients/client-python/gravitino/dto/rel/partitioning/range_partitioning_dto.py
index a301e282e6..1df016083c 100644
--- 
a/clients/client-python/gravitino/dto/rel/partitioning/range_partitioning_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/partitioning/range_partitioning_dto.py
@@ -17,8 +17,8 @@
 
 from typing import List, Optional
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partition_utils import PartitionUtils
 from gravitino.dto.rel.partitioning.partitioning import Partitioning
diff --git 
a/clients/client-python/gravitino/dto/rel/partitioning/truncate_partitioning_dto.py
 
b/clients/client-python/gravitino/dto/rel/partitioning/truncate_partitioning_dto.py
index daed9be667..eb4b2bd6ad 100644
--- 
a/clients/client-python/gravitino/dto/rel/partitioning/truncate_partitioning_dto.py
+++ 
b/clients/client-python/gravitino/dto/rel/partitioning/truncate_partitioning_dto.py
@@ -17,8 +17,8 @@
 
 from typing import List
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.transforms.transforms import Transforms
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.transforms.transforms import Transforms
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partition_utils import PartitionUtils
 from gravitino.dto.rel.partitioning.partitioning import Partitioning
diff --git a/clients/client-python/gravitino/dto/rel/sort_order_dto.py 
b/clients/client-python/gravitino/dto/rel/sort_order_dto.py
index 53141d1a12..6256e09307 100644
--- a/clients/client-python/gravitino/dto/rel/sort_order_dto.py
+++ b/clients/client-python/gravitino/dto/rel/sort_order_dto.py
@@ -17,10 +17,10 @@
 
 from typing import ClassVar
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
-from gravitino.api.expressions.sorts.sort_order import SortOrder
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.sort_order import SortOrder
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.expressions.function_arg import FunctionArg
 
diff --git a/clients/client-python/gravitino/dto/rel/table_dto.py 
b/clients/client-python/gravitino/dto/rel/table_dto.py
new file mode 100644
index 0000000000..d64344083f
--- /dev/null
+++ b/clients/client-python/gravitino/dto/rel/table_dto.py
@@ -0,0 +1,140 @@
+# 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.
+
+from dataclasses import dataclass, field
+from typing import Optional
+
+from dataclasses_json import DataClassJsonMixin, config
+
+from gravitino.api.rel.expressions.distributions.distribution import 
Distribution
+from gravitino.api.rel.expressions.transforms.transform import Transform
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.table import Table
+from gravitino.dto.audit_dto import AuditDTO
+from gravitino.dto.rel.column_dto import ColumnDTO
+from gravitino.dto.rel.distribution_dto import DistributionDTO
+from gravitino.dto.rel.indexes.index_dto import IndexDTO
+from gravitino.dto.rel.indexes.json_serdes.index_serdes import IndexSerdes
+from gravitino.dto.rel.json_serdes.distribution_serdes import 
DistributionSerDes
+from gravitino.dto.rel.json_serdes.sort_order_serdes import SortOrderSerdes
+from gravitino.dto.rel.partitioning.json_serdes.partitioning_serdes import (
+    PartitioningSerdes,
+)
+from gravitino.dto.rel.partitioning.partitioning import Partitioning
+from gravitino.dto.rel.sort_order_dto import SortOrderDTO
+from gravitino.utils.precondition import Precondition
+
+
+@dataclass
+class TableDTO(Table, DataClassJsonMixin):  # pylint: disable=R0902
+    """Represents a Table DTO (Data Transfer Object)."""
+
+    _name: Optional[str] = field(default=None, 
metadata=config(field_name="name"))
+    _columns: Optional[list[ColumnDTO]] = field(
+        default=None, metadata=config(field_name="columns")
+    )
+    _audit: Optional[AuditDTO] = field(
+        default=None, metadata=config(field_name="audit")
+    )
+    _comment: Optional[str] = field(
+        default=None,
+        metadata=config(field_name="comment", exclude=lambda value: value is 
None),
+    )
+    _distribution: Optional[DistributionDTO] = field(
+        default=None,
+        metadata=config(
+            field_name="distribution",
+            encoder=DistributionSerDes.serialize,
+            decoder=DistributionSerDes.deserialize,
+            exclude=lambda value: value is None,
+        ),
+    )
+    _sort_orders: Optional[list[SortOrderDTO]] = field(
+        default=None,
+        metadata=config(
+            field_name="sortOrders",
+            encoder=lambda items: [SortOrderSerdes.serialize(item) for item in 
items],
+            decoder=lambda values: [
+                SortOrderSerdes.deserialize(value) for value in values
+            ],
+            exclude=lambda value: value is None,
+        ),
+    )
+    _partitioning: Optional[list[Partitioning]] = field(
+        default=None,
+        metadata=config(
+            field_name="partitioning",
+            encoder=lambda items: [
+                PartitioningSerdes.serialize(item) for item in items
+            ],
+            decoder=lambda values: [
+                PartitioningSerdes.deserialize(value) for value in values
+            ],
+            exclude=lambda value: value is None,
+        ),
+    )
+    _indexes: Optional[list[IndexDTO]] = field(
+        default=None,
+        metadata=config(
+            field_name="indexes",
+            encoder=lambda items: [IndexSerdes.serialize(item) for item in 
items],
+            decoder=lambda values: [IndexSerdes.deserialize(value) for value 
in values],
+            exclude=lambda value: value is None,
+        ),
+    )
+    _properties: Optional[dict[str, str]] = field(
+        default=None,
+        metadata=config(field_name="properties", exclude=lambda value: value 
is None),
+    )
+
+    def __post_init__(self):
+        Precondition.check_argument(
+            self._name is not None and self._name != "",
+            "name cannot be null or empty",
+        )
+        Precondition.check_argument(self._audit is not None, "audit cannot be 
null")
+        Precondition.check_argument(
+            self._columns is not None and len(self._columns) > 0,
+            "columns cannot be null or empty",
+        )
+
+    def name(self) -> str:
+        return self._name
+
+    def comment(self) -> Optional[str]:
+        return self._comment
+
+    def columns(self) -> list[ColumnDTO]:
+        return self._columns
+
+    def audit_info(self) -> AuditDTO:
+        return self._audit
+
+    def properties(self) -> Optional[dict[str, str]]:
+        return self._properties
+
+    def partitioning(self) -> Optional[list[Transform]]:
+        return self._partitioning
+
+    def sort_order(self) -> Optional[list[SortOrderDTO]]:
+        return self._sort_orders
+
+    def distribution(self) -> Optional[Distribution]:
+        return self._distribution
+
+    def index(self) -> Optional[list[Index]]:
+        return self._indexes
diff --git a/clients/client-python/tests/unittests/rel/__init__.py 
b/clients/client-python/tests/unittests/api/rel/__init__.py
similarity index 100%
rename from clients/client-python/tests/unittests/rel/__init__.py
rename to clients/client-python/tests/unittests/api/rel/__init__.py
diff --git a/clients/client-python/tests/unittests/test_column.py 
b/clients/client-python/tests/unittests/api/rel/test_column.py
similarity index 96%
rename from clients/client-python/tests/unittests/test_column.py
rename to clients/client-python/tests/unittests/api/rel/test_column.py
index d3ca33c73f..b03a88608b 100644
--- a/clients/client-python/tests/unittests/test_column.py
+++ b/clients/client-python/tests/unittests/api/rel/test_column.py
@@ -18,9 +18,9 @@
 import unittest
 from unittest.mock import Mock
 
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.function_expression import FunctionExpression
 from gravitino.api.rel.column import Column, ColumnImpl
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.function_expression import 
FunctionExpression
 from gravitino.api.rel.types.type import Type
 from gravitino.exceptions.base import (
     IllegalArgumentException,
diff --git a/clients/client-python/tests/unittests/rel/test_distributions.py 
b/clients/client-python/tests/unittests/api/rel/test_distributions.py
similarity index 95%
rename from clients/client-python/tests/unittests/rel/test_distributions.py
rename to clients/client-python/tests/unittests/api/rel/test_distributions.py
index 85976aaf95..93e8b26df5 100644
--- a/clients/client-python/tests/unittests/rel/test_distributions.py
+++ b/clients/client-python/tests/unittests/api/rel/test_distributions.py
@@ -18,12 +18,12 @@
 import unittest
 from typing import List
 
-from gravitino.api.expressions.distributions.distributions import (
+from gravitino.api.rel.expressions.distributions.distributions import (
     DistributionImpl,
     Distributions,
 )
-from gravitino.api.expressions.distributions.strategy import Strategy
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.expression import Expression
 
 
 class MockExpression(Expression):
diff --git a/clients/client-python/tests/unittests/rel/test_expressions.py 
b/clients/client-python/tests/unittests/api/rel/test_expressions.py
similarity index 94%
rename from clients/client-python/tests/unittests/rel/test_expressions.py
rename to clients/client-python/tests/unittests/api/rel/test_expressions.py
index 6054c1fde6..b8fdb6a9b3 100644
--- a/clients/client-python/tests/unittests/rel/test_expressions.py
+++ b/clients/client-python/tests/unittests/api/rel/test_expressions.py
@@ -17,8 +17,9 @@
 
 import unittest
 from typing import List
-from gravitino.api.expressions.expression import Expression
-from gravitino.api.expressions.named_reference import NamedReference
+
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.named_reference import NamedReference
 
 
 class MockExpression(Expression):
diff --git 
a/clients/client-python/tests/unittests/rel/test_function_expression.py 
b/clients/client-python/tests/unittests/api/rel/test_function_expression.py
similarity index 94%
rename from 
clients/client-python/tests/unittests/rel/test_function_expression.py
rename to 
clients/client-python/tests/unittests/api/rel/test_function_expression.py
index deaa2089e2..5b30ed4033 100644
--- a/clients/client-python/tests/unittests/rel/test_function_expression.py
+++ b/clients/client-python/tests/unittests/api/rel/test_function_expression.py
@@ -16,11 +16,12 @@
 # under the License.
 
 import unittest
-from gravitino.api.expressions.function_expression import (
-    FunctionExpression,
+
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.function_expression import (
     FuncExpressionImpl,
+    FunctionExpression,
 )
-from gravitino.api.expressions.expression import Expression
 
 
 class MockExpression(Expression):
diff --git a/clients/client-python/tests/unittests/rel/test_indexes.py 
b/clients/client-python/tests/unittests/api/rel/test_indexes.py
similarity index 100%
rename from clients/client-python/tests/unittests/rel/test_indexes.py
rename to clients/client-python/tests/unittests/api/rel/test_indexes.py
diff --git a/clients/client-python/tests/unittests/rel/test_literals.py 
b/clients/client-python/tests/unittests/api/rel/test_literals.py
similarity index 98%
rename from clients/client-python/tests/unittests/rel/test_literals.py
rename to clients/client-python/tests/unittests/api/rel/test_literals.py
index 577b19f297..59b17b2e48 100644
--- a/clients/client-python/tests/unittests/rel/test_literals.py
+++ b/clients/client-python/tests/unittests/api/rel/test_literals.py
@@ -18,7 +18,7 @@ import unittest
 from datetime import date, datetime, time
 from decimal import Decimal
 
-from gravitino.api.expressions.literals.literals import Literals
+from gravitino.api.rel.expressions.literals.literals import Literals
 from gravitino.api.rel.types.types import Types
 
 
diff --git a/clients/client-python/tests/unittests/rel/test_partitions.py 
b/clients/client-python/tests/unittests/api/rel/test_partitions.py
similarity index 98%
rename from clients/client-python/tests/unittests/rel/test_partitions.py
rename to clients/client-python/tests/unittests/api/rel/test_partitions.py
index b6fc768481..00cc81c8b4 100644
--- a/clients/client-python/tests/unittests/rel/test_partitions.py
+++ b/clients/client-python/tests/unittests/api/rel/test_partitions.py
@@ -17,7 +17,7 @@
 import unittest
 from datetime import date
 
-from gravitino.api.expressions.literals.literals import Literals
+from gravitino.api.rel.expressions.literals.literals import Literals
 from gravitino.api.rel.partitions.partitions import Partitions
 
 
diff --git a/clients/client-python/tests/unittests/rel/test_sorts.py 
b/clients/client-python/tests/unittests/api/rel/test_sorts.py
similarity index 91%
rename from clients/client-python/tests/unittests/rel/test_sorts.py
rename to clients/client-python/tests/unittests/api/rel/test_sorts.py
index 7116add4de..40172536f0 100644
--- a/clients/client-python/tests/unittests/rel/test_sorts.py
+++ b/clients/client-python/tests/unittests/api/rel/test_sorts.py
@@ -17,12 +17,12 @@
 import unittest
 from unittest.mock import MagicMock
 
-from gravitino.api.expressions.function_expression import FunctionExpression
-from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_orders import SortImpl, SortOrders
-from gravitino.api.expressions.expression import Expression
+from gravitino.api.rel.expressions.expression import Expression
+from gravitino.api.rel.expressions.function_expression import 
FunctionExpression
+from gravitino.api.rel.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.sort_orders import SortImpl, 
SortOrders
 
 
 class TestSortOrder(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/rel/test_table_change.py 
b/clients/client-python/tests/unittests/api/rel/test_table_change.py
similarity index 99%
rename from clients/client-python/tests/unittests/rel/test_table_change.py
rename to clients/client-python/tests/unittests/api/rel/test_table_change.py
index c164075684..fb9989abac 100644
--- a/clients/client-python/tests/unittests/rel/test_table_change.py
+++ b/clients/client-python/tests/unittests/api/rel/test_table_change.py
@@ -17,8 +17,8 @@
 
 import unittest
 
-from gravitino.api.expressions.literals.literals import Literals
 from gravitino.api.rel.column import Column
+from gravitino.api.rel.expressions.literals.literals import Literals
 from gravitino.api.rel.indexes.index import Index
 from gravitino.api.rel.table_change import TableChange
 from gravitino.api.rel.types.types import Types
diff --git a/clients/client-python/tests/unittests/rel/test_transforms.py 
b/clients/client-python/tests/unittests/api/rel/test_transforms.py
similarity index 97%
rename from clients/client-python/tests/unittests/rel/test_transforms.py
rename to clients/client-python/tests/unittests/api/rel/test_transforms.py
index 0b354b7a8d..3694b5a6cf 100644
--- a/clients/client-python/tests/unittests/rel/test_transforms.py
+++ b/clients/client-python/tests/unittests/api/rel/test_transforms.py
@@ -19,9 +19,9 @@ import unittest
 from datetime import date, time
 from itertools import combinations
 
-from gravitino.api.expressions.literals.literals import Literals
-from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.transforms.transforms import Transforms
+from gravitino.api.rel.expressions.literals.literals import Literals
+from gravitino.api.rel.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.transforms.transforms import Transforms
 from gravitino.api.rel.partitions.partitions import Partitions
 
 
diff --git a/clients/client-python/tests/unittests/rel/test_types.py 
b/clients/client-python/tests/unittests/api/rel/test_types.py
similarity index 100%
rename from clients/client-python/tests/unittests/rel/test_types.py
rename to clients/client-python/tests/unittests/api/rel/test_types.py
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_distribution_dto.py 
b/clients/client-python/tests/unittests/dto/rel/test_distribution_dto.py
index 07a2443bfb..a6cc5c69c9 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_distribution_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_distribution_dto.py
@@ -17,7 +17,7 @@
 
 import unittest
 
-from gravitino.api.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.distribution_dto import DistributionDTO
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_distribution_serdes.py 
b/clients/client-python/tests/unittests/dto/rel/test_distribution_serdes.py
index 067a9083ed..e0b93982e0 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_distribution_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_distribution_serdes.py
@@ -21,7 +21,7 @@ from dataclasses import dataclass, field
 
 from dataclasses_json import DataClassJsonMixin, config
 
-from gravitino.api.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
 from gravitino.dto.rel.distribution_dto import DistributionDTO
 from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import 
SerdesUtils
 from gravitino.dto.rel.json_serdes.distribution_serdes import 
DistributionSerDes
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_non_single_field_partitioning_dto.py
 
b/clients/client-python/tests/unittests/dto/rel/test_non_single_field_partitioning_dto.py
index ca50c68c2a..9e5e951c1e 100644
--- 
a/clients/client-python/tests/unittests/dto/rel/test_non_single_field_partitioning_dto.py
+++ 
b/clients/client-python/tests/unittests/dto/rel/test_non_single_field_partitioning_dto.py
@@ -19,8 +19,8 @@ import random
 import unittest
 from itertools import chain
 
-from gravitino.api.expressions.literals.literals import Literals
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.literals.literals import Literals
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
diff --git a/clients/client-python/tests/unittests/dto/rel/test_partitioning.py 
b/clients/client-python/tests/unittests/dto/rel/test_partitioning.py
index 475d4a937a..aba50c4725 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partitioning.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partitioning.py
@@ -17,7 +17,7 @@
 
 import unittest
 
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partitioning.partitioning import (
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_single_field_partitioning_dto.py
 
b/clients/client-python/tests/unittests/dto/rel/test_single_field_partitioning_dto.py
index 37991825b8..75f4c5d5c9 100644
--- 
a/clients/client-python/tests/unittests/dto/rel/test_single_field_partitioning_dto.py
+++ 
b/clients/client-python/tests/unittests/dto/rel/test_single_field_partitioning_dto.py
@@ -17,7 +17,7 @@
 
 import unittest
 
-from gravitino.api.expressions.named_reference import NamedReference
+from gravitino.api.rel.expressions.named_reference import NamedReference
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.partitioning.day_partitioning_dto import 
DayPartitioningDTO
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_sort_order_dto.py 
b/clients/client-python/tests/unittests/dto/rel/test_sort_order_dto.py
index 10e32d619c..03da15c3e7 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_sort_order_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_sort_order_dto.py
@@ -17,8 +17,8 @@
 
 import unittest
 
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.column_dto import ColumnDTO
 from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
diff --git 
a/clients/client-python/tests/unittests/dto/rel/test_sort_order_serdes.py 
b/clients/client-python/tests/unittests/dto/rel/test_sort_order_serdes.py
index af850388f8..4009576a25 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_sort_order_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_sort_order_serdes.py
@@ -23,8 +23,8 @@ from typing import cast
 
 from dataclasses_json import DataClassJsonMixin, config
 
-from gravitino.api.expressions.sorts.null_ordering import NullOrdering
-from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
 from gravitino.api.rel.types.types import Types
 from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
 from gravitino.dto.rel.expressions.func_expression_dto import FuncExpressionDTO
diff --git a/clients/client-python/tests/unittests/dto/rel/test_table_dto.py 
b/clients/client-python/tests/unittests/dto/rel/test_table_dto.py
new file mode 100644
index 0000000000..271624cee9
--- /dev/null
+++ b/clients/client-python/tests/unittests/dto/rel/test_table_dto.py
@@ -0,0 +1,446 @@
+# 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.
+
+import json
+import unittest
+
+from gravitino.api.rel.expressions.distributions.strategy import Strategy
+from gravitino.api.rel.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.rel.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.types.types import Types
+from gravitino.dto.audit_dto import AuditDTO
+from gravitino.dto.rel.column_dto import ColumnDTO
+from gravitino.dto.rel.distribution_dto import DistributionDTO
+from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
+from gravitino.dto.rel.indexes.index_dto import IndexDTO
+from gravitino.dto.rel.partitioning.identity_partitioning_dto import (
+    IdentityPartitioningDTO,
+)
+from gravitino.dto.rel.partitioning.partitioning import SingleFieldPartitioning
+from gravitino.dto.rel.sort_order_dto import SortOrderDTO
+from gravitino.dto.rel.table_dto import TableDTO
+from gravitino.exceptions.base import IllegalArgumentException
+
+
+class TestTableDTO(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls) -> None:
+        cls.complete_json = """
+        {
+            "name": "example_table",
+            "comment": "This is an example table",
+            "audit": {
+                "creator": "Apache Gravitino",
+                "createTime":"2025-10-10T00:00:00"
+            },
+            "columns": [
+                {
+                    "name": "id",
+                    "type": "integer",
+                    "comment": "id column comment",
+                    "nullable": false,
+                    "autoIncrement": true,
+                    "defaultValue": {
+                        "type": "literal",
+                        "dataType": "integer",
+                        "value": "-1"
+                    }
+                },
+                {
+                    "name": "name",
+                    "type": "varchar(500)",
+                    "comment": "name column comment",
+                    "nullable": true,
+                    "autoIncrement": false,
+                    "defaultValue": {
+                        "type": "literal",
+                        "dataType": "null",
+                        "value": "null"
+                    }
+                },
+                {
+                    "name": "StartingDate",
+                    "type": "timestamp",
+                    "comment": "StartingDate column comment",
+                    "nullable": false,
+                    "autoIncrement": false,
+                    "defaultValue": {
+                        "type": "function",
+                        "funcName": "current_timestamp",
+                        "funcArgs": []
+                    }
+                },
+                {
+                    "name": "info",
+                    "type": {
+                        "type": "struct",
+                        "fields": [
+                            {
+                                "name": "position",
+                                "type": "string",
+                                "nullable": true,
+                                "comment": "position field comment"
+                            },
+                            {
+                                "name": "contact",
+                                "type": {
+                                "type": "list",
+                                "elementType": "integer",
+                                "containsNull": false
+                                },
+                                "nullable": true,
+                                "comment": "contact field comment"
+                            },
+                            {
+                                "name": "rating",
+                                "type": {
+                                "type": "map",
+                                "keyType": "string",
+                                "valueType": "integer",
+                                "valueContainsNull": false
+                                },
+                                "nullable": true,
+                                "comment": "rating field comment"
+                            }
+                        ]
+                    },
+                    "comment": "info column comment",
+                    "nullable": true
+                },
+                {
+                    "name": "dt",
+                    "type": "date",
+                    "comment": "dt column comment",
+                    "nullable": true
+                }
+            ],
+            "partitioning": [
+                {
+                    "strategy": "identity",
+                    "fieldName": [ "dt" ]
+                }
+            ],
+            "distribution": {
+                "strategy": "hash",
+                "number": 32,
+                "funcArgs": [
+                    {
+                        "type": "field",
+                        "fieldName": [ "id" ]
+                    }
+                ]
+            },
+            "sortOrders": [
+                {
+                    "sortTerm": {
+                        "type": "field",
+                        "fieldName": [ "age" ]
+                    },
+                    "direction": "asc",
+                    "nullOrdering": "nulls_first"
+                }
+            ],
+            "indexes": [
+                {
+                    "indexType": "primary_key",
+                    "name": "PRIMARY",
+                    "fieldNames": [["id"]]
+                }
+            ],
+            "properties": {
+                "format": "ORC"
+            }
+        }
+        """
+
+    def test_table_dto_complete_deserialize(self):
+        dto = TableDTO.from_json(self.complete_json)
+
+        partitioning_dto = dto.partitioning()[0]
+        self.assertIsInstance(partitioning_dto, IdentityPartitioningDTO)
+        self.assertIs(
+            partitioning_dto.strategy(), 
SingleFieldPartitioning.Strategy.IDENTITY
+        )
+
+        sort_order_dto = dto.sort_order()[0]
+        self.assertIsInstance(sort_order_dto, SortOrderDTO)
+        self.assertIs(sort_order_dto.direction(), SortDirection.ASCENDING)
+        self.assertIsInstance(sort_order_dto.sort_term(), FieldReferenceDTO)
+
+        index_dto = dto.index()[0]
+        self.assertIsInstance(index_dto, IndexDTO)
+        self.assertIs(index_dto.type(), Index.IndexType.PRIMARY_KEY)
+        self.assertEqual(index_dto.name(), "PRIMARY")
+        self.assertListEqual(index_dto.field_names(), [["id"]])
+
+        self.assertDictEqual(dto.properties(), {"format": "ORC"})
+
+    def test_table_dto_deserialize_required_fields_success(self):
+        json_string = """
+        {
+            "name": "example_table",
+            "audit": {
+                "creator": "Apache Gravitino",
+                "createTime":"2025-10-10T00:00:00"
+            },
+            "columns": [
+                {
+                    "name": "id",
+                    "type": "integer",
+                    "comment": "id column comment",
+                    "nullable": false,
+                    "autoIncrement": true,
+                    "defaultValue": {
+                        "type": "literal",
+                        "dataType": "integer",
+                        "value": "-1"
+                    }
+                }
+            ]
+        }
+        """
+
+        dto = TableDTO.from_json(json_string)
+        self.assertEqual(dto.name(), "example_table")
+        self.assertEqual(dto.audit_info().creator(), "Apache Gravitino")
+        self.assertEqual(dto.audit_info().create_time(), "2025-10-10T00:00:00")
+        self.assertEqual(len(dto.columns()), 1)
+        self.assertIsInstance(dto.columns()[0], ColumnDTO)
+
+        self.assertIsNone(dto.comment())
+        self.assertIsNone(dto.distribution())
+        self.assertIsNone(dto.index())
+        self.assertIsNone(dto.partitioning())
+        self.assertIsNone(dto.sort_order())
+        self.assertIsNone(dto.distribution())
+        self.assertIsNone(dto.properties())
+
+    def test_table_dto_deserialize_invalid_name(self):
+        json_string = """
+        {
+            "name": "",
+            "audit": {
+                "creator": "Apache Gravitino",
+                "createTime":"2025-10-10T00:00:00"
+            },
+            "columns": [
+                {
+                    "name": "id",
+                    "type": "integer",
+                    "comment": "id column comment",
+                    "nullable": false,
+                    "autoIncrement": true,
+                    "defaultValue": {
+                        "type": "literal",
+                        "dataType": "integer",
+                        "value": "-1"
+                    }
+                }
+            ]
+        }
+        """
+
+        with self.assertRaisesRegex(
+            IllegalArgumentException, "name cannot be null or empty"
+        ):
+            TableDTO.from_json(json_string)
+
+    def test_table_dto_deserialize_invalid_audit(self):
+        json_string = """
+        {
+            "name": "example_table",
+            "columns": [
+                {
+                    "name": "id",
+                    "type": "integer",
+                    "comment": "id column comment",
+                    "nullable": false,
+                    "autoIncrement": true,
+                    "defaultValue": {
+                        "type": "literal",
+                        "dataType": "integer",
+                        "value": "-1"
+                    }
+                }
+            ]
+        }
+        """
+
+        with self.assertRaisesRegex(IllegalArgumentException, "audit cannot be 
null"):
+            TableDTO.from_json(json_string)
+
+    def test_table_dto_deserialize_invalid_columns(self):
+        json_string = """
+        {
+            "name": "example_table",
+            "audit": {
+                "creator": "Apache Gravitino",
+                "createTime":"2025-10-10T00:00:00"
+            },
+            "columns": []
+        }
+        """
+
+        with self.assertRaisesRegex(
+            IllegalArgumentException, "columns cannot be null or empty"
+        ):
+            TableDTO.from_json(json_string)
+
+    def test_table_dto_serialize_with_none_values(self):
+        """Tests the fields with none value are excluded after 
serialization."""
+
+        optional_fields = {
+            "comment",
+            "distribution",
+            "partitioning",
+            "sortOrders",
+            "indexes",
+            "properties",
+        }
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        for field in optional_fields:
+            self.assertNotIn(field, dto_dict)
+
+    def test_table_dto_serialize_required_fields_success(self):
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        self.assertEqual(dto_dict["name"], "example_table")
+        self.assertEqual(dto_dict["audit"]["creator"], "Apache Gravitino")
+        self.assertEqual(len(dto_dict["columns"]), 1)
+        self.assertEqual(dto_dict["columns"][0]["name"], "id")
+        self.assertEqual(dto_dict["columns"][0]["type"], "integer")
+
+    def test_table_dto_serialize_with_distribution(self):
+        """Tests the distribution field is serialized correctly."""
+
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+            "comment for example_table",
+            _distribution=DistributionDTO(
+                strategy=Strategy.HASH,
+                number=32,
+                args=[FieldReferenceDTO(["id"])],
+            ),
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        self.assertEqual(dto_dict["distribution"]["strategy"], "hash")
+        self.assertEqual(dto_dict["distribution"]["number"], 32)
+        self.assertEqual(dto_dict["distribution"]["funcArgs"][0]["fieldName"], 
["id"])
+
+    def test_table_dto_serialize_with_partitioning(self):
+        """Tests the partitioning field is serialized correctly."""
+
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+            "comment for example_table",
+            _partitioning=[IdentityPartitioningDTO("id")],
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        self.assertEqual(dto_dict["partitioning"][0]["strategy"], "identity")
+        self.assertEqual(dto_dict["partitioning"][0]["fieldName"], ["id"])
+
+    def test_table_dto_serialize_with_sort_order(self):
+        """Tests the sort order field is serialized correctly."""
+
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+            "comment for example_table",
+            _sort_orders=[
+                SortOrderDTO(
+                    FieldReferenceDTO(["id"]),
+                    SortDirection.ASCENDING,
+                    NullOrdering.NULLS_FIRST,
+                )
+            ],
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        self.assertEqual(dto_dict["sortOrders"][0]["sortTerm"]["fieldName"], 
["id"])
+        self.assertEqual(dto_dict["sortOrders"][0]["direction"], "asc")
+        self.assertEqual(dto_dict["sortOrders"][0]["nullOrdering"], 
"nulls_first")
+
+    def test_table_dto_serialize_with_indexes(self):
+        """Tests the indexes field is serialized correctly."""
+
+        dto = TableDTO(
+            "example_table",
+            [
+                ColumnDTO.builder()
+                .with_name("id")
+                .with_data_type(Types.IntegerType.get())
+                .build()
+            ],
+            AuditDTO("Apache Gravitino"),
+            "comment for example_table",
+            _indexes=[
+                IndexDTO(
+                    Index.IndexType.PRIMARY_KEY,
+                    "PRIMARY",
+                    [["id"]],
+                )
+            ],
+        )
+
+        dto_dict = json.loads(dto.to_json())
+        self.assertEqual(dto_dict["indexes"][0]["indexType"], "PRIMARY_KEY")
+        self.assertEqual(dto_dict["indexes"][0]["name"], "PRIMARY")
+        self.assertEqual(dto_dict["indexes"][0]["fieldNames"], [["id"]])
diff --git a/clients/client-python/tests/unittests/test_named_reference.py 
b/clients/client-python/tests/unittests/test_named_reference.py
index a9942aec7f..101c1e90a1 100644
--- a/clients/client-python/tests/unittests/test_named_reference.py
+++ b/clients/client-python/tests/unittests/test_named_reference.py
@@ -16,7 +16,8 @@
 # under the License.
 
 import unittest
-from gravitino.api.expressions.named_reference import NamedReference, 
FieldReference
+
+from gravitino.api.rel.expressions.named_reference import FieldReference, 
NamedReference
 
 
 class TestNamedReference(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/test_unparsed_expression.py 
b/clients/client-python/tests/unittests/test_unparsed_expression.py
index 809caf67d4..63ef64d1b5 100644
--- a/clients/client-python/tests/unittests/test_unparsed_expression.py
+++ b/clients/client-python/tests/unittests/test_unparsed_expression.py
@@ -16,7 +16,8 @@
 # under the License.
 
 import unittest
-from gravitino.api.expressions.unparsed_expression import 
UnparsedExpressionImpl
+
+from gravitino.api.rel.expressions.unparsed_expression import 
UnparsedExpressionImpl
 
 
 class TestUnparsedExpression(unittest.TestCase):

Reply via email to