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 15fe57a705 [#8589] feat(client-python): add table change to support
alter table (#8542)
15fe57a705 is described below
commit 15fe57a705a5a0da01548514d82cfce6aea4f849
Author: George T. C. Lai <[email protected]>
AuthorDate: Mon Sep 22 15:17:52 2025 +0800
[#8589] feat(client-python): add table change to support alter table
(#8542)
### What changes were proposed in this pull request?
This PR is aimed at implementing the following classes corresponding to
the Java client.
TableChange.java
- TableChange
In this PR, the approach to implementing the above class conforms to the
following classes for consistent coding style.
- MetalakeChange (metalake_change.py)
- SchemaChange (schema_change.py)
- FilesetChange (fileset_change.py)
### Why are the changes needed?
We need to support python client for table operations.
#8589
### 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]>
---
.../gravitino/api/expressions/literals/literal.py | 4 +-
.../gravitino/api/expressions/literals/literals.py | 6 +-
.../api/expressions/transforms/transform.py | 4 +-
.../api/expressions/transforms/transforms.py | 6 +-
.../api/{expressions/indexes => rel}/__init__.py | 0
.../gravitino/api/{ => rel}/column.py | 2 +-
.../api/{types => rel/indexes}/__init__.py | 0
.../api/{expressions => rel}/indexes/index.py | 0
.../api/{expressions => rel}/indexes/indexes.py | 2 +-
.../partitions/identity_partition.py | 6 +-
.../partitions/list_partition.py | 4 +-
.../{expressions => rel}/partitions/partition.py | 0
.../{expressions => rel}/partitions/partitions.py | 10 +-
.../partitions/range_partition.py | 2 +-
.../gravitino/api/rel/table_change.py | 1089 ++++++++++++++++++++
.../{expressions/indexes => rel/types}/__init__.py | 0
.../api/{ => rel}/types/json_serdes/__init__.py | 4 +-
.../types/json_serdes/_helper/serdes_utils.py | 4 +-
.../api/{ => rel}/types/json_serdes/base.py | 4 +-
.../api/{ => rel}/types/json_serdes/type_serdes.py | 6 +-
.../gravitino/api/{ => rel}/types/type.py | 0
.../gravitino/api/{ => rel}/types/types.py | 2 +-
.../client-python/gravitino/dto/rel/column_dto.py | 8 +-
.../json_serdes/_helper/serdes_utils.py | 2 +-
.../json_serdes/column_default_value_serdes.py | 4 +-
.../gravitino/dto/rel/expressions/literal_dto.py | 4 +-
.../gravitino/dto/rel/indexes/index_dto.py | 2 +-
.../dto/rel/indexes/json_serdes/index_serdes.py | 4 +-
.../dto/rel/json_serdes/distribution_serdes.py | 2 +-
.../dto/rel/json_serdes/sort_order_serdes.py | 2 +-
.../json_serdes/partitioning_serdes.py | 2 +-
.../dto/rel/partitions/identity_partition_dto.py | 2 +-
.../partitions/json_serdes/partition_dto_serdes.py | 2 +-
.../dto/rel/partitions/list_partition_dto.py | 2 +-
.../gravitino/dto/rel/partitions/partition_dto.py | 2 +-
.../dto/rel/partitions/range_partition_dto.py | 2 +-
clients/client-python/gravitino/utils/serdes.py | 2 +-
.../dto/rel/test_column_default_value_serdes.py | 4 +-
.../tests/unittests/dto/rel/test_column_dto.py | 8 +-
.../unittests/dto/rel/test_distribution_dto.py | 2 +-
.../unittests/dto/rel/test_field_reference_dto.py | 2 +-
.../unittests/dto/rel/test_func_expression_dto.py | 2 +-
.../tests/unittests/dto/rel/test_function_arg.py | 2 +-
.../tests/unittests/dto/rel/test_index_dto.py | 2 +-
.../tests/unittests/dto/rel/test_index_serdes.py | 2 +-
.../tests/unittests/dto/rel/test_literal_dto.py | 2 +-
.../rel/test_non_single_field_partitioning_dto.py | 2 +-
.../unittests/dto/rel/test_partition_dto_serdes.py | 2 +-
.../tests/unittests/dto/rel/test_partition_dtos.py | 2 +-
.../unittests/dto/rel/test_partition_utils.py | 2 +-
.../tests/unittests/dto/rel/test_partitioning.py | 2 +-
.../unittests/dto/rel/test_partitioning_serdes.py | 2 +-
.../tests/unittests/dto/rel/test_serdes_utils.py | 2 +-
.../dto/rel/test_single_field_partitioning_dto.py | 2 +-
.../tests/unittests/dto/rel/test_sort_order_dto.py | 2 +-
.../unittests/dto/rel/test_sort_order_serdes.py | 2 +-
.../dto/rel/test_unparsed_expression_dto.py | 2 +-
.../unittests/json_serdes/test_type_serdes.py | 8 +-
.../tests/unittests/rel/test_indexes.py | 4 +-
.../tests/unittests/rel/test_literals.py | 4 +-
.../tests/unittests/rel/test_partitions.py | 2 +-
.../tests/unittests/rel/test_table_change.py | 566 ++++++++++
.../tests/unittests/rel/test_transforms.py | 2 +-
.../tests/unittests/rel/test_types.py | 2 +-
.../client-python/tests/unittests/test_column.py | 4 +-
65 files changed, 1746 insertions(+), 91 deletions(-)
diff --git
a/clients/client-python/gravitino/api/expressions/literals/literal.py
b/clients/client-python/gravitino/api/expressions/literals/literal.py
index 676b9ef4ce..b1edbc5068 100644
--- a/clients/client-python/gravitino/api/expressions/literals/literal.py
+++ b/clients/client-python/gravitino/api/expressions/literals/literal.py
@@ -16,10 +16,10 @@
# under the License.
from abc import abstractmethod
-from typing import List, TypeVar, Generic
+from typing import Generic, List, TypeVar
from gravitino.api.expressions.expression import Expression
-from gravitino.api.types.type import Type
+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/expressions/literals/literals.py
index c4d07338bc..e5c85f1568 100644
--- a/clients/client-python/gravitino/api/expressions/literals/literals.py
+++ b/clients/client-python/gravitino/api/expressions/literals/literals.py
@@ -15,12 +15,12 @@
# specific language governing permissions and limitations
# under the License.
import decimal
+from datetime import date, datetime, time
from typing import TypeVar
-from datetime import date, time, datetime
from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.types.type import Type
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.type import Type
+from gravitino.api.rel.types.types import Types
T = TypeVar("T")
diff --git
a/clients/client-python/gravitino/api/expressions/transforms/transform.py
b/clients/client-python/gravitino/api/expressions/transforms/transform.py
index ad47be5255..e653be0988 100644
--- a/clients/client-python/gravitino/api/expressions/transforms/transform.py
+++ b/clients/client-python/gravitino/api/expressions/transforms/transform.py
@@ -20,8 +20,8 @@ from typing import List
from gravitino.api.expressions.expression import Expression
from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.partitions.partition import Partition
-from gravitino.api.expressions.partitions.partitions import Partitions
+from gravitino.api.rel.partitions.partition import Partition
+from gravitino.api.rel.partitions.partitions import Partitions
class Transform(Expression, ABC):
diff --git
a/clients/client-python/gravitino/api/expressions/transforms/transforms.py
b/clients/client-python/gravitino/api/expressions/transforms/transforms.py
index c32935659f..8d587ead45 100644
--- a/clients/client-python/gravitino/api/expressions/transforms/transforms.py
+++ b/clients/client-python/gravitino/api/expressions/transforms/transforms.py
@@ -21,13 +21,13 @@ 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.partitions.list_partition import ListPartition
-from gravitino.api.expressions.partitions.partition import Partition
-from gravitino.api.expressions.partitions.range_partition import RangePartition
from gravitino.api.expressions.transforms.transform import (
SingleFieldTransform,
Transform,
)
+from gravitino.api.rel.partitions.list_partition import ListPartition
+from gravitino.api.rel.partitions.partition import Partition
+from gravitino.api.rel.partitions.range_partition import RangePartition
class Transforms(Transform):
diff --git
a/clients/client-python/gravitino/api/expressions/indexes/__init__.py
b/clients/client-python/gravitino/api/rel/__init__.py
similarity index 100%
copy from clients/client-python/gravitino/api/expressions/indexes/__init__.py
copy to clients/client-python/gravitino/api/rel/__init__.py
diff --git a/clients/client-python/gravitino/api/column.py
b/clients/client-python/gravitino/api/rel/column.py
similarity index 99%
rename from clients/client-python/gravitino/api/column.py
rename to clients/client-python/gravitino/api/rel/column.py
index e1d782732f..b540a23c22 100644
--- a/clients/client-python/gravitino/api/column.py
+++ b/clients/client-python/gravitino/api/rel/column.py
@@ -23,8 +23,8 @@ from typing import Optional
from gravitino.api.expressions.expression import Expression
from gravitino.api.expressions.function_expression import FunctionExpression
+from gravitino.api.rel.types.type import Type
from gravitino.api.tag.supports_tags import SupportsTags
-from gravitino.api.types.type import Type
from gravitino.exceptions.base import UnsupportedOperationException
from gravitino.utils.precondition import Precondition
diff --git a/clients/client-python/gravitino/api/types/__init__.py
b/clients/client-python/gravitino/api/rel/indexes/__init__.py
similarity index 100%
rename from clients/client-python/gravitino/api/types/__init__.py
rename to clients/client-python/gravitino/api/rel/indexes/__init__.py
diff --git a/clients/client-python/gravitino/api/expressions/indexes/index.py
b/clients/client-python/gravitino/api/rel/indexes/index.py
similarity index 100%
rename from clients/client-python/gravitino/api/expressions/indexes/index.py
rename to clients/client-python/gravitino/api/rel/indexes/index.py
diff --git a/clients/client-python/gravitino/api/expressions/indexes/indexes.py
b/clients/client-python/gravitino/api/rel/indexes/indexes.py
similarity index 97%
rename from clients/client-python/gravitino/api/expressions/indexes/indexes.py
rename to clients/client-python/gravitino/api/rel/indexes/indexes.py
index 720e2b46fe..7862bc342d 100644
--- a/clients/client-python/gravitino/api/expressions/indexes/indexes.py
+++ b/clients/client-python/gravitino/api/rel/indexes/indexes.py
@@ -18,7 +18,7 @@
from typing import ClassVar, List, Optional, final
-from gravitino.api.expressions.indexes.index import Index
+from gravitino.api.rel.indexes.index import Index
class Indexes:
diff --git
a/clients/client-python/gravitino/api/expressions/partitions/identity_partition.py
b/clients/client-python/gravitino/api/rel/partitions/identity_partition.py
similarity index 91%
rename from
clients/client-python/gravitino/api/expressions/partitions/identity_partition.py
rename to
clients/client-python/gravitino/api/rel/partitions/identity_partition.py
index e4b660c09d..75e175dedc 100644
---
a/clients/client-python/gravitino/api/expressions/partitions/identity_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/identity_partition.py
@@ -16,10 +16,10 @@
# under the License.
from abc import abstractmethod
-from typing import List, Any
+from typing import Any, List
-from .partition import Partition
-from ..literals.literal import Literal
+from gravitino.api.expressions.literals.literal import Literal
+from gravitino.api.rel.partitions.partition import Partition
class IdentityPartition(Partition):
diff --git
a/clients/client-python/gravitino/api/expressions/partitions/list_partition.py
b/clients/client-python/gravitino/api/rel/partitions/list_partition.py
similarity index 94%
rename from
clients/client-python/gravitino/api/expressions/partitions/list_partition.py
rename to clients/client-python/gravitino/api/rel/partitions/list_partition.py
index 8316e4daa0..4f30020ee8 100644
---
a/clients/client-python/gravitino/api/expressions/partitions/list_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/list_partition.py
@@ -16,10 +16,10 @@
# under the License.
from abc import abstractmethod
-from typing import List, Any
+from typing import Any, List
from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.expressions.partitions.partition import Partition
+from gravitino.api.rel.partitions.partition import Partition
class ListPartition(Partition):
diff --git
a/clients/client-python/gravitino/api/expressions/partitions/partition.py
b/clients/client-python/gravitino/api/rel/partitions/partition.py
similarity index 100%
rename from
clients/client-python/gravitino/api/expressions/partitions/partition.py
rename to clients/client-python/gravitino/api/rel/partitions/partition.py
diff --git
a/clients/client-python/gravitino/api/expressions/partitions/partitions.py
b/clients/client-python/gravitino/api/rel/partitions/partitions.py
similarity index 94%
rename from
clients/client-python/gravitino/api/expressions/partitions/partitions.py
rename to clients/client-python/gravitino/api/rel/partitions/partitions.py
index c116b3bdcb..10b2a43698 100644
--- a/clients/client-python/gravitino/api/expressions/partitions/partitions.py
+++ b/clients/client-python/gravitino/api/rel/partitions/partitions.py
@@ -15,13 +15,13 @@
# specific language governing permissions and limitations
# under the License.
-from typing import List, Dict, Any, Optional
+from typing import Any, Dict, List, Optional
from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.expressions.partitions.identity_partition import
IdentityPartition
-from gravitino.api.expressions.partitions.list_partition import ListPartition
-from gravitino.api.expressions.partitions.partition import Partition
-from gravitino.api.expressions.partitions.range_partition import RangePartition
+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
+from gravitino.api.rel.partitions.range_partition import RangePartition
class Partitions:
diff --git
a/clients/client-python/gravitino/api/expressions/partitions/range_partition.py
b/clients/client-python/gravitino/api/rel/partitions/range_partition.py
similarity index 96%
rename from
clients/client-python/gravitino/api/expressions/partitions/range_partition.py
rename to clients/client-python/gravitino/api/rel/partitions/range_partition.py
index 7155c033c0..b3f4e0af80 100644
---
a/clients/client-python/gravitino/api/expressions/partitions/range_partition.py
+++ b/clients/client-python/gravitino/api/rel/partitions/range_partition.py
@@ -19,7 +19,7 @@ from abc import abstractmethod
from typing import Any
from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.expressions.partitions.partition import Partition
+from gravitino.api.rel.partitions.partition import Partition
class RangePartition(Partition):
diff --git a/clients/client-python/gravitino/api/rel/table_change.py
b/clients/client-python/gravitino/api/rel/table_change.py
new file mode 100644
index 0000000000..8c1de696a8
--- /dev/null
+++ b/clients/client-python/gravitino/api/rel/table_change.py
@@ -0,0 +1,1089 @@
+# 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 ABC, abstractmethod
+from dataclasses import dataclass, field
+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.indexes.index import Index
+from gravitino.api.rel.types.type import Type
+
+
+class TableChange(ABC):
+ """Defines the public APIs for managing tables in a schema.
+
+ The `TableChange` interface defines the public API for managing tables in
a schema.
+ If the catalog implementation supports tables, it must implement this
interface.
+ """
+
+ @staticmethod
+ def rename(new_name: str) -> "RenameTable":
+ """Create a `TableChange` for renaming a table.
+
+ Args:
+ new_name: The new table name.
+
+ Returns:
+ RenameTable: A `TableChange` for the rename.
+ """
+ return TableChange.RenameTable(new_name)
+
+ @staticmethod
+ def update_comment(new_comment: str) -> "UpdateComment":
+ """Create a `TableChange` for updating the comment.
+
+ Args:
+ new_comment: The new comment.
+
+ Returns:
+ UpdateComment: A `TableChange` for the update.
+ """
+ return TableChange.UpdateComment(new_comment)
+
+ @staticmethod
+ def set_property(property_name: str, value: str) -> "SetProperty":
+ """Create a `TableChange` for setting a table property.
+
+ If the property already exists, it will be replaced with the new value.
+
+ Args:
+ property_name (str): The property name.
+ value (str): The new property value.
+
+ Returns:
+ SetProperty: A `TableChange` for the addition.
+ """
+ return TableChange.SetProperty(property_name, value)
+
+ @staticmethod
+ def remove_property(property_name: str) -> "RemoveProperty":
+ """Create a `TableChange` for removing a table property.
+
+ If the property does not exist, the change will succeed.
+
+ Args:
+ property_name (str): The property name.
+
+ Returns:
+ RemoveProperty: A `TableChange` for the addition.
+ """
+ return TableChange.RemoveProperty(property_name)
+
+ @staticmethod
+ def add_column(
+ field_name: list[str],
+ data_type: Type,
+ comment: Optional[str] = None,
+ position: Optional["TableChange.ColumnPosition"] = None,
+ nullable: bool = True,
+ auto_increment: bool = False,
+ default_value: Optional[Expression] = None,
+ ) -> "AddColumn":
+ """Create a `TableChange` for adding a column.
+
+ Args:
+ field_name (list[str]):
+ Field name of the new column.
+ data_type (Type):
+ The new column's data type.
+ comment (Optional[str]):
+ The new field's comment string, defaults to `None`.
+ position (Optional[TableChange.ColumnPosition]):
+ The new column's position, defaults to `None`.
+ nullable (bool):
+ The new column's nullable.
+ auto_increment (bool):
+ The new column's autoIncrement.
+ default_value (Expression):
+ The new column's default value.
+
+ Returns:
+ AddColumn: A `TableChange` for the addition.
+ """
+ return AddColumn(
+ field_name,
+ data_type,
+ comment,
+ position,
+ nullable,
+ auto_increment,
+ default_value,
+ )
+
+ @staticmethod
+ def rename_column(field_name: list[str], new_name: str) -> "RenameColumn":
+ """Create a `TableChange` for renaming a field.
+
+ The name is used to find the field to rename. The new name will
replace the **leaf field
+ name**. For example, `rename_column(["a", "b", "c"], "x")` should
produce column **a.b.x**.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The current field name.
+ new_name (str): The new name.
+
+ Returns:
+ RenameColumn: A TableChange for the rename.
+ """
+ return RenameColumn(field_name, new_name)
+
+ @staticmethod
+ def update_column_default_value(
+ field_name: list[str], new_default_value: Expression
+ ) -> "UpdateColumnDefaultValue":
+ """Create a `TableChange` for updating the default value of a field.
+
+ The name is used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ new_default_value (Expression): The new default value.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnDefaultValue(field_name, new_default_value)
+
+ @staticmethod
+ def update_column_type(
+ field_name: list[str], new_data_type: Type
+ ) -> "UpdateColumnType":
+ """Create a `TableChange` for updating the type of a field that is
nullable.
+
+ The field name are used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ new_data_type (Type): The new data type.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnType(field_name, new_data_type)
+
+ @staticmethod
+ def update_column_comment(
+ field_name: list[str], new_comment: str
+ ) -> "UpdateColumnComment":
+ """Create a `TableChange` for updating the comment of a field.
+
+ The name is used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ new_comment (str): The new comment.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnComment(field_name, new_comment)
+
+ @staticmethod
+ def update_column_position(
+ field_name: list[str], new_position: "TableChange.ColumnPosition"
+ ) -> "UpdateColumnPosition":
+ """Create a `TableChange` for updating the position of a field.
+
+ The name is used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ new_position (TableChange.ColumnPosition): The new position.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnPosition(field_name, new_position)
+
+ @staticmethod
+ def delete_column(field_name: list[str], if_exists: bool) ->
"DeleteColumn":
+ """Create a `TableChange` for deleting a field.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`
+ unless `if_exists` is true.
+
+ Args:
+ field_name (list[str]): Field name of the column to delete.
+ if_exists (bool): If true, silence the error if column does not
exist during drop.
+ Otherwise, an `IllegalArgumentException` will be thrown.
+
+ Returns:
+ TableChange: A `TableChange` for the delete.
+ """
+ return DeleteColumn(field_name, if_exists)
+
+ @staticmethod
+ def update_column_nullability(
+ field_name: list[str], nullable: bool
+ ) -> "UpdateColumnNullability":
+ """Create a `TableChange` for updating the nullability of a field.
+
+ The name is used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ nullable (bool): The new nullability.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnNullability(field_name, nullable)
+
+ @staticmethod
+ def add_index(
+ index_type: Index.IndexType,
+ name: str,
+ field_names: list[list[str]],
+ ) -> "AddIndex":
+ """Create a `TableChange` for adding an index.
+
+ Args:
+ index_type (Index.IndexType): The type of the index.
+ name (str): The name of the index.
+ field_names (list[list[str]]): The field names of the index.
+
+ Returns:
+ TableChange: A `TableChange` for the add index.
+ """
+ return TableChange.AddIndex(index_type, name, field_names)
+
+ @staticmethod
+ def delete_index(name: str, if_exists: bool) -> "DeleteIndex":
+ """Create a `TableChange` for deleting an index.
+
+ Args:
+ name (str): The name of the index to be dropped.
+ if_exists (bool): If true, silence the error if column does not
exist during drop.
+ Otherwise, an `IllegalArgumentException` will be thrown.
+
+ Returns:
+ TableChange: A `TableChange` for the delete index.
+ """
+ return TableChange.DeleteIndex(name, if_exists)
+
+ @staticmethod
+ def update_column_auto_increment(
+ field_name: list[str], auto_increment: bool
+ ) -> "UpdateColumnAutoIncrement":
+ """Create a `TableChange` for updating the autoIncrement of a field.
+
+ The name is used to find the field to update.
+
+ If the field does not exist, the change will result in an
`IllegalArgumentException`.
+
+ Args:
+ field_name (list[str]): The field name of the column to update.
+ auto_increment (bool): The new autoIncrement.
+
+ Returns:
+ TableChange: A `TableChange` for the update.
+ """
+ return UpdateColumnAutoIncrement(field_name, auto_increment)
+
+ @final
+ @dataclass(frozen=True)
+ class RenameTable:
+ """A `TableChange` to rename a table."""
+
+ _new_name: str = field(metadata=config(field_name="new_name"))
+
+ def get_new_name(self) -> str:
+ """Retrieves the new name for the table.
+
+ Returns:
+ str: The new name of the table.
+ """
+ return self._new_name
+
+ def __str__(self):
+ return f"RENAMETABLE {self._new_name}"
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.RenameTable):
+ return False
+ other = cast(TableChange.RenameTable, value)
+ return self._new_name == other.get_new_name()
+
+ def __hash__(self) -> int:
+ return hash(self._new_name)
+
+ @final
+ @dataclass(frozen=True)
+ class UpdateComment:
+ """A `TableChange` to update a table's comment."""
+
+ _new_comment: str = field(metadata=config(field_name="new_comment"))
+
+ def get_new_comment(self) -> str:
+ """Retrieves the new comment for the table.
+
+ Returns:
+ str: The new comment of the table.
+ """
+ return self._new_comment
+
+ def __str__(self):
+ return f"UPDATECOMMENT {self._new_comment}"
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.UpdateComment):
+ return False
+ other = cast(TableChange.UpdateComment, value)
+ return self._new_comment == other.get_new_comment()
+
+ def __hash__(self) -> int:
+ return hash(self._new_comment)
+
+ @final
+ @dataclass(frozen=True)
+ class SetProperty:
+ """A `TableChange` to set a table property."""
+
+ _property: str = field(metadata=config(field_name="property"))
+ _value: str = field(metadata=config(field_name="value"))
+
+ def get_property(self) -> str:
+ """Retrieves the name of the property.
+
+ Returns:
+ str: The name of the property.
+ """
+ return self._property
+
+ def get_value(self) -> str:
+ """Retrieves the value of the property.
+
+ Returns:
+ str: The value of the property.
+ """
+ return self._value
+
+ def __str__(self):
+ return f"SETPROPERTY {self._property} {self._value}"
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.SetProperty):
+ return False
+ other = cast(TableChange.SetProperty, value)
+ return (
+ self._property == other.get_property()
+ and self._value == other.get_value()
+ )
+
+ def __hash__(self) -> int:
+ return hash((self._property, self._value))
+
+ @final
+ @dataclass(frozen=True)
+ class RemoveProperty:
+ """A `TableChange` to remove a table property.
+
+ If the property does not exist, the change should succeed.
+ """
+
+ _property: str = field(metadata=config(field_name="property"))
+
+ def get_property(self) -> str:
+ """Retrieves the name of the property to be removed from the table.
+
+ Returns:
+ str: The name of the property scheduled for removal.
+ """
+ return self._property
+
+ def __str__(self):
+ return f"REMOVEPROPERTY {self._property}"
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.RemoveProperty):
+ return False
+ other = cast(TableChange.RemoveProperty, value)
+ return self._property == other.get_property()
+
+ def __hash__(self) -> int:
+ return hash(self._property)
+
+ @final
+ @dataclass(frozen=True)
+ class AddIndex:
+ """A TableChange to add an index.
+
+ Add an index key based on the type and field name passed in as well as
the name.
+ """
+
+ _type: Index.IndexType = field(metadata=config(field_name="type"))
+ _name: str = field(metadata=config(field_name="name"))
+ _field_names: list[list[str]] =
field(metadata=config(field_name="field_names"))
+
+ def get_type(self) -> Index.IndexType:
+ """Retrieves the type of the index.
+
+ Returns:
+ IndexType: The type of the index.
+ """
+ return self._type
+
+ def get_name(self) -> str:
+ """Retrieves the name of the index.
+
+ Returns:
+ str: The name of the index.
+ """
+ return self._name
+
+ def get_field_names(self) -> list[list[str]]:
+ """Retrieves the field names of the index.
+
+ Returns:
+ list[list[str]]: The field names of the index.
+ """
+ return self._field_names
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.AddIndex):
+ return False
+ other = cast(TableChange.AddIndex, value)
+ return (
+ self._type == other.get_type()
+ and self._name == other.get_name()
+ and self._field_names == other.get_field_names()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash((self._type, self._name)) + hash(
+ tuple(tuple(field_name) for field_name in self._field_names)
+ )
+
+ @final
+ @dataclass(frozen=True)
+ class DeleteIndex:
+ """A `TableChange` to delete an index.
+
+ If the index does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _name: str = field(metadata=config(field_name="name"))
+ _if_exists: bool = field(metadata=config(field_name="if_exists"))
+
+ def get_name(self) -> str:
+ """Retrieves the name of the index to be deleted.
+
+ Returns:
+ str: The name of the index to be deleted.
+ """
+ return self._name
+
+ def is_if_exists(self) -> bool:
+ """Retrieves the value of the `if_exists` flag.
+
+ Returns:
+ bool: True if the index should be deleted if it exists, False
otherwise.
+ """
+ return self._if_exists
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, TableChange.DeleteIndex):
+ return False
+ other = cast(TableChange.DeleteIndex, value)
+ return (
+ self._name == other.get_name()
+ and self._if_exists == other.is_if_exists()
+ )
+
+ def __hash__(self) -> int:
+ return hash((self._name, self._if_exists))
+
+ class ColumnPosition(ABC):
+ """The interface for all column positions.
+
+ Column positions are used to specify the position of a column when
adding
+ a new column to a table.
+ """
+
+ @staticmethod
+ def first() -> "First":
+ """The first position of `ColumnPosition` instance.
+
+ Returns:
+ First:
+ The first position of `ColumnPosition` instance.
+ """
+ return First()
+
+ @staticmethod
+ def after(column: str) -> "After":
+ """Returns the position after the given column.
+
+ Args:
+ column:
+ The name of the reference column to place the new column
after.
+
+ Returns:
+ After:
+ The position after the given column.
+ """
+ return After(column)
+
+ @staticmethod
+ def default_pos() -> "Default":
+ """Returns the default position of `ColumnPosition` instance.
+
+ Returns:
+ Default:
+ The default position of `ColumnPosition` instance.
+ """
+ return Default()
+
+ class ColumnChange(ABC):
+ """The interface for all column changes.
+
+ Column changes are used to modify the schema of a table.
+ """
+
+ @abstractmethod
+ def field_name(self) -> list[str]:
+ """Retrieves the field name of the column to be modified.
+
+ Returns:
+ list[str]:
+ A list of strings representing the field name.
+ """
+
+
+@final
+@dataclass(frozen=True)
+class First(TableChange.ColumnPosition):
+ """Column position FIRST.
+
+ It means the specified column should be the first column. Note that, the
specified column
+ may be a nested field, and then FIRST means this field should be the first
one within the
+ struct.
+ """
+
+ def __str__(self):
+ return "FIRST"
+
+
+@final
+@dataclass(frozen=True)
+class After(TableChange.ColumnPosition):
+ """Column position AFTER
+
+ It means the specified column should be put after the given `column`.
+ Note that, the specified column may be a nested field, and then the given
`column`
+ refers to a field in the same struct.
+ """
+
+ _column: str = field(metadata=config(field_name="column"))
+
+ def get_column(self) -> str:
+ """Retrieves the name of the reference column after which the
specified column will be placed.
+
+ Returns:
+ str: The name of the reference column.
+ """
+ return self._column
+
+ def __str__(self):
+ return f"AFTER {self._column}"
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, After):
+ return False
+ other = cast(After, value)
+ return self._column == other.get_column()
+
+ def __hash__(self) -> int:
+ return hash(self._column)
+
+
+@final
+@dataclass(frozen=True)
+class Default(TableChange.ColumnPosition):
+ """Column position DEFAULT.
+
+ It means the position of the column was ignored by the user, and should be
determined
+ by the catalog implementation.
+ """
+
+ def __str__(self):
+ return "DEFAULT"
+
+
+@final
+@dataclass(frozen=True)
+class AddColumn(TableChange.ColumnChange):
+ """A TableChange to add a field.
+
+ The implementation may need to back-fill all the existing data to add this
new column,
+ or remember the column default value specified here and let the reader
fill the column value
+ when reading existing data that do not have this new column.
+
+ If the field already exists, the change must result in an
`IllegalArgumentException`.
+ If the new field is nested and its parent does not exist or is not a
struct, the change must
+ result in an `IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _data_type: Type = field(metadata=config(field_name="data_type"))
+ _comment: Optional[str] = field(default=None,
metadata=config(field_name="comment"))
+ _position: Optional[TableChange.ColumnPosition] = field(
+ default=None, metadata=config(field_name="position")
+ )
+ _nullable: bool = field(default=True,
metadata=config(field_name="nullable"))
+ _auto_increment: bool = field(
+ default=False, metadata=config(field_name="auto_increment")
+ )
+ _default_value: Optional[Expression] = field(
+ default=None,
+ metadata=config(field_name="default_value"),
+ )
+
+ def get_field_name(self) -> list[str]:
+ """Retrieves the field name of the new column.
+
+ Returns:
+ list[str]: The field name of the new column.
+ """
+ return self._field_name
+
+ def get_data_type(self) -> Type:
+ """Retrieves the data type of the new column.
+
+ Returns:
+ Type: The data type of the new column.
+ """
+ return self._data_type
+
+ def get_comment(self) -> Optional[str]:
+ """Retrieves the comment for the new column.
+
+ Returns:
+ str: comment for the new column.
+ """
+ return self._comment
+
+ def get_position(self) -> Optional[TableChange.ColumnPosition]:
+ """Retrieves the position where the new column should be added.
+
+ Returns:
+ TableChange.ColumnPosition:
+ The position of the column.
+ """
+ return self._position
+
+ def is_nullable(self) -> bool:
+ """Checks if the new column is nullable.
+
+ Returns:
+ bool: `True` if the column is nullable; `False` otherwise.
+ """
+ return self._nullable
+
+ def is_auto_increment(self) -> bool:
+ """Checks if the new column is auto-increment.
+
+ Returns:
+ bool: `True` if the column is auto-increment; `False` otherwise.
+ """
+ return self._auto_increment
+
+ def get_default_value(self) -> Expression:
+ """Retrieves the default value of the new column.
+
+ Returns:
+ Expression: The default value of the column.
+ """
+ return (
+ self._default_value if self._default_value else
Column.DEFAULT_VALUE_NOT_SET
+ )
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, AddColumn):
+ return False
+ other = cast(AddColumn, value)
+ return (
+ self._nullable == other.is_nullable()
+ and self._auto_increment == other.is_auto_increment()
+ and self._field_name == other.get_field_name()
+ and self._comment == other.get_comment()
+ and self._data_type == other.get_data_type()
+ and self._position == other.get_position()
+ and self.get_default_value() == other.get_default_value()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(
+ (
+ self._data_type,
+ self._comment,
+ self._position,
+ self._nullable,
+ self._auto_increment,
+ (
+ tuple(self._default_value)
+ if self._default_value == Column.DEFAULT_VALUE_NOT_SET
+ else self._default_value
+ ),
+ )
+ ) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class RenameColumn(TableChange.ColumnChange):
+ """A `TableChange` to rename a field.
+
+ The name is used to find the field to rename. The new name will replace
the **leaf field name**.
+ For example, `rename_column("a.b.c", "x")` should produce column **a.b.x**.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _new_name: str = field(metadata=config(field_name="new_name"))
+
+ def get_field_name(self) -> list[str]:
+ """Retrieves the hierarchical field name of the column to be renamed.
+
+ Returns:
+ list[str]: The field name of the column to be renamed.
+ """
+ return self._field_name
+
+ def get_new_name(self) -> str:
+ """Retrieves the new name for the column.
+
+ Returns:
+ str: The new name of the column.
+ """
+ return self._new_name
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, RenameColumn):
+ return False
+ other = cast(RenameColumn, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._new_name == other.get_new_name()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._new_name) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnDefaultValue(TableChange.ColumnChange):
+ """A `TableChange` to update the default value of a field.
+
+ The field names are used to find the field to update.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _new_default_value: Optional[Expression] = field(
+ metadata=config(field_name="new_default_value")
+ )
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_new_default_value(self) -> Expression:
+ return (
+ self._new_default_value
+ if self._new_default_value
+ else Column.DEFAULT_VALUE_NOT_SET
+ )
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnDefaultValue):
+ return False
+ other = cast(UpdateColumnDefaultValue, value)
+ return (
+ self._field_name == other.field_name()
+ and self.get_new_default_value() == other.get_new_default_value()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(
+ tuple(self.get_new_default_value())
+ if self._new_default_value == Column.DEFAULT_VALUE_NOT_SET
+ else self._new_default_value
+ ) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnType(TableChange.ColumnChange):
+ """A `TableChange` to update the type of a field.
+
+ The field names are used to find the field to update.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _new_data_type: Type = field(metadata=config(field_name="new_data_type"))
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_new_data_type(self) -> Type:
+ return self._new_data_type
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnType):
+ return False
+ other = cast(UpdateColumnType, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._new_data_type == other.get_new_data_type()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._new_data_type) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnComment(TableChange.ColumnChange):
+ """A `TableChange` to update the comment of a field.
+
+ The field names are used to find the field to update.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _new_comment: str = field(metadata=config(field_name="new_comment"))
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_new_comment(self) -> str:
+ return self._new_comment
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnComment):
+ return False
+ other = cast(UpdateColumnComment, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._new_comment == other.get_new_comment()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._new_comment) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnPosition(TableChange.ColumnChange):
+ """A TableChange to update the position of a field.
+
+ The field names are used to find the field to update.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _position: TableChange.ColumnPosition = field(
+ metadata=config(field_name="position")
+ )
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_field_name(self) -> list[str]:
+ """Retrieves the field name of the column whose position is being
updated.
+
+ Returns:
+ list[str]: A list of strings representing the field name.
+ """
+ return self._field_name
+
+ def get_position(self) -> TableChange.ColumnPosition:
+ """Retrieves the new position for the column.
+
+ Returns:
+ TableChange.ColumnPosition: The new position of the column.
+ """
+ return self._position
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnPosition):
+ return False
+ other = cast(UpdateColumnPosition, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._position == other.get_position()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._position) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class DeleteColumn(TableChange.ColumnChange):
+ """A TableChange to delete a field.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _if_exists: bool = field(metadata=config(field_name="if_exists"))
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_field_name(self) -> list[str]:
+ """Retrieves the field name of the column to be deleted.
+
+ Returns:
+ list[str]: A list of strings representing the field name.
+ """
+ return self._field_name
+
+ def get_if_exists(self) -> bool:
+ """Checks if the field should be deleted only if it exists.
+
+ Returns:
+ bool: `True` if the field should be deleted only if it exists;
`False` otherwise.
+ """
+ return self._if_exists
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, DeleteColumn):
+ return False
+ other = cast(DeleteColumn, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._if_exists == other.get_if_exists()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._if_exists) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnNullability(TableChange.ColumnChange):
+ """A TableChange to update the nullability of a field.
+
+ The field names are used to find the field to update.
+
+ If the field does not exist, the change must result in an
`IllegalArgumentException`.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _nullable: bool = field(metadata=config(field_name="nullable"))
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def get_field_name(self) -> list[str]:
+ """Retrieves the field name of the column whose nullability is being
updated.
+
+ Returns:
+ list[str]: A list of strings representing the field name.
+ """
+ return self._field_name
+
+ def get_nullable(self) -> bool:
+ """Checks if the column is nullable.
+
+ Returns:
+ bool: `True` if the column is nullable; `False` otherwise.
+ """
+ return self._nullable
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnNullability):
+ return False
+ other = cast(UpdateColumnNullability, value)
+ return (
+ self._field_name == other.get_field_name()
+ and self._nullable == other.get_nullable()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._nullable) + hash(tuple(self._field_name))
+
+
+@final
+@dataclass(frozen=True)
+class UpdateColumnAutoIncrement(TableChange.ColumnChange):
+ """A TableChange to update the `autoIncrement` of a field.
+
+ True is to add autoIncrement, false is to delete autoIncrement.
+ """
+
+ _field_name: list[str] = field(metadata=config(field_name="field_name"))
+ _auto_increment: bool = field(metadata=config(field_name="auto_increment"))
+
+ def field_name(self) -> list[str]:
+ return self._field_name
+
+ def is_auto_increment(self) -> bool:
+ """Checks if the column is `autoIncrement`.
+
+ Returns:
+ bool: `True` if the column is `autoIncrement`; `False` otherwise.
+ """
+ return self._auto_increment
+
+ def __eq__(self, value: object) -> bool:
+ if not isinstance(value, UpdateColumnAutoIncrement):
+ return False
+ other = cast(UpdateColumnAutoIncrement, value)
+ return (
+ self._field_name == other.field_name()
+ and self._auto_increment == other.is_auto_increment()
+ )
+
+ def __hash__(self) -> int:
+ return 31 * hash(self._auto_increment) + hash(tuple(self._field_name))
diff --git
a/clients/client-python/gravitino/api/expressions/indexes/__init__.py
b/clients/client-python/gravitino/api/rel/types/__init__.py
similarity index 100%
rename from clients/client-python/gravitino/api/expressions/indexes/__init__.py
rename to clients/client-python/gravitino/api/rel/types/__init__.py
diff --git a/clients/client-python/gravitino/api/types/json_serdes/__init__.py
b/clients/client-python/gravitino/api/rel/types/json_serdes/__init__.py
similarity index 85%
rename from clients/client-python/gravitino/api/types/json_serdes/__init__.py
rename to clients/client-python/gravitino/api/rel/types/json_serdes/__init__.py
index fb9e11264c..aa841f09a7 100644
--- a/clients/client-python/gravitino/api/types/json_serdes/__init__.py
+++ b/clients/client-python/gravitino/api/rel/types/json_serdes/__init__.py
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
-from gravitino.api.types.json_serdes.base import JsonSerializable
-from gravitino.api.types.json_serdes.type_serdes import TypeSerdes
+from gravitino.api.rel.types.json_serdes.base import JsonSerializable
+from gravitino.api.rel.types.json_serdes.type_serdes import TypeSerdes
__all__ = ["JsonSerializable", "TypeSerdes"]
diff --git
a/clients/client-python/gravitino/api/types/json_serdes/_helper/serdes_utils.py
b/clients/client-python/gravitino/api/rel/types/json_serdes/_helper/serdes_utils.py
similarity index 99%
rename from
clients/client-python/gravitino/api/types/json_serdes/_helper/serdes_utils.py
rename to
clients/client-python/gravitino/api/rel/types/json_serdes/_helper/serdes_utils.py
index cab0ebbacc..25656fa0e4 100644
---
a/clients/client-python/gravitino/api/types/json_serdes/_helper/serdes_utils.py
+++
b/clients/client-python/gravitino/api/rel/types/json_serdes/_helper/serdes_utils.py
@@ -20,8 +20,8 @@ from typing import Any, Dict, Union, overload
from dataclasses_json.core import Json
-from gravitino.api.types.type import Name, Type
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.type import Name, Type
+from gravitino.api.rel.types.types import Types
from gravitino.utils.precondition import Precondition
from gravitino.utils.serdes import SerdesUtilsBase
diff --git a/clients/client-python/gravitino/api/types/json_serdes/base.py
b/clients/client-python/gravitino/api/rel/types/json_serdes/base.py
similarity index 95%
rename from clients/client-python/gravitino/api/types/json_serdes/base.py
rename to clients/client-python/gravitino/api/rel/types/json_serdes/base.py
index 9f44de8462..aa20d76ba7 100644
--- a/clients/client-python/gravitino/api/types/json_serdes/base.py
+++ b/clients/client-python/gravitino/api/rel/types/json_serdes/base.py
@@ -22,9 +22,9 @@ 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.indexes.index import Index
from gravitino.api.expressions.sorts.sort_order import SortOrder
-from gravitino.api.types.types import Type
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.types.types import Type
from gravitino.dto.rel.partitioning.partitioning import Partitioning
from gravitino.dto.rel.partitions.partition_dto import PartitionDTO
diff --git
a/clients/client-python/gravitino/api/types/json_serdes/type_serdes.py
b/clients/client-python/gravitino/api/rel/types/json_serdes/type_serdes.py
similarity index 89%
rename from clients/client-python/gravitino/api/types/json_serdes/type_serdes.py
rename to
clients/client-python/gravitino/api/rel/types/json_serdes/type_serdes.py
index 4577987486..8e97c54b75 100644
--- a/clients/client-python/gravitino/api/types/json_serdes/type_serdes.py
+++ b/clients/client-python/gravitino/api/rel/types/json_serdes/type_serdes.py
@@ -18,9 +18,9 @@
from dataclasses_json.core import Json
-from gravitino.api.types.json_serdes._helper.serdes_utils import SerdesUtils
-from gravitino.api.types.json_serdes.base import JsonSerializable
-from gravitino.api.types.type import Type
+from gravitino.api.rel.types.json_serdes._helper.serdes_utils import
SerdesUtils
+from gravitino.api.rel.types.json_serdes.base import JsonSerializable
+from gravitino.api.rel.types.type import Type
class TypeSerdes(JsonSerializable[Type]):
diff --git a/clients/client-python/gravitino/api/types/type.py
b/clients/client-python/gravitino/api/rel/types/type.py
similarity index 100%
rename from clients/client-python/gravitino/api/types/type.py
rename to clients/client-python/gravitino/api/rel/types/type.py
diff --git a/clients/client-python/gravitino/api/types/types.py
b/clients/client-python/gravitino/api/rel/types/types.py
similarity index 99%
rename from clients/client-python/gravitino/api/types/types.py
rename to clients/client-python/gravitino/api/rel/types/types.py
index 9549c1ec5e..f182f086bf 100644
--- a/clients/client-python/gravitino/api/types/types.py
+++ b/clients/client-python/gravitino/api/rel/types/types.py
@@ -19,7 +19,7 @@ from __future__ import annotations
from typing import List
-from .type import (
+from gravitino.api.rel.types.type import (
ComplexType,
DateTimeType,
FractionType,
diff --git a/clients/client-python/gravitino/dto/rel/column_dto.py
b/clients/client-python/gravitino/dto/rel/column_dto.py
index 42286fd128..fba28be2ec 100644
--- a/clients/client-python/gravitino/dto/rel/column_dto.py
+++ b/clients/client-python/gravitino/dto/rel/column_dto.py
@@ -22,11 +22,11 @@ from typing import List, Optional, Union, cast
from dataclasses_json import DataClassJsonMixin, config
-from gravitino.api.column import Column
from gravitino.api.expressions.expression import Expression
-from gravitino.api.types.json_serdes.type_serdes import TypeSerdes
-from gravitino.api.types.type import Type
-from gravitino.api.types.types import Types
+from gravitino.api.rel.column import Column
+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
from gravitino.dto.rel.expressions.json_serdes.column_default_value_serdes
import (
ColumnDefaultValueSerdes,
)
diff --git
a/clients/client-python/gravitino/dto/rel/expressions/json_serdes/_helper/serdes_utils.py
b/clients/client-python/gravitino/dto/rel/expressions/json_serdes/_helper/serdes_utils.py
index 4edfc133f7..53a9ec9b63 100644
---
a/clients/client-python/gravitino/dto/rel/expressions/json_serdes/_helper/serdes_utils.py
+++
b/clients/client-python/gravitino/dto/rel/expressions/json_serdes/_helper/serdes_utils.py
@@ -17,7 +17,7 @@
from typing import Any, Dict, cast
-from gravitino.api.types.json_serdes._helper.serdes_utils import (
+from gravitino.api.rel.types.json_serdes._helper.serdes_utils import (
SerdesUtils as TypesSerdesUtils,
)
from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
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 6e717c4f62..2b6905619b 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,9 +19,9 @@ from typing import overload
from dataclasses_json.core import Json
-from gravitino.api.column import Column
from gravitino.api.expressions.expression import Expression
-from gravitino.api.types.json_serdes.base import JsonSerializable
+from gravitino.api.rel.column import Column
+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 7e416c31c3..31dc1cc2cc 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
@@ -20,11 +20,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING, ClassVar
from gravitino.api.expressions.literals.literal import Literal
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.function_arg import FunctionArg
if TYPE_CHECKING:
- from gravitino.api.types.type import Type
+ from gravitino.api.rel.types.type import Type
class LiteralDTO(Literal[str], FunctionArg):
diff --git a/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
b/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
index 539c660bf5..b804fc0cc0 100644
--- a/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
+++ b/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
@@ -18,7 +18,7 @@
from functools import reduce
from typing import ClassVar, List, Optional
-from gravitino.api.expressions.indexes.index import Index
+from gravitino.api.rel.indexes.index import Index
from gravitino.utils.precondition import Precondition
diff --git
a/clients/client-python/gravitino/dto/rel/indexes/json_serdes/index_serdes.py
b/clients/client-python/gravitino/dto/rel/indexes/json_serdes/index_serdes.py
index a1eab07e15..5aa004eb21 100644
---
a/clients/client-python/gravitino/dto/rel/indexes/json_serdes/index_serdes.py
+++
b/clients/client-python/gravitino/dto/rel/indexes/json_serdes/index_serdes.py
@@ -17,8 +17,8 @@
from typing import Any
-from gravitino.api.expressions.indexes.index import Index
-from gravitino.api.types.json_serdes import JsonSerializable
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.types.json_serdes import JsonSerializable
from gravitino.dto.rel.indexes.index_dto import IndexDTO
from gravitino.utils.precondition import Precondition
from gravitino.utils.serdes import SerdesUtilsBase
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 84e88642b9..eb0993a433 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
@@ -19,7 +19,7 @@
from typing import Any
from gravitino.api.expressions.distributions.strategy import Strategy
-from gravitino.api.types.json_serdes.base import JsonSerializable
+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
from gravitino.utils.precondition import Precondition
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 7eadb5416f..bd457066aa 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
@@ -19,7 +19,7 @@ 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.types.json_serdes import JsonSerializable
+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
from gravitino.utils.precondition import Precondition
diff --git
a/clients/client-python/gravitino/dto/rel/partitioning/json_serdes/partitioning_serdes.py
b/clients/client-python/gravitino/dto/rel/partitioning/json_serdes/partitioning_serdes.py
index 2b3a9bbc03..da9e95701b 100644
---
a/clients/client-python/gravitino/dto/rel/partitioning/json_serdes/partitioning_serdes.py
+++
b/clients/client-python/gravitino/dto/rel/partitioning/json_serdes/partitioning_serdes.py
@@ -19,7 +19,7 @@ from contextlib import suppress
from types import MappingProxyType
from typing import Any, Dict, Final, cast
-from gravitino.api.types.json_serdes.base import JsonSerializable
+from gravitino.api.rel.types.json_serdes.base import JsonSerializable
from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import (
SerdesUtils as ExpressionSerdesUtils,
)
diff --git
a/clients/client-python/gravitino/dto/rel/partitions/identity_partition_dto.py
b/clients/client-python/gravitino/dto/rel/partitions/identity_partition_dto.py
index ab675cd769..e4d26eb0cb 100644
---
a/clients/client-python/gravitino/dto/rel/partitions/identity_partition_dto.py
+++
b/clients/client-python/gravitino/dto/rel/partitions/identity_partition_dto.py
@@ -18,7 +18,7 @@
from typing import Dict, List
-from gravitino.api.expressions.partitions.identity_partition import
IdentityPartition
+from gravitino.api.rel.partitions.identity_partition import IdentityPartition
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.partitions.partition_dto import PartitionDTO
diff --git
a/clients/client-python/gravitino/dto/rel/partitions/json_serdes/partition_dto_serdes.py
b/clients/client-python/gravitino/dto/rel/partitions/json_serdes/partition_dto_serdes.py
index 383ba8d3a9..030ffb5e24 100644
---
a/clients/client-python/gravitino/dto/rel/partitions/json_serdes/partition_dto_serdes.py
+++
b/clients/client-python/gravitino/dto/rel/partitions/json_serdes/partition_dto_serdes.py
@@ -17,7 +17,7 @@
from typing import Any, Dict
-from gravitino.api.types.json_serdes.base import JsonSerializable
+from gravitino.api.rel.types.json_serdes.base import JsonSerializable
from gravitino.dto.rel.partitions.json_serdes._helper.serdes_utils import
SerdesUtils
from gravitino.dto.rel.partitions.partition_dto import PartitionDTO
diff --git
a/clients/client-python/gravitino/dto/rel/partitions/list_partition_dto.py
b/clients/client-python/gravitino/dto/rel/partitions/list_partition_dto.py
index 9ccd542b75..ec08f658a9 100644
--- a/clients/client-python/gravitino/dto/rel/partitions/list_partition_dto.py
+++ b/clients/client-python/gravitino/dto/rel/partitions/list_partition_dto.py
@@ -18,7 +18,7 @@
from typing import Dict, List
-from gravitino.api.expressions.partitions.list_partition import ListPartition
+from gravitino.api.rel.partitions.list_partition import ListPartition
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.partitions.partition_dto import PartitionDTO
diff --git
a/clients/client-python/gravitino/dto/rel/partitions/partition_dto.py
b/clients/client-python/gravitino/dto/rel/partitions/partition_dto.py
index 40047d6901..ed68931da7 100644
--- a/clients/client-python/gravitino/dto/rel/partitions/partition_dto.py
+++ b/clients/client-python/gravitino/dto/rel/partitions/partition_dto.py
@@ -19,7 +19,7 @@
from abc import abstractmethod
from enum import Enum, unique
-from gravitino.api.expressions.partitions.partition import Partition
+from gravitino.api.rel.partitions.partition import Partition
class PartitionDTO(Partition):
diff --git
a/clients/client-python/gravitino/dto/rel/partitions/range_partition_dto.py
b/clients/client-python/gravitino/dto/rel/partitions/range_partition_dto.py
index 967ff1a2b7..73930c9843 100644
--- a/clients/client-python/gravitino/dto/rel/partitions/range_partition_dto.py
+++ b/clients/client-python/gravitino/dto/rel/partitions/range_partition_dto.py
@@ -18,7 +18,7 @@
from typing import Dict
-from gravitino.api.expressions.partitions.range_partition import RangePartition
+from gravitino.api.rel.partitions.range_partition import RangePartition
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.partitions.partition_dto import PartitionDTO
diff --git a/clients/client-python/gravitino/utils/serdes.py
b/clients/client-python/gravitino/utils/serdes.py
index b862ba9259..ddee51ac84 100644
--- a/clients/client-python/gravitino/utils/serdes.py
+++ b/clients/client-python/gravitino/utils/serdes.py
@@ -20,7 +20,7 @@ from collections.abc import Mapping
from types import MappingProxyType
from typing import Final, Pattern, Set
-from gravitino.api.types.types import Name, Types
+from gravitino.api.rel.types.types import Name, Types
class SerdesUtilsBase:
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_column_default_value_serdes.py
b/clients/client-python/tests/unittests/dto/rel/test_column_default_value_serdes.py
index 303dd98f45..999ec0f476 100644
---
a/clients/client-python/tests/unittests/dto/rel/test_column_default_value_serdes.py
+++
b/clients/client-python/tests/unittests/dto/rel/test_column_default_value_serdes.py
@@ -18,8 +18,8 @@
import unittest
from unittest.mock import patch
-from gravitino.api.column import Column
-from gravitino.api.types.types import Types
+from gravitino.api.rel.column import Column
+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
from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import
SerdesUtils
diff --git a/clients/client-python/tests/unittests/dto/rel/test_column_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_column_dto.py
index 0a9c2b4a3d..30b4159b37 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_column_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_column_dto.py
@@ -19,10 +19,10 @@ import json
import unittest
from itertools import product
-from gravitino.api.column import Column
-from gravitino.api.types.json_serdes import TypeSerdes
-from gravitino.api.types.json_serdes._helper.serdes_utils import SerdesUtils
-from gravitino.api.types.types import Types
+from gravitino.api.rel.column import Column
+from gravitino.api.rel.types.json_serdes import TypeSerdes
+from gravitino.api.rel.types.json_serdes._helper.serdes_utils import
SerdesUtils
+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
from gravitino.dto.rel.expressions.func_expression_dto import FuncExpressionDTO
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 fe88afa0e1..07a2443bfb 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
@@ -18,7 +18,7 @@
import unittest
from gravitino.api.expressions.distributions.strategy import Strategy
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
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
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_field_reference_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_field_reference_dto.py
index 230a88ad67..78b1ca9d85 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_field_reference_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_field_reference_dto.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
from gravitino.dto.rel.expressions.function_arg import FunctionArg
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_func_expression_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_func_expression_dto.py
index c29324b260..b78cfd5ef4 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_func_expression_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_func_expression_dto.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
diff --git a/clients/client-python/tests/unittests/dto/rel/test_function_arg.py
b/clients/client-python/tests/unittests/dto/rel/test_function_arg.py
index 83ebb413b5..9aa4176c08 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_function_arg.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_function_arg.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.expressions.func_expression_dto import FuncExpressionDTO
diff --git a/clients/client-python/tests/unittests/dto/rel/test_index_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_index_dto.py
index 5bb9fa31dc..9a17862a23 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_index_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_index_dto.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.expressions.indexes.index import Index
+from gravitino.api.rel.indexes.index import Index
from gravitino.dto.rel.indexes.index_dto import IndexDTO
from gravitino.exceptions.base import IllegalArgumentException
diff --git a/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
b/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
index 5373193209..790f102a24 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
@@ -21,7 +21,7 @@ from dataclasses import dataclass, field
from dataclasses_json import DataClassJsonMixin, config
-from gravitino.api.expressions.indexes.index import Index
+from gravitino.api.rel.indexes.index import Index
from gravitino.dto.rel.indexes.index_dto import IndexDTO
from gravitino.dto.rel.indexes.json_serdes.index_serdes import IndexSerdes
from gravitino.exceptions.base import IllegalArgumentException
diff --git a/clients/client-python/tests/unittests/dto/rel/test_literal_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_literal_dto.py
index d730a49de2..a3a69084cc 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_literal_dto.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_literal_dto.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
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 633d34d3db..ca50c68c2a 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
@@ -21,7 +21,7 @@ from itertools import chain
from gravitino.api.expressions.literals.literals import Literals
from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.partitioning.bucket_partitioning_dto import
BucketPartitioningDTO
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_partition_dto_serdes.py
b/clients/client-python/tests/unittests/dto/rel/test_partition_dto_serdes.py
index 464c705ad8..e83df8b051 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partition_dto_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partition_dto_serdes.py
@@ -21,7 +21,7 @@ from enum import Enum
from typing import cast
from unittest.mock import patch
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.json_serdes._helper.serdes_utils import (
SerdesUtils as ExpressionSerdesUtils,
)
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_partition_dtos.py
b/clients/client-python/tests/unittests/dto/rel/test_partition_dtos.py
index 9bcf9f106a..ed0f083c11 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partition_dtos.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partition_dtos.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.partitions.identity_partition_dto import
IdentityPartitionDTO
from gravitino.dto.rel.partitions.list_partition_dto import ListPartitionDTO
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_partition_utils.py
b/clients/client-python/tests/unittests/dto/rel/test_partition_utils.py
index 8d69c127a1..ac639f45ed 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partition_utils.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partition_utils.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.column_dto import ColumnDTO
from gravitino.dto.rel.partition_utils import PartitionUtils
from gravitino.exceptions.base import IllegalArgumentException
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 370bdec0b1..475d4a937a 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partitioning.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partitioning.py
@@ -18,7 +18,7 @@
import unittest
from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.column_dto import ColumnDTO
from gravitino.dto.rel.partitioning.partitioning import (
Partitioning,
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_partitioning_serdes.py
b/clients/client-python/tests/unittests/dto/rel/test_partitioning_serdes.py
index ee99c7112f..4eccd68234 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_partitioning_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_partitioning_serdes.py
@@ -20,7 +20,7 @@ import unittest
from enum import Enum
from unittest.mock import patch
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.field_reference_dto import FieldReferenceDTO
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.partitioning.day_partitioning_dto import
DayPartitioningDTO
diff --git a/clients/client-python/tests/unittests/dto/rel/test_serdes_utils.py
b/clients/client-python/tests/unittests/dto/rel/test_serdes_utils.py
index d8b29659f6..0151f759cb 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_serdes_utils.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_serdes_utils.py
@@ -19,7 +19,7 @@ import unittest
from enum import Enum
from unittest.mock import patch
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.expressions.function_arg import FunctionArg
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 1efb860541..37991825b8 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
@@ -18,7 +18,7 @@
import unittest
from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.partitioning.hour_partitioning_dto import
HourPartitioningDTO
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 68a39e1ab3..10e32d619c 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
@@ -19,7 +19,7 @@ import unittest
from gravitino.api.expressions.sorts.null_ordering import NullOrdering
from gravitino.api.expressions.sorts.sort_direction import SortDirection
-from gravitino.api.types.types import Types
+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
from gravitino.dto.rel.sort_order_dto import SortOrderDTO
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 bb2bce511a..af850388f8 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
@@ -25,7 +25,7 @@ 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.types.types import Types
+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
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
diff --git
a/clients/client-python/tests/unittests/dto/rel/test_unparsed_expression_dto.py
b/clients/client-python/tests/unittests/dto/rel/test_unparsed_expression_dto.py
index fdae2a9b64..85f034a242 100644
---
a/clients/client-python/tests/unittests/dto/rel/test_unparsed_expression_dto.py
+++
b/clients/client-python/tests/unittests/dto/rel/test_unparsed_expression_dto.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
from gravitino.dto.rel.expressions.literal_dto import LiteralDTO
from gravitino.dto.rel.expressions.unparsed_expression_dto import
UnparsedExpressionDTO
diff --git
a/clients/client-python/tests/unittests/json_serdes/test_type_serdes.py
b/clients/client-python/tests/unittests/json_serdes/test_type_serdes.py
index 7ef195b649..10f5f77eac 100644
--- a/clients/client-python/tests/unittests/json_serdes/test_type_serdes.py
+++ b/clients/client-python/tests/unittests/json_serdes/test_type_serdes.py
@@ -19,10 +19,10 @@ import random
import unittest
from itertools import combinations, product
-from gravitino.api.types.json_serdes import TypeSerdes
-from gravitino.api.types.json_serdes._helper.serdes_utils import SerdesUtils
-from gravitino.api.types.type import PrimitiveType
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.json_serdes import TypeSerdes
+from gravitino.api.rel.types.json_serdes._helper.serdes_utils import
SerdesUtils
+from gravitino.api.rel.types.type import PrimitiveType
+from gravitino.api.rel.types.types import Types
from gravitino.exceptions.base import IllegalArgumentException
diff --git a/clients/client-python/tests/unittests/rel/test_indexes.py
b/clients/client-python/tests/unittests/rel/test_indexes.py
index 6633d07efe..4f9a65f770 100644
--- a/clients/client-python/tests/unittests/rel/test_indexes.py
+++ b/clients/client-python/tests/unittests/rel/test_indexes.py
@@ -17,8 +17,8 @@
import unittest
-from gravitino.api.expressions.indexes.index import Index
-from gravitino.api.expressions.indexes.indexes import Indexes
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.indexes.indexes import Indexes
class TestIndexes(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/rel/test_literals.py
b/clients/client-python/tests/unittests/rel/test_literals.py
index d9c96b7bab..577b19f297 100644
--- a/clients/client-python/tests/unittests/rel/test_literals.py
+++ b/clients/client-python/tests/unittests/rel/test_literals.py
@@ -15,11 +15,11 @@
# specific language governing permissions and limitations
# under the License.
import unittest
-from datetime import date, time, datetime
+from datetime import date, datetime, time
from decimal import Decimal
from gravitino.api.expressions.literals.literals import Literals
-from gravitino.api.types.types import Types
+from gravitino.api.rel.types.types import Types
class TestLiterals(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/rel/test_partitions.py
b/clients/client-python/tests/unittests/rel/test_partitions.py
index a14eb079d6..b6fc768481 100644
--- a/clients/client-python/tests/unittests/rel/test_partitions.py
+++ b/clients/client-python/tests/unittests/rel/test_partitions.py
@@ -18,7 +18,7 @@ import unittest
from datetime import date
from gravitino.api.expressions.literals.literals import Literals
-from gravitino.api.expressions.partitions.partitions import Partitions
+from gravitino.api.rel.partitions.partitions import Partitions
class TestPartitions(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/rel/test_table_change.py
b/clients/client-python/tests/unittests/rel/test_table_change.py
new file mode 100644
index 0000000000..c164075684
--- /dev/null
+++ b/clients/client-python/tests/unittests/rel/test_table_change.py
@@ -0,0 +1,566 @@
+# 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 unittest
+
+from gravitino.api.expressions.literals.literals import Literals
+from gravitino.api.rel.column import Column
+from gravitino.api.rel.indexes.index import Index
+from gravitino.api.rel.table_change import TableChange
+from gravitino.api.rel.types.types import Types
+
+
+class TestTableChange(unittest.TestCase):
+ def test_table_change_rename(self):
+ rename1, rename2 = (
+ TableChange.rename(f"New table name {i + 1}") for i in range(2)
+ )
+ rename3 = TableChange.rename("New table name 1")
+ self.assertEqual(rename1.get_new_name(), "New table name 1")
+ self.assertEqual(str(rename1), f"RENAMETABLE {rename1.get_new_name()}")
+ self.assertFalse(rename1 == rename2)
+ self.assertFalse(rename1 == "invalid_rename")
+ self.assertTrue(rename1 == rename3)
+ self.assertTrue(hash(rename1) == hash(rename3))
+ self.assertFalse(hash(rename1) == hash(rename2))
+
+ def test_table_change_update_comment(self):
+ new_comment1, new_comment2 = (
+ TableChange.update_comment(f"New comment {i + 1}") for i in
range(2)
+ )
+ new_comment3 = TableChange.update_comment("New comment 1")
+ self.assertEqual(new_comment1.get_new_comment(), "New comment 1")
+ self.assertEqual(
+ str(new_comment1), f"UPDATECOMMENT
{new_comment1.get_new_comment()}"
+ )
+ self.assertFalse(new_comment1 == new_comment2)
+ self.assertFalse(new_comment1 == "invalid_update_comment")
+ self.assertTrue(new_comment1 == new_comment3)
+ self.assertTrue(hash(new_comment1) == hash(new_comment3))
+ self.assertFalse(hash(new_comment1) == hash(new_comment2))
+
+ def test_table_change_set_property(self):
+ new_property1, new_property2 = (
+ TableChange.set_property(f"new_property_{i + 1}", str(i + 1))
+ for i in range(2)
+ )
+ new_property3 = TableChange.set_property("new_property_1", "1")
+ self.assertEqual(new_property1.get_property(), "new_property_1")
+ self.assertEqual(new_property1.get_value(), "1")
+ self.assertEqual(
+ str(new_property1),
+ f"SETPROPERTY {new_property1.get_property()}
{new_property1.get_value()}",
+ )
+ self.assertFalse(new_property1 == new_property2)
+ self.assertFalse(new_property1 == "invalid_set_property")
+ self.assertTrue(new_property1 == new_property3)
+ self.assertTrue(hash(new_property1) == hash(new_property3))
+ self.assertFalse(hash(new_property1) == hash(new_property2))
+
+ def test_table_change_remove_property(self):
+ property1, property2 = (
+ TableChange.remove_property(f"property_{i + 1}") for i in range(2)
+ )
+ property3 = TableChange.remove_property("property_1")
+ self.assertEqual(property1.get_property(), "property_1")
+ self.assertEqual(str(property1), f"REMOVEPROPERTY
{property1.get_property()}")
+ self.assertFalse(property1 == property2)
+ self.assertFalse(property1 == "invalid_remove_property")
+ self.assertTrue(property1 == property3)
+ self.assertTrue(hash(property1) == hash(property3))
+ self.assertFalse(hash(property1) == hash(property2))
+
+ def test_column_position(self):
+ first = TableChange.ColumnPosition.first()
+ after = TableChange.ColumnPosition.after("column")
+ default_pos = TableChange.ColumnPosition.default_pos()
+
+ self.assertIsInstance(first, TableChange.ColumnPosition)
+ self.assertIsInstance(after, TableChange.ColumnPosition)
+ self.assertIsInstance(default_pos, TableChange.ColumnPosition)
+ self.assertEqual(after.get_column(), "column")
+ self.assertEqual(str(first), "FIRST")
+ self.assertEqual(str(after), "AFTER column")
+ self.assertEqual(str(default_pos), "DEFAULT")
+
+ def test_column_position_equal_and_hash(self):
+ first = TableChange.ColumnPosition.first()
+ after = TableChange.ColumnPosition.after("column")
+ default_pos = TableChange.ColumnPosition.default_pos()
+
+ self.assertFalse(first == after)
+ self.assertTrue(first == TableChange.ColumnPosition.first())
+ self.assertFalse(after == default_pos)
+ self.assertTrue(after == TableChange.ColumnPosition.after("column"))
+ self.assertTrue(hash(after) ==
hash(TableChange.ColumnPosition.after("column")))
+ self.assertFalse(
+ hash(after) == hash(TableChange.ColumnPosition.after("aonther
column"))
+ )
+ self.assertFalse(default_pos == first)
+ self.assertTrue(default_pos ==
TableChange.ColumnPosition.default_pos())
+
+ def test_add_column(self):
+ add_col_mandatory = TableChange.add_column(["col1"],
Types.StringType.get())
+ self.assertListEqual(add_col_mandatory.get_field_name(), ["col1"])
+ self.assertListEqual(add_col_mandatory.field_name(), ["col1"])
+ self.assertEqual(add_col_mandatory.get_data_type(),
Types.StringType.get())
+ self.assertIsNone(add_col_mandatory.get_comment())
+ self.assertIsNone(add_col_mandatory.get_position())
+ self.assertTrue(add_col_mandatory.is_nullable())
+ self.assertFalse(add_col_mandatory.is_auto_increment())
+ self.assertEqual(
+ add_col_mandatory.get_default_value(), Column.DEFAULT_VALUE_NOT_SET
+ )
+
+ def test_add_column_with_position(self):
+ field_name = ["Full Name", "First Name"]
+ data_type = Types.StringType.get()
+ comment = "First or given name"
+ position = TableChange.ColumnPosition.after("Address")
+ add_column = TableChange.add_column(field_name, data_type, comment,
position)
+ self.assertListEqual(add_column.get_field_name(), field_name)
+ self.assertEqual(add_column.get_data_type(), data_type)
+ self.assertEqual(add_column.get_comment(), comment)
+ self.assertEqual(add_column.get_position(), position)
+ self.assertTrue(add_column.is_nullable())
+ self.assertFalse(add_column.is_auto_increment())
+ self.assertEqual(add_column.get_default_value(),
Column.DEFAULT_VALUE_NOT_SET)
+
+ def test_add_column_with_null_comment_and_position(self):
+ field_name = ["Middle Name"]
+ data_type = Types.StringType.get()
+ add_column = TableChange.add_column(field_name, data_type, None, None)
+ self.assertListEqual(add_column.get_field_name(), field_name)
+ self.assertEqual(add_column.get_data_type(), data_type)
+ self.assertIsNone(add_column.get_comment())
+ self.assertIsNone(add_column.get_position())
+ self.assertTrue(add_column.is_nullable())
+ self.assertFalse(add_column.is_auto_increment())
+ self.assertEqual(add_column.get_default_value(),
Column.DEFAULT_VALUE_NOT_SET)
+
+ def test_add_column_equal_and_hash(self):
+ field_name = ["Name"]
+ another_field_name = ["First Name"]
+ data_type = Types.StringType.get()
+ comment = "Person name"
+ add_columns = [
+ TableChange.add_column(field_name, data_type, comment) for _ in
range(2)
+ ]
+ add_column_dict = {add_columns[i]: i for i in range(2)}
+
+ self.assertTrue(add_columns[0] == add_columns[1])
+ self.assertTrue(add_columns[1] == add_columns[0])
+ self.assertFalse(add_columns[0] == "invalid_add_column")
+ self.assertEqual(len(add_column_dict), 1)
+ self.assertEqual(add_column_dict[add_columns[0]], 1)
+
+ another_add_column = TableChange.add_column(
+ another_field_name, data_type, comment
+ )
+ add_column_dict = {add_columns[0]: 0, another_add_column: 1}
+ self.assertFalse(add_columns[0] == another_add_column)
+ self.assertFalse(another_add_column == add_columns[0])
+ self.assertEqual(len(add_column_dict), 2)
+
+ def test_rename_column(self):
+ field_name = ["Last Name"]
+ new_name = "Family Name"
+ rename_column = TableChange.rename_column(field_name, new_name)
+ self.assertListEqual(rename_column.get_field_name(), field_name)
+ self.assertListEqual(rename_column.field_name(), field_name)
+ self.assertEqual(rename_column.get_new_name(), new_name)
+
+ def test_rename_nested_column(self):
+ field_name = ["Name", "First Name"]
+ new_name = "Name.first"
+ rename_column = TableChange.rename_column(field_name, new_name)
+ self.assertListEqual(rename_column.field_name(), field_name)
+ self.assertEqual(rename_column.get_new_name(), new_name)
+
+ def test_column_rename_equal_and_hash(self):
+ field_name = ["Name"]
+ another_field_name = ["First Name"]
+ new_name = "Family Name"
+ rename_columns = [
+ TableChange.rename_column(field_name, new_name) for _ in range(2)
+ ]
+ rename_column_dict = {rename_columns[i]: i for i in range(2)}
+
+ self.assertTrue(rename_columns[0] == rename_columns[1])
+ self.assertTrue(rename_columns[1] == rename_columns[0])
+ self.assertFalse(rename_columns[0] == "invalid_rename_column")
+ self.assertEqual(len(rename_column_dict), 1)
+ self.assertEqual(rename_column_dict[rename_columns[0]], 1)
+
+ another_rename_column = TableChange.rename_column(another_field_name,
new_name)
+ rename_column_dict = {rename_columns[0]: 0, another_rename_column: 1}
+ self.assertFalse(rename_columns[0] == another_rename_column)
+ self.assertFalse(another_rename_column == rename_columns[0])
+ self.assertEqual(len(rename_column_dict), 2)
+
+ def test_update_column_default_value(self):
+ field_name_data = [["existing_column"], ["nested", "existing_column"]]
+ new_default_value = Literals.of("Default Value",
Types.VarCharType.of(255))
+
+ for field_name in field_name_data:
+ update_column_default_value =
TableChange.update_column_default_value(
+ field_name, new_default_value
+ )
+ self.assertListEqual(update_column_default_value.field_name(),
field_name)
+ self.assertEqual(
+ update_column_default_value.get_new_default_value(),
new_default_value
+ )
+
+ update_column_default_value = TableChange.update_column_default_value(
+ field_name_data[0], Column.DEFAULT_VALUE_NOT_SET
+ )
+ self.assertListEqual(
+ update_column_default_value.field_name(), field_name_data[0]
+ )
+ self.assertEqual(
+ update_column_default_value.get_new_default_value(),
+ Column.DEFAULT_VALUE_NOT_SET,
+ )
+
+ def test_update_column_default_value_equal_and_hash(self):
+ field_name = ["existing_column"]
+ new_default_value = Literals.of("Default Value",
Types.VarCharType.of(255))
+ update_column_default_values = [
+ TableChange.update_column_default_value(field_name,
new_default_value)
+ for _ in range(2)
+ ]
+ update_column_default_value_dict = {
+ update_column_default_values[i]: i for i in range(2)
+ }
+
+ self.assertTrue(
+ update_column_default_values[0] == update_column_default_values[1]
+ )
+ self.assertTrue(
+ update_column_default_values[1] == update_column_default_values[0]
+ )
+ self.assertFalse(
+ update_column_default_values[0] ==
"invalid_update_column_default_value"
+ )
+ self.assertEqual(len(update_column_default_value_dict), 1)
+ self.assertEqual(
+ update_column_default_value_dict[update_column_default_values[0]],
1
+ )
+
+ update_column_default_values = [
+ TableChange.update_column_default_value(
+ field_name, Column.DEFAULT_VALUE_NOT_SET
+ )
+ for _ in range(2)
+ ]
+
+ update_column_default_value_dict = {
+ update_column_default_values[i]: i for i in range(2)
+ }
+
+ self.assertTrue(
+ update_column_default_values[0] == update_column_default_values[1]
+ )
+ self.assertTrue(
+ update_column_default_values[1] == update_column_default_values[0]
+ )
+ self.assertEqual(len(update_column_default_value_dict), 1)
+ self.assertEqual(
+ update_column_default_value_dict[update_column_default_values[0]],
1
+ )
+
+ def test_update_column_type(self):
+ field_name_data = [["existing_column"], ["nested", "existing_column"]]
+ data_type = Types.StringType.get()
+ for field_name in field_name_data:
+ update_column_type = TableChange.update_column_type(field_name,
data_type)
+ self.assertListEqual(update_column_type.field_name(), field_name)
+ self.assertListEqual(update_column_type.get_field_name(),
field_name)
+ self.assertTrue(update_column_type.get_new_data_type() ==
data_type)
+
+ def test_update_column_type_equal_and_hash(self):
+ field_name = ["First Name"]
+ data_type = Types.StringType.get()
+ update_column_types = [
+ TableChange.update_column_type(field_name, data_type) for _ in
range(2)
+ ]
+ update_column_type_dict = {update_column_types[i]: i for i in range(2)}
+
+ self.assertTrue(update_column_types[0] == update_column_types[1])
+ self.assertTrue(update_column_types[1] == update_column_types[0])
+ self.assertFalse(update_column_types[0] ==
"invalid_update_column_type")
+ self.assertEqual(len(update_column_type_dict), 1)
+ self.assertEqual(update_column_type_dict[update_column_types[0]], 1)
+
+ another_update_column_type = TableChange.update_column_type(
+ ["Last Name"], data_type
+ )
+ update_column_type_dict = {
+ update_column_types[0]: 0,
+ another_update_column_type: 1,
+ }
+ self.assertFalse(update_column_types[0] == another_update_column_type)
+ self.assertFalse(another_update_column_type == update_column_types[0])
+ self.assertEqual(len(update_column_type_dict), 2)
+
+ def test_update_column_comment(self):
+ field_name_data = [["First Name"], ["nested", "Last Name"]]
+ comment_data = ["First or given name", "Last or family name"]
+ for field_name, comment in zip(field_name_data, comment_data):
+ update_column_comment = TableChange.update_column_comment(
+ field_name, comment
+ )
+ self.assertListEqual(update_column_comment.field_name(),
field_name)
+ self.assertListEqual(update_column_comment.get_field_name(),
field_name)
+ self.assertEqual(update_column_comment.get_new_comment(), comment)
+
+ def test_update_column_comment_equal_and_hash(self):
+ field_name = ["First Name"]
+ comment = "First or given name"
+ update_column_comments = [
+ TableChange.update_column_comment(field_name, comment) for _ in
range(2)
+ ]
+ update_column_comment_dict = {update_column_comments[i]: i for i in
range(2)}
+ self.assertTrue(update_column_comments[0] == update_column_comments[1])
+ self.assertTrue(update_column_comments[1] == update_column_comments[0])
+ self.assertEqual(len(update_column_comment_dict), 1)
+
+ another_update_column_comment = TableChange.update_column_comment(
+ ["Last Name"], "Last or family name"
+ )
+ update_column_comment_dict = {
+ update_column_comments[0]: 0,
+ another_update_column_comment: 1,
+ }
+ self.assertFalse(update_column_comments[0] ==
another_update_column_comment)
+ self.assertFalse(another_update_column_comment ==
update_column_comments[0])
+ self.assertFalse(update_column_comments[0] ==
"invalid_update_column_comment")
+ self.assertEqual(len(update_column_comment_dict), 2)
+
+ def test_update_column_position(self):
+ field_name_data = [["First Name"], ["nested", "Last Name"]]
+ position_data = [
+ TableChange.ColumnPosition.first(),
+ TableChange.ColumnPosition.after("First Name"),
+ ]
+ for field_name, position in zip(field_name_data, position_data):
+ update_column_position = TableChange.update_column_position(
+ field_name, position
+ )
+ self.assertListEqual(update_column_position.field_name(),
field_name)
+ self.assertListEqual(update_column_position.get_field_name(),
field_name)
+ self.assertEqual(update_column_position.get_position(), position)
+
+ def test_update_column_position_equal_and_hash(self):
+ field_name = ["First Name"]
+ position = TableChange.ColumnPosition.first()
+ update_column_positions = [
+ TableChange.update_column_position(field_name, position) for _ in
range(2)
+ ]
+ update_column_position_dict = {update_column_positions[i]: i for i in
range(2)}
+ self.assertTrue(update_column_positions[0] ==
update_column_positions[1])
+ self.assertTrue(update_column_positions[1] ==
update_column_positions[0])
+ self.assertEqual(len(update_column_position_dict), 1)
+
+ another_update_column_position = TableChange.update_column_position(
+ ["Last Name"], TableChange.ColumnPosition.after("First Name")
+ )
+ update_column_position_dict = {
+ update_column_positions[0]: 0,
+ another_update_column_position: 1,
+ }
+ self.assertFalse(update_column_positions[0] ==
another_update_column_position)
+ self.assertFalse(another_update_column_position ==
update_column_positions[0])
+ self.assertFalse(update_column_positions[0] ==
"invalid_update_column_position")
+ self.assertEqual(len(update_column_position_dict), 2)
+
+ def test_delete_column(self):
+ field_name_data = [["existing_column"], ["nested", "existing_column"]]
+ if_exists_data = [True, False]
+ for field_name, if_exists in zip(field_name_data, if_exists_data):
+ delete_column = TableChange.delete_column(field_name, if_exists)
+ self.assertListEqual(delete_column.field_name(), field_name)
+ self.assertListEqual(delete_column.get_field_name(), field_name)
+ self.assertEqual(delete_column.get_if_exists(), if_exists)
+
+ def test_delete_column_equal_and_hash(self):
+ field_name = ["Column A"]
+ if_exists = True
+ delete_columns = [
+ TableChange.delete_column(field_name, if_exists) for _ in range(2)
+ ]
+ delete_column_dict = {delete_columns[i]: i for i in range(2)}
+ self.assertTrue(delete_columns[0] == delete_columns[1])
+ self.assertTrue(delete_columns[1] == delete_columns[0])
+ self.assertEqual(len(delete_column_dict), 1)
+
+ another_delete_column = TableChange.delete_column(["Column B"],
if_exists)
+ delete_column_dict = {delete_columns[0]: 0, another_delete_column: 1}
+ self.assertFalse(delete_columns[0] == another_delete_column)
+ self.assertFalse(another_delete_column == delete_columns[0])
+ self.assertFalse(delete_columns[0] == "invalid_delete_column")
+ self.assertEqual(len(delete_column_dict), 2)
+
+ def test_update_column_nullability(self):
+ field_name_data = [["existing_column"], ["nested", "existing_column"]]
+ nullable_data = [True, False]
+ for field_name, nullable in zip(field_name_data, nullable_data):
+ update_column_nullability = TableChange.update_column_nullability(
+ field_name, nullable
+ )
+ self.assertListEqual(update_column_nullability.field_name(),
field_name)
+ self.assertListEqual(update_column_nullability.get_field_name(),
field_name)
+ self.assertEqual(update_column_nullability.get_nullable(),
nullable)
+
+ def test_update_column_nullability_equal_and_hash(self):
+ field_name = ["Column A"]
+ nullable = True
+ update_column_nullabilities = [
+ TableChange.update_column_nullability(field_name, nullable)
+ for _ in range(2)
+ ]
+ update_column_nullability_dict = {
+ update_column_nullabilities[i]: i for i in range(2)
+ }
+ self.assertTrue(
+ update_column_nullabilities[0] == update_column_nullabilities[1]
+ )
+ self.assertTrue(
+ update_column_nullabilities[1] == update_column_nullabilities[0]
+ )
+ self.assertEqual(len(update_column_nullability_dict), 1)
+
+ another_update_column_nullability =
TableChange.update_column_nullability(
+ ["Column B"], False
+ )
+ update_column_nullability_dict = {
+ update_column_nullabilities[0]: 0,
+ another_update_column_nullability: 1,
+ }
+ self.assertFalse(
+ update_column_nullabilities[0] == another_update_column_nullability
+ )
+ self.assertFalse(
+ another_update_column_nullability == update_column_nullabilities[0]
+ )
+ self.assertFalse(
+ update_column_nullabilities[0] ==
"invalid_update_column_nullability"
+ )
+ self.assertEqual(len(update_column_nullability_dict), 2)
+
+ def test_add_index(self):
+ index_name = "index_name"
+ field_names = [["id"]]
+ index_type = Index.IndexType.PRIMARY_KEY
+ add_index = TableChange.add_index(index_type, index_name, field_names)
+ self.assertEqual(add_index.get_name(), index_name)
+ self.assertListEqual(add_index.get_field_names(), field_names)
+ self.assertIs(add_index.get_type(), index_type)
+
+ def test_add_index_equal_and_hash(self):
+ index_name = "index_name"
+ field_names = [["Column A"], ["Column B"]]
+ index_type = Index.IndexType.UNIQUE_KEY
+ add_indexes = [
+ TableChange.add_index(index_type, index_name, field_names) for _
in range(2)
+ ]
+ add_index_dict = {add_indexes[i]: i for i in range(2)}
+ self.assertTrue(add_indexes[0] == add_indexes[1])
+ self.assertTrue(add_indexes[1] == add_indexes[0])
+ self.assertFalse(add_indexes[0] == "invalid_add_index")
+ self.assertEqual(len(add_index_dict), 1)
+
+ another_add_index = TableChange.add_index(
+ Index.IndexType.PRIMARY_KEY, "another_index_name", [["id"]]
+ )
+ add_index_dict = {add_indexes[0]: 0, another_add_index: 1}
+ self.assertFalse(add_indexes[0] == another_add_index)
+ self.assertFalse(another_add_index == add_indexes[0])
+ self.assertEqual(len(add_index_dict), 2)
+
+ def test_delete_index(self):
+ index_name = "index_name"
+ if_exists = True
+ delete_index = TableChange.delete_index(index_name, if_exists)
+ self.assertEqual(delete_index.get_name(), index_name)
+ self.assertEqual(delete_index.is_if_exists(), if_exists)
+
+ def test_delete_index_equal_and_hash(self):
+ index_name = "index_name"
+ if_exists = True
+ delete_indexes = [
+ TableChange.delete_index(index_name, if_exists) for _ in range(2)
+ ]
+ delete_index_dict = {delete_indexes[i]: i for i in range(2)}
+ self.assertTrue(delete_indexes[0] == delete_indexes[1])
+ self.assertTrue(delete_indexes[1] == delete_indexes[0])
+ self.assertFalse(delete_indexes[0] == "invalid_delete_index")
+ self.assertEqual(len(delete_index_dict), 1)
+
+ another_delete_index = TableChange.delete_index("another_index_name",
if_exists)
+ delete_index_dict = {delete_indexes[0]: 0, another_delete_index: 1}
+ self.assertFalse(delete_indexes[0] == another_delete_index)
+ self.assertFalse(another_delete_index == delete_indexes[0])
+ self.assertEqual(len(delete_index_dict), 2)
+
+ def test_update_column_auto_increment(self):
+ field_name_data = [["existing_column"], ["nested", "existing_column"]]
+ auto_increment_data = [True, False]
+ for field_name, auto_increment in zip(field_name_data,
auto_increment_data):
+ update_column_auto_increment =
TableChange.update_column_auto_increment(
+ field_name, auto_increment
+ )
+ self.assertListEqual(update_column_auto_increment.field_name(),
field_name)
+ self.assertEqual(
+ update_column_auto_increment.is_auto_increment(),
auto_increment
+ )
+
+ def test_update_column_auto_increment_equal_and_hash(self):
+ field_name = ["Column A"]
+ auto_increment = True
+ update_column_auto_increments = [
+ TableChange.update_column_auto_increment(field_name,
auto_increment)
+ for _ in range(2)
+ ]
+ update_column_auto_increment_dict = {
+ update_column_auto_increments[i]: i for i in range(2)
+ }
+ self.assertTrue(
+ update_column_auto_increments[0] ==
update_column_auto_increments[1]
+ )
+ self.assertTrue(
+ update_column_auto_increments[1] ==
update_column_auto_increments[0]
+ )
+ self.assertEqual(len(update_column_auto_increment_dict), 1)
+
+ another_update_column_auto_increment =
TableChange.update_column_auto_increment(
+ ["Column B"], False
+ )
+ update_column_auto_increment_dict = {
+ update_column_auto_increments[0]: 0,
+ another_update_column_auto_increment: 1,
+ }
+ self.assertFalse(
+ update_column_auto_increments[0] ==
another_update_column_auto_increment
+ )
+ self.assertFalse(
+ another_update_column_auto_increment ==
update_column_auto_increments[0]
+ )
+ self.assertFalse(
+ update_column_auto_increments[0] ==
"invalid_update_column_auto_increment"
+ )
+ self.assertEqual(len(update_column_auto_increment_dict), 2)
diff --git a/clients/client-python/tests/unittests/rel/test_transforms.py
b/clients/client-python/tests/unittests/rel/test_transforms.py
index 495c88775b..0b354b7a8d 100644
--- a/clients/client-python/tests/unittests/rel/test_transforms.py
+++ b/clients/client-python/tests/unittests/rel/test_transforms.py
@@ -21,8 +21,8 @@ from itertools import combinations
from gravitino.api.expressions.literals.literals import Literals
from gravitino.api.expressions.named_reference import NamedReference
-from gravitino.api.expressions.partitions.partitions import Partitions
from gravitino.api.expressions.transforms.transforms import Transforms
+from gravitino.api.rel.partitions.partitions import Partitions
class TestTransforms(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/rel/test_types.py
b/clients/client-python/tests/unittests/rel/test_types.py
index c742281e7e..940b11f99d 100644
--- a/clients/client-python/tests/unittests/rel/test_types.py
+++ b/clients/client-python/tests/unittests/rel/test_types.py
@@ -17,7 +17,7 @@
import unittest
-from gravitino.api.types.types import Types, Name
+from gravitino.api.rel.types.types import Name, Types
class TestTypes(unittest.TestCase):
diff --git a/clients/client-python/tests/unittests/test_column.py
b/clients/client-python/tests/unittests/test_column.py
index 672ce5d82d..d3ca33c73f 100644
--- a/clients/client-python/tests/unittests/test_column.py
+++ b/clients/client-python/tests/unittests/test_column.py
@@ -18,10 +18,10 @@
import unittest
from unittest.mock import Mock
-from gravitino.api.column import Column, ColumnImpl
from gravitino.api.expressions.expression import Expression
from gravitino.api.expressions.function_expression import FunctionExpression
-from gravitino.api.types.type import Type
+from gravitino.api.rel.column import Column, ColumnImpl
+from gravitino.api.rel.types.type import Type
from gravitino.exceptions.base import (
IllegalArgumentException,
UnsupportedOperationException,