Skip to content

Commit 17a93d2

Browse files
committed
feat: make Or json serializable via IcebergBaseModel
1 parent 9bff326 commit 17a93d2

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

pyiceberg/expressions/__init__.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from __future__ import annotations
1919

20+
import typing
2021
from abc import ABC, abstractmethod
2122
from functools import cached_property
2223
from typing import (
@@ -35,6 +36,8 @@
3536

3637
from pydantic import Field
3738

39+
from pydantic import ConfigDict, Field, field_serializer
40+
3841
from pyiceberg.expressions.literals import (
3942
AboveMax,
4043
BelowMin,
@@ -302,12 +305,18 @@ def __getnewargs__(self) -> Tuple[BooleanExpression, BooleanExpression]:
302305
return (self.left, self.right)
303306

304307

305-
class Or(BooleanExpression):
308+
class Or(IcebergBaseModel, BooleanExpression):
306309
"""OR operation expression - logical disjunction."""
307310

311+
model_config = ConfigDict(arbitrary_types_allowed=True)
312+
313+
type: str = Field(default="or", repr=False)
308314
left: BooleanExpression
309315
right: BooleanExpression
310316

317+
def __init__(self, left: typing.Union[BooleanExpression, Or], right: typing.Union[BooleanExpression, Or], *rest: Any):
318+
return super().__init__(left=left, right=right)
319+
311320
def __new__(cls, left: BooleanExpression, right: BooleanExpression, *rest: BooleanExpression) -> BooleanExpression: # type: ignore
312321
if rest:
313322
return _build_balanced_tree(Or, (left, right, *rest))
@@ -319,10 +328,24 @@ def __new__(cls, left: BooleanExpression, right: BooleanExpression, *rest: Boole
319328
return left
320329
else:
321330
obj = super().__new__(cls)
322-
obj.left = left
323-
obj.right = right
324331
return obj
325332

333+
@field_serializer("left")
334+
def ser_left(self, left: BooleanExpression) -> str:
335+
if isinstance(left, IcebergRootModel):
336+
return left.root
337+
return str(left)
338+
339+
@field_serializer("right")
340+
def ser_right(self, right: BooleanExpression) -> str:
341+
if isinstance(right, IcebergRootModel):
342+
return right.root
343+
return str(right)
344+
345+
def __str__(self) -> str:
346+
"""Return the string representation of the Or class."""
347+
return f"{str(self.__class__.__name__)}(left={repr(self.left)}, right={repr(self.right)})"
348+
326349
def __eq__(self, other: Any) -> bool:
327350
"""Return the equality of two instances of the Or class."""
328351
return self.left == other.left and self.right == other.right if isinstance(other, Or) else False

tests/expressions/test_expressions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ def test_or() -> None:
702702
# Some syntactic sugar
703703
assert or_ == null | nan
704704

705+
assert (
706+
or_.model_dump_json()
707+
== '{"type":"or","left":"IsNull(term=Reference(name=\'a\'))","right":"IsNaN(term=Reference(name=\'b\'))"}'
708+
)
705709
assert str(or_) == f"Or(left={str(null)}, right={str(nan)})"
706710
assert repr(or_) == f"Or(left={repr(null)}, right={repr(nan)})"
707711
assert or_ == eval(repr(or_))

0 commit comments

Comments
 (0)