This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git


The following commit(s) were added to refs/heads/main by this push:
     new 9ce7619c Feat/json serialize or expression (#2565)
9ce7619c is described below

commit 9ce7619cc8f1fe2e184f0b3d384f9a70193f19f6
Author: Jaime Fernández <[email protected]>
AuthorDate: Wed Oct 22 17:44:29 2025 +0200

    Feat/json serialize or expression (#2565)
    
    <!--
    Thanks for opening a pull request!
    -->
    
    <!-- In the case this PR will resolve an issue, please replace
    ${GITHUB_ISSUE_ID} below with the actual Github issue id. -->
    Closes https://github.com/apache/iceberg-python/issues/2519
    
    # Rationale for this change
    
    ## Are these changes tested?
    yes
    
    ## Are there any user-facing changes?
    
    <!-- In the case of user-facing changes, please add the changelog label.
    -->
---
 pyiceberg/expressions/__init__.py     | 17 +++++++++++++----
 tests/expressions/test_expressions.py | 11 +++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/pyiceberg/expressions/__init__.py 
b/pyiceberg/expressions/__init__.py
index 16210bae..339fd9cd 100644
--- a/pyiceberg/expressions/__init__.py
+++ b/pyiceberg/expressions/__init__.py
@@ -33,7 +33,7 @@ from typing import (
 )
 from typing import Literal as TypingLiteral
 
-from pydantic import Field
+from pydantic import ConfigDict, Field
 
 from pyiceberg.expressions.literals import (
     AboveMax,
@@ -302,12 +302,19 @@ class And(BooleanExpression):
         return (self.left, self.right)
 
 
-class Or(BooleanExpression):
+class Or(IcebergBaseModel, BooleanExpression):
     """OR operation expression - logical disjunction."""
 
+    model_config = ConfigDict(arbitrary_types_allowed=True)
+
+    type: TypingLiteral["or"] = Field(default="or", alias="type")
     left: BooleanExpression
     right: BooleanExpression
 
+    def __init__(self, left: BooleanExpression, right: BooleanExpression, 
*rest: BooleanExpression) -> None:
+        if isinstance(self, Or) and not hasattr(self, "left") and not 
hasattr(self, "right"):
+            super().__init__(left=left, right=right)
+
     def __new__(cls, left: BooleanExpression, right: BooleanExpression, *rest: 
BooleanExpression) -> BooleanExpression:  # type: ignore
         if rest:
             return _build_balanced_tree(Or, (left, right, *rest))
@@ -319,10 +326,12 @@ class Or(BooleanExpression):
             return left
         else:
             obj = super().__new__(cls)
-            obj.left = left
-            obj.right = right
             return obj
 
+    def __str__(self) -> str:
+        """Return the string representation of the Or class."""
+        return f"{str(self.__class__.__name__)}(left={repr(self.left)}, 
right={repr(self.right)})"
+
     def __eq__(self, other: Any) -> bool:
         """Return the equality of two instances of the Or class."""
         return self.left == other.left and self.right == other.right if 
isinstance(other, Or) else False
diff --git a/tests/expressions/test_expressions.py 
b/tests/expressions/test_expressions.py
index 63673fda..2a57fb66 100644
--- a/tests/expressions/test_expressions.py
+++ b/tests/expressions/test_expressions.py
@@ -714,6 +714,17 @@ def test_or() -> None:
         null | "abc"  # type: ignore
 
 
+def test_or_serialization() -> None:
+    left = EqualTo("a", 10)
+    right = EqualTo("b", 20)
+    or_ = Or(left, right)
+
+    assert (
+        or_.model_dump_json()
+        == 
'{"type":"or","left":{"term":"a","type":"eq","value":10},"right":{"term":"b","type":"eq","value":20}}'
+    )
+
+
 def test_not() -> None:
     null = IsNull(Reference("a"))
     not_ = Not(null)

Reply via email to