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)

Reply via email to