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 cb4c690630 [#5199] feat(client-python): add sort order DTO (#8220)
cb4c690630 is described below
commit cb4c69063063ebdf146089f494876957125a1599
Author: George T. C. Lai <[email protected]>
AuthorDate: Thu Aug 21 14:41:03 2025 +0800
[#5199] feat(client-python): add sort order DTO (#8220)
### What changes were proposed in this pull request?
This PR is aimed at implementing class `SortOrderDTO` corresponding to
the one in 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]>
---
.../gravitino/dto/rel/sort_order_dto.py | 85 ++++++++++++++++++++++
.../tests/unittests/dto/rel/test_sort_order_dto.py | 68 +++++++++++++++++
2 files changed, 153 insertions(+)
diff --git a/clients/client-python/gravitino/dto/rel/sort_order_dto.py
b/clients/client-python/gravitino/dto/rel/sort_order_dto.py
new file mode 100644
index 0000000000..3d6fa77a08
--- /dev/null
+++ b/clients/client-python/gravitino/dto/rel/sort_order_dto.py
@@ -0,0 +1,85 @@
+# 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 typing import ClassVar, List
+
+from gravitino.api.expressions.expression import Expression
+from gravitino.api.expressions.sorts.null_ordering import NullOrdering
+from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.expressions.sorts.sort_order import SortOrder
+from gravitino.dto.rel.column_dto import ColumnDTO
+from gravitino.dto.rel.expressions.function_arg import FunctionArg
+from gravitino.utils.precondition import Precondition
+
+
+class SortOrderDTO(SortOrder):
+ """Data Transfer Object for SortOrder.
+
+ Attributes:
+ EMPTY_SORT (List[SortOrderDTO]):
+ An empty array of SortOrderDTO.
+ """
+
+ EMPTY_SORT: ClassVar[List["SortOrderDTO"]] = []
+
+ def __init__(
+ self,
+ sort_term: FunctionArg,
+ direction: SortDirection,
+ null_ordering: NullOrdering,
+ ):
+ Precondition.check_argument(sort_term is not None, "expression cannot
be null")
+
+ self._sort_term = sort_term
+ self._direction = (
+ direction if direction is not None else SortDirection.ASCENDING
+ )
+ self._null_ordering = (
+ null_ordering
+ if null_ordering is not None
+ else direction.default_null_ordering()
+ )
+
+ def sort_term(self) -> FunctionArg:
+ """Returns the sort term.
+
+ Returns:
+ FunctionArg: The sort term.
+ """
+ return self._sort_term
+
+ def expression(self) -> Expression:
+ return self._sort_term
+
+ def direction(self):
+ return self._direction
+
+ def null_ordering(self):
+ return self._null_ordering
+
+ def validate(self, columns: List[ColumnDTO]) -> None:
+ """Validates the sort order.
+
+ Args:
+ columns (List[ColumnDTO]):
+ The column DTOs to validate against.
+
+ Raises:
+ IllegalArgumentException:
+ If the sort order is invalid, this exception is thrown.
+ """
+ self._sort_term.validate(columns)
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
new file mode 100644
index 0000000000..e7cdf8950a
--- /dev/null
+++ b/clients/client-python/tests/unittests/dto/rel/test_sort_order_dto.py
@@ -0,0 +1,68 @@
+# 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.sorts.null_ordering import NullOrdering
+from gravitino.api.expressions.sorts.sort_direction import SortDirection
+from gravitino.api.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
+from gravitino.exceptions.base import IllegalArgumentException
+
+
+class TestSortOrderDTO(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.field_ref_dto = (
+ FieldReferenceDTO.builder().with_field_name(["field1"]).build()
+ )
+ cls.columns = [
+ ColumnDTO.builder()
+ .with_name("field1")
+ .with_data_type(Types.StringType.get())
+ .build(),
+ ColumnDTO.builder()
+ .with_name("field2")
+ .with_data_type(Types.StringType.get())
+ .build(),
+ ]
+ cls.sort_order_dto = SortOrderDTO(
+ cls.field_ref_dto,
+ SortDirection.ASCENDING,
+ NullOrdering.NULLS_FIRST,
+ )
+
+ def test_sort_dto_class_vars(self):
+ self.assertEqual(SortOrderDTO.EMPTY_SORT, [])
+ self.assertEqual(SortOrderDTO.EMPTY_EXPRESSION, [])
+ self.assertEqual(SortOrderDTO.EMPTY_NAMED_REFERENCE, [])
+
+ def test_sort_order_dto_init(self):
+ with self.assertRaisesRegex(
+ IllegalArgumentException, "expression cannot be null"
+ ):
+ SortOrderDTO(None, SortDirection.ASCENDING,
NullOrdering.NULLS_FIRST)
+
+ self.sort_order_dto.validate(self.columns)
+ self.assertTrue(self.sort_order_dto.sort_term() == self.field_ref_dto)
+ self.assertIs(self.sort_order_dto.direction(), SortDirection.ASCENDING)
+ self.assertIs(self.sort_order_dto.null_ordering(),
NullOrdering.NULLS_FIRST)
+ self.assertEqual(
+ self.sort_order_dto.expression(), self.sort_order_dto.sort_term()
+ )