Skip to content

Commit f3e740f

Browse files
committed
Make And expression JSON serializable using Pydantic
1 parent 40521c8 commit f3e740f

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

pyiceberg/expressions/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@
3232
Union,
3333
)
3434

35+
from pydantic import Field
36+
3537
from pyiceberg.expressions.literals import (
3638
AboveMax,
3739
BelowMin,
3840
Literal,
3941
literal,
4042
)
4143
from pyiceberg.schema import Accessor, Schema
42-
from pyiceberg.typedef import L, StructProtocol
44+
from pyiceberg.typedef import IcebergBaseModel, L, StructProtocol
4345
from pyiceberg.types import DoubleType, FloatType, NestedField
4446
from pyiceberg.utils.singleton import Singleton
4547

@@ -247,9 +249,10 @@ def as_bound(self) -> Type[BoundReference[L]]:
247249
return BoundReference[L]
248250

249251

250-
class And(BooleanExpression):
252+
class And(BooleanExpression, IcebergBaseModel):
251253
"""AND operation expression - logical conjunction."""
252254

255+
type: str = Field(default="and", alias="type")
253256
left: BooleanExpression
254257
right: BooleanExpression
255258

@@ -289,6 +292,12 @@ def __getnewargs__(self) -> Tuple[BooleanExpression, BooleanExpression]:
289292
"""Pickle the And class."""
290293
return (self.left, self.right)
291294

295+
class Config:
296+
"""Pydantic configuration for And expression serialization."""
297+
298+
arbitrary_types_allowed = True
299+
json_encoders = {BooleanExpression: lambda v: v.model_dump(by_alias=True) if isinstance(v, IcebergBaseModel) else str(v)}
300+
292301

293302
class Or(BooleanExpression):
294303
"""OR operation expression - logical disjunction."""

tests/table/test_partitioning.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import pytest
2323

24+
from pyiceberg.expressions import And, EqualTo
2425
from pyiceberg.partitioning import UNPARTITIONED_PARTITION_SPEC, PartitionField, PartitionSpec
2526
from pyiceberg.schema import Schema
2627
from pyiceberg.transforms import (
@@ -125,6 +126,13 @@ def test_serialize_partition_spec() -> None:
125126
)
126127

127128

129+
def test_serialize_and_expression() -> None:
130+
expr = And(EqualTo("foo", 1), EqualTo("bar", 2))
131+
assert expr.model_dump_json(by_alias=True) == (
132+
'{"type":"and","left":{"type":"equal_to","term":"foo","literal":1},"right":{"type":"equal_to","term":"bar","literal":2}}'
133+
)
134+
135+
128136
def test_deserialize_unpartition_spec() -> None:
129137
json_partition_spec = """{"spec-id":0,"fields":[]}"""
130138
spec = PartitionSpec.model_validate_json(json_partition_spec)

0 commit comments

Comments
 (0)