This is an automated email from the ASF dual-hosted git repository.
unknowntpo 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 9c24f83ef7 [#5202] refactor(client-python): fix builder method of DTOs
in expression (#7582)
9c24f83ef7 is described below
commit 9c24f83ef78cdaaed355d354ec793eadecc93c71
Author: George T. C. Lai <[email protected]>
AuthorDate: Tue Jul 8 19:20:04 2025 +0800
[#5202] refactor(client-python): fix builder method of DTOs in expression
(#7582)
<!--
1. Title: [#<issue>] <type>(<scope>): <subject>
Examples:
- "[#123] feat(operator): support xxx"
- "[#233] fix: check null before access result in xxx"
- "[MINOR] refactor: fix typo in variable name"
- "[MINOR] docs: fix typo in README"
- "[#255] test: fix flaky test NameOfTheTest"
Reference: https://www.conventionalcommits.org/en/v1.0.0/
2. If the PR is unfinished, please mark this PR as draft.
-->
### What changes were proposed in this pull request?
This is a refactor of builder method for `LiteralDTO`,
`FieldReferenceDTO`, `FuncExpressionDTO`, and `UnparsedExpressionDTO`
that is proposed in the
[comments](https://github.com/apache/gravitino/pull/7498#pullrequestreview-2974695664)
of the previous PR.
### Why are the changes needed?
We need to support Column and its default value in python client.
#5202
### 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]>
---
.../dto/rel/expressions/field_reference_dto.py | 50 ++++++++++++++++++++
.../dto/rel/expressions/func_expression_dto.py | 55 ++++++++++++++++++++++
.../gravitino/dto/rel/expressions/literal_dto.py | 48 +++++++++++++++++++
.../dto/rel/expressions/unparsed_expression_dto.py | 41 ++++++++++++++++
.../unittests/dto/rel/test_field_reference_dto.py | 26 ++++++++--
.../unittests/dto/rel/test_func_expression_dto.py | 39 +++++++++++----
.../tests/unittests/dto/rel/test_literal_dto.py | 30 ++++++++++--
.../dto/rel/test_unparsed_expression_dto.py | 16 +++++--
8 files changed, 286 insertions(+), 19 deletions(-)
diff --git
a/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
b/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
index 22639d8d00..2e60df5f9e 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/field_reference_dto.py
@@ -42,3 +42,53 @@ class FieldReferenceDTO(NamedReference, FunctionArg):
def __hash__(self) -> int:
return hash((self.arg_type(), tuple(self._field_name)))
+
+ @staticmethod
+ def builder() -> Builder:
+ """The builder for creating a new instance of `FieldReferenceDTO`.
+
+ Returns:
+ Builder: The builder for creating a new instance of
`FieldReferenceDTO`.
+ """
+ return FieldReferenceDTO.Builder()
+
+ class Builder:
+ """Builder for `FieldRererenceDTO`"""
+
+ def __init__(self):
+ self._field_name = None
+
+ def with_field_name(self, field_name: List[str]) ->
FieldReferenceDTO.Builder:
+ """Set the field name for the field reference.
+
+ Args:
+ field_name (List[str]): The field name.
+
+ Returns:
+ FieldReferenceDTO.Builder: The builder.
+ """
+
+ self._field_name = field_name
+ return self
+
+ def with_column_name(self, column_name: List[str]) ->
FieldReferenceDTO.Builder:
+ """Set the column name for the field reference.
+
+ Args:
+ column_name (List[str]): The column name.
+
+ Returns:
+ FieldReferenceDTO.Builder: The builder.
+ """
+
+ self._field_name = column_name
+ return self
+
+ def build(self) -> FieldReferenceDTO:
+ """Build the field reference.
+
+ Returns:
+ FieldReferenceDTO: The field reference.
+ """
+
+ return FieldReferenceDTO(field_name=self._field_name)
diff --git
a/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
b/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
index e210a8e69f..a61f08ee52 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/func_expression_dto.py
@@ -57,3 +57,58 @@ class FuncExpressionDTO(FunctionExpression, FunctionArg):
def __hash__(self) -> int:
return hash((self.arg_type(), self._function_name,
tuple(self._function_args)))
+
+ @staticmethod
+ def builder() -> Builder:
+ """The builder for creating a new instance of `FuncExpressionDTO`.
+
+ Returns:
+ Builder: The builder for creating a new instance of
`FuncExpressionDTO`.
+ """
+ return FuncExpressionDTO.Builder()
+
+ class Builder:
+ """Builder for `FuncExpressionDTO.`"""
+
+ def __init__(self):
+ self._function_args = None
+ self._function_name = None
+
+ def with_function_name(self, function_name: str) ->
FuncExpressionDTO.Builder:
+ """Set the function name for the function expression.
+
+ Args:
+ function_name (str): The function name.
+
+ Returns:
+ FuncExpressionDTO.Builder: The builder.
+ """
+
+ self._function_name = function_name
+ return self
+
+ def with_function_args(
+ self, function_args: List[FunctionArg]
+ ) -> FuncExpressionDTO.Builder:
+ """Set the function arguments for the function expression.
+
+ Args:
+ function_args (List[FunctionArg]): The function arguments.
+
+ Returns:
+ FuncExpressionDTO.Builder: The builder.
+ """
+
+ self._function_args = function_args
+ return self
+
+ def build(self) -> FuncExpressionDTO:
+ """Build the function expression.
+
+ Returns:
+ FuncExpressionDTO: The function expression.
+ """
+
+ return FuncExpressionDTO(
+ function_name=self._function_name,
function_args=self._function_args
+ )
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 4e0ba4bbc4..7e416c31c3 100644
--- a/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
+++ b/clients/client-python/gravitino/dto/rel/expressions/literal_dto.py
@@ -71,5 +71,53 @@ class LiteralDTO(Literal[str], FunctionArg):
def __str__(self) -> str:
return f"LiteralDTO(value='{self._value}',
data_type={self._data_type})"
+ @staticmethod
+ def builder() -> Builder:
+ """the builder for creating a new instance of LiteralDTO.
+
+ Returns:
+ Builder: the builder for creating a new instance of LiteralDTO.
+ """
+ return LiteralDTO.Builder()
+
+ class Builder:
+ """Builder for LiteralDTO."""
+
+ def __init__(self):
+ self._data_type = None
+ self._value = None
+
+ def with_value(self, value: str) -> LiteralDTO.Builder:
+ """Set the value of the literal.
+
+ Args:
+ value (str): The value of the literal.
+
+ Returns:
+ Builder: The builder.
+ """
+ self._value = value
+ return self
+
+ def with_data_type(self, data_type: Type) -> LiteralDTO.Builder:
+ """Set the data type of the literal.
+
+ Args:
+ data_type (Type): The data type of the literal.
+
+ Returns:
+ Builder: The builder.
+ """
+ self._data_type = data_type
+ return self
+
+ def build(self) -> LiteralDTO:
+ """Builds a `LiteralDTO` instance.
+
+ Returns:
+ LiteralDTO: The `LiteralDTO` instance.
+ """
+ return LiteralDTO(value=self._value, data_type=self._data_type)
+
LiteralDTO.NULL = LiteralDTO("NULL", Types.NullType.get())
diff --git
a/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
b/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
index d62a66ebe0..420b80c1b1 100644
---
a/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
+++
b/clients/client-python/gravitino/dto/rel/expressions/unparsed_expression_dto.py
@@ -15,6 +15,8 @@
# specific language governing permissions and limitations
# under the License.
+from __future__ import annotations
+
from gravitino.api.expressions.unparsed_expression import UnparsedExpression
from gravitino.dto.rel.expressions.function_arg import FunctionArg
@@ -48,3 +50,42 @@ class UnparsedExpressionDTO(UnparsedExpression, FunctionArg):
return (
f"UnparsedExpressionDTO{{unparsedExpression='{self._unparsed_expression}'}}"
)
+
+ @staticmethod
+ def builder() -> Builder:
+ """A builder instance for `UnparsedExpressionDTO`.
+
+ Returns:
+ Builder: A builder instance for `UnparsedExpressionDTO`.
+ """
+ return UnparsedExpressionDTO.Builder()
+
+ class Builder:
+ """Builder for `UnparsedExpressionDTO`."""
+
+ def __init__(self):
+ self._unparsed_expression = None
+
+ def with_unparsed_expression(
+ self, unparsed_expression: str
+ ) -> UnparsedExpressionDTO.Builder:
+ """Set the unparsed expression.
+
+ Args:
+ unparsed_expression (str): The unparsed expression.
+
+ Returns:
+ Builder: The builder.
+ """
+
+ self._unparsed_expression = unparsed_expression
+ return self
+
+ def build(self) -> UnparsedExpressionDTO:
+ """Build the unparsed expression.
+
+ Returns:
+ UnparsedExpressionDTO: The unparsed expression.
+ """
+
+ return
UnparsedExpressionDTO(unparsed_expression=self._unparsed_expression)
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 5a1e8abed7..402698f306 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
@@ -26,16 +26,27 @@ from gravitino.dto.rel.expressions.literal_dto import
LiteralDTO
class TestFieldReferenceDTO(unittest.TestCase):
def setUp(self):
self._field_references = [
- FieldReferenceDTO(field_name=[f"field_name_{idx}"]) for idx in
range(3)
+ FieldReferenceDTO.builder()
+ .with_field_name(field_name=[f"field_name_{idx}"])
+ .build()
+ for idx in range(3)
]
def test_field_reference_dto(self):
- dto =
FieldReferenceDTO(field_name=self._field_references[0].field_name())
+ dto = (
+ FieldReferenceDTO.builder()
+ .with_field_name(field_name=self._field_references[0].field_name())
+ .build()
+ )
self.assertListEqual(dto.field_name(),
self._field_references[0].field_name())
self.assertIs(dto.arg_type(), FunctionArg.ArgType.FIELD)
def test_equality(self):
- dto =
FieldReferenceDTO(field_name=self._field_references[0].field_name())
+ dto = (
+ FieldReferenceDTO.builder()
+ .with_field_name(field_name=self._field_references[0].field_name())
+ .build()
+ )
self.assertTrue(dto == self._field_references[0])
self.assertFalse(dto == self._field_references[1])
@@ -47,3 +58,12 @@ class TestFieldReferenceDTO(unittest.TestCase):
dto_dict = {dto: idx for idx, dto in enumerate(self._field_references)}
self.assertEqual(0, dto_dict.get(self._field_references[0]))
self.assertNotEqual(0, dto_dict.get(self._field_references[1]))
+
+ def test_builder(self):
+ dto =
FieldReferenceDTO.builder().with_field_name(["field_name"]).build()
+ self.assertIsInstance(dto, FieldReferenceDTO)
+ self.assertEqual(dto.field_name(), ["field_name"])
+
+ dto =
FieldReferenceDTO.builder().with_column_name(["field_name"]).build()
+ self.assertIsInstance(dto, FieldReferenceDTO)
+ self.assertEqual(dto.field_name(), ["field_name"])
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 5e58a383af..c29324b260 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
@@ -26,14 +26,23 @@ from gravitino.dto.rel.expressions.literal_dto import
LiteralDTO
class TestFuncExpressionDTO(unittest.TestCase):
def setUp(self) -> None:
self._func_args = [
- LiteralDTO(value="year", data_type=Types.StringType.get()),
- FieldReferenceDTO(field_name=["birthday"]),
+ LiteralDTO.builder()
+ .with_value(value="year")
+ .with_data_type(data_type=Types.StringType.get())
+ .build(),
+ FieldReferenceDTO.builder()
+ .with_field_name(field_name=["birthday"])
+ .build(),
]
self._func_expressions = [
- FuncExpressionDTO(function_name="function_without_args",
function_args=[]),
- FuncExpressionDTO(
- function_name="function_with_args",
function_args=self._func_args
- ),
+ FuncExpressionDTO.builder()
+ .with_function_name(function_name="function_without_args")
+ .with_function_args(function_args=[])
+ .build(),
+ FuncExpressionDTO.builder()
+ .with_function_name(function_name="function_with_args")
+ .with_function_args(function_args=self._func_args)
+ .build(),
]
def test_func_expression_dto(self):
@@ -46,8 +55,11 @@ class TestFuncExpressionDTO(unittest.TestCase):
def test_equality(self):
dto = self._func_expressions[1]
- dto1 = FuncExpressionDTO(
- function_name="function_with_args", function_args=self._func_args
+ dto1 = (
+ FuncExpressionDTO.builder()
+ .with_function_name(function_name="function_with_args")
+ .with_function_args(function_args=self._func_args)
+ .build()
)
self.assertTrue(dto == dto1)
self.assertFalse(dto == self._func_expressions[0])
@@ -57,3 +69,14 @@ class TestFuncExpressionDTO(unittest.TestCase):
dto_dict = {dto: idx for idx, dto in enumerate(self._func_expressions)}
self.assertEqual(0, dto_dict.get(self._func_expressions[0]))
self.assertNotEqual(0, dto_dict.get(self._func_expressions[1]))
+
+ def test_builder(self):
+ dto = (
+ FuncExpressionDTO.builder()
+ .with_function_name("function_name")
+ .with_function_args(self._func_args)
+ .build()
+ )
+ self.assertIsInstance(dto, FuncExpressionDTO)
+ self.assertEqual(dto.function_name(), "function_name")
+ self.assertListEqual(dto.args(), self._func_args)
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 a6e00e9bbc..62d1d61bd6 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
@@ -23,7 +23,12 @@ from gravitino.dto.rel.expressions.literal_dto import
LiteralDTO
class TestLiteralDTO(unittest.TestCase):
def setUp(self):
- self._literal_dto = LiteralDTO(data_type=Types.IntegerType.get(),
value="-1")
+ self._literal_dto = (
+ LiteralDTO.builder()
+ .with_data_type(data_type=Types.IntegerType.get())
+ .with_value(value="-1")
+ .build()
+ )
def test_literal_dto(self):
self.assertEqual(self._literal_dto.value(), "-1")
@@ -35,14 +40,31 @@ class TestLiteralDTO(unittest.TestCase):
def test_literal_dto_null(self):
self.assertEqual(
- LiteralDTO.NULL, LiteralDTO(data_type=Types.NullType.get(),
value="NULL")
+ LiteralDTO.NULL,
+ LiteralDTO.builder()
+ .with_data_type(data_type=Types.NullType.get())
+ .with_value(value="NULL")
+ .build(),
)
def test_literal_dto_hash(self):
- second_literal_dto: LiteralDTO = LiteralDTO(
- data_type=Types.IntegerType.get(), value="2"
+ second_literal_dto: LiteralDTO = (
+ LiteralDTO.builder()
+ .with_data_type(data_type=Types.IntegerType.get())
+ .with_value(value="2")
+ .build()
)
literal_dto_dict = {self._literal_dto: "test1", second_literal_dto:
"test2"}
self.assertEqual("test1", literal_dto_dict.get(self._literal_dto))
self.assertNotEqual("test2", literal_dto_dict.get(self._literal_dto))
+
+ def test_builder(self):
+ dto = (
+ LiteralDTO.Builder()
+ .with_value("-1")
+ .with_data_type(Types.IntegerType.get())
+ .build()
+ )
+ self.assertIsInstance(dto, LiteralDTO)
+ self.assertTrue(dto == self._literal_dto)
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 331c5c5f77..fdae2a9b64 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
@@ -25,7 +25,9 @@ from gravitino.dto.rel.expressions.unparsed_expression_dto
import UnparsedExpres
class TestUnparsedExpressionDTO(unittest.TestCase):
def setUp(self) -> None:
self._dtos = [
-
UnparsedExpressionDTO(unparsed_expression=f"unparsed_expression_{idx}")
+ UnparsedExpressionDTO.builder()
+
.with_unparsed_expression(unparsed_expression=f"unparsed_expression_{idx}")
+ .build()
for idx in range(3)
]
@@ -41,9 +43,15 @@ class TestUnparsedExpressionDTO(unittest.TestCase):
def test_equality(self):
dto = self._dtos[0]
- similar_dto =
UnparsedExpressionDTO(unparsed_expression="unparsed_expression_0")
- another_dto = UnparsedExpressionDTO(
- unparsed_expression="another_unparsed_expression"
+ similar_dto = (
+ UnparsedExpressionDTO.builder()
+
.with_unparsed_expression(unparsed_expression="unparsed_expression_0")
+ .build()
+ )
+ another_dto = (
+ UnparsedExpressionDTO.builder()
+
.with_unparsed_expression(unparsed_expression="another_unparsed_expression")
+ .build()
)
self.assertTrue(dto == similar_dto)