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 9afa4cd6b0 [#5199] feat(client-python): add index DTO (#8262)
9afa4cd6b0 is described below

commit 9afa4cd6b0d7fc8e245fc745b5422a724631d61f
Author: George T. C. Lai <[email protected]>
AuthorDate: Tue Aug 26 13:58:56 2025 +0800

    [#5199] feat(client-python): add index DTO (#8262)
    
    ### What changes were proposed in this pull request?
    
    This PR is aimed at implementing the class `IndexDTO` corresponding to
    the Java client.
    
    ### Why are the changes needed?
    
    We need to support table partitioning, bucketing and sort ordering and
    indexes.
    
    #5199
    
    ### 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]>
    Co-authored-by: Jerry Shao <[email protected]>
---
 .../gravitino/api/expressions/indexes/index.py     |  6 +-
 .../gravitino/api/expressions/indexes/indexes.py   |  9 ++-
 .../gravitino/dto/rel/indexes/__init__.py          | 16 +++++
 .../gravitino/dto/rel/indexes/index_dto.py         | 74 ++++++++++++++++++++++
 .../tests/unittests/dto/rel/test_index_dto.py      | 72 +++++++++++++++++++++
 5 files changed, 171 insertions(+), 6 deletions(-)

diff --git a/clients/client-python/gravitino/api/expressions/indexes/index.py 
b/clients/client-python/gravitino/api/expressions/indexes/index.py
index 82d0931d8f..777e3b4813 100644
--- a/clients/client-python/gravitino/api/expressions/indexes/index.py
+++ b/clients/client-python/gravitino/api/expressions/indexes/index.py
@@ -18,7 +18,7 @@
 
 from abc import ABC, abstractmethod
 from enum import Enum, unique
-from typing import List
+from typing import List, Optional
 
 
 class Index(ABC):
@@ -60,11 +60,11 @@ class Index(ABC):
         pass  # pragma: no cover
 
     @abstractmethod
-    def name(self) -> str:
+    def name(self) -> Optional[str]:
         """Returns the name of the index.
 
         Returns:
-            str: The name of the index.
+            Optional[str]: The name of the index.
         """
         pass  # pragma: no cover
 
diff --git a/clients/client-python/gravitino/api/expressions/indexes/indexes.py 
b/clients/client-python/gravitino/api/expressions/indexes/indexes.py
index f2a75ba768..720e2b46fe 100644
--- a/clients/client-python/gravitino/api/expressions/indexes/indexes.py
+++ b/clients/client-python/gravitino/api/expressions/indexes/indexes.py
@@ -16,7 +16,7 @@
 # under the License.
 
 
-from typing import ClassVar, List, final
+from typing import ClassVar, List, Optional, final
 
 from gravitino.api.expressions.indexes.index import Index
 
@@ -50,7 +50,10 @@ class Indexes:
     @final
     class IndexImpl(Index):
         def __init__(
-            self, index_type: Index.IndexType, name: str, field_names: 
List[List[str]]
+            self,
+            index_type: Index.IndexType,
+            name: Optional[str],
+            field_names: List[List[str]],
         ):
             self._index_type = index_type
             self._name = name
@@ -59,7 +62,7 @@ class Indexes:
         def type(self) -> Index.IndexType:
             return self._index_type
 
-        def name(self) -> str:
+        def name(self) -> Optional[str]:
             return self._name
 
         def field_names(self) -> List[List[str]]:
diff --git a/clients/client-python/gravitino/dto/rel/indexes/__init__.py 
b/clients/client-python/gravitino/dto/rel/indexes/__init__.py
new file mode 100644
index 0000000000..13a83393a9
--- /dev/null
+++ b/clients/client-python/gravitino/dto/rel/indexes/__init__.py
@@ -0,0 +1,16 @@
+# 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.
diff --git a/clients/client-python/gravitino/dto/rel/indexes/index_dto.py 
b/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
new file mode 100644
index 0000000000..d78843ab22
--- /dev/null
+++ b/clients/client-python/gravitino/dto/rel/indexes/index_dto.py
@@ -0,0 +1,74 @@
+# 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 functools import reduce
+from typing import ClassVar, List, Optional
+
+from gravitino.api.expressions.indexes.index import Index
+from gravitino.utils.precondition import Precondition
+
+
+class IndexDTO(Index):
+    """Data transfer object representing index information.
+
+    Attributes:
+        EMPTY_INDEXES (List[IndexDTO]): An empty array of indexes.
+    """
+
+    EMPTY_INDEXES: ClassVar[List["IndexDTO"]] = []
+
+    def __init__(
+        self,
+        index_type: Index.IndexType,
+        name: Optional[str],
+        field_names: List[List[str]],
+    ):
+        Precondition.check_argument(index_type is not None, "Index type cannot 
be null")
+        Precondition.check_argument(
+            field_names is not None and len(field_names) > 0,
+            "The index must be set with corresponding column names",
+        )
+
+        self._index_type = index_type
+        self._name = name
+        self._field_names = field_names
+
+    def type(self) -> Index.IndexType:
+        return self._index_type
+
+    def name(self) -> Optional[str]:
+        return self._name
+
+    def field_names(self) -> List[List[str]]:
+        return self._field_names
+
+    def __eq__(self, other) -> bool:
+        if not isinstance(other, IndexDTO):
+            return False
+        return (
+            self._index_type is other.type()
+            and self._name is other.name()
+            and self._field_names == other.field_names()
+        )
+
+    def __hash__(self) -> int:
+        initial_hash = hash((self._index_type, self._name))
+        return reduce(
+            lambda result, field_name: 31 * result + hash(tuple(field_name)),
+            self._field_names,
+            initial_hash,
+        )
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
new file mode 100644
index 0000000000..5bb9fa31dc
--- /dev/null
+++ b/clients/client-python/tests/unittests/dto/rel/test_index_dto.py
@@ -0,0 +1,72 @@
+# 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.indexes.index import Index
+from gravitino.dto.rel.indexes.index_dto import IndexDTO
+from gravitino.exceptions.base import IllegalArgumentException
+
+
+class TestIndexDTO(unittest.TestCase):
+    def test_index_dto_invalid_init(self):
+        self.assertRaisesRegex(
+            IllegalArgumentException,
+            "Index type cannot be null",
+            IndexDTO,
+            None,
+            "invalid_index_type",
+            [["field1", "field2"]],
+        )
+        self.assertRaisesRegex(
+            IllegalArgumentException,
+            "The index must be set with corresponding column names",
+            IndexDTO,
+            Index.IndexType.PRIMARY_KEY,
+            "invalid_field_names",
+            None,
+        )
+        self.assertRaisesRegex(
+            IllegalArgumentException,
+            "The index must be set with corresponding column names",
+            IndexDTO,
+            Index.IndexType.PRIMARY_KEY,
+            "invalid_field_names",
+            [],
+        )
+
+    def test_index_dto(self):
+        names = (None, "", "index_name")
+        field_names = [["col1"], ["col2"]]
+        dto_dict = {}
+        index_dto = None
+        for idx, name in enumerate(names):
+            index_dto = IndexDTO(Index.IndexType.PRIMARY_KEY, name, 
field_names)
+            dto_dict[index_dto] = idx
+
+            self.assertIs(index_dto.type(), Index.IndexType.PRIMARY_KEY)
+            self.assertEqual(index_dto.name(), name)
+            self.assertListEqual(index_dto.field_names(), field_names)
+
+        slack_dto = IndexDTO(Index.IndexType.PRIMARY_KEY, "index_name", 
field_names)
+        self.assertTrue(index_dto == slack_dto)
+        self.assertFalse(index_dto == "index_dto")
+        self.assertEqual(dto_dict[slack_dto], len(names) - 1)
+
+        dto_dict[slack_dto] = len(names)
+        self.assertEqual(len(dto_dict), len(names))
+        self.assertEqual(dto_dict[slack_dto], len(names))

Reply via email to