diff --git a/pyiceberg/expressions/__init__.py b/pyiceberg/expressions/__init__.py index 2adf898fea..205f3e439e 100644 --- a/pyiceberg/expressions/__init__.py +++ b/pyiceberg/expressions/__init__.py @@ -32,6 +32,8 @@ Union, ) +from pydantic import Field + from pyiceberg.expressions.literals import ( AboveMax, BelowMin, @@ -39,7 +41,7 @@ literal, ) from pyiceberg.schema import Accessor, Schema -from pyiceberg.typedef import L, StructProtocol +from pyiceberg.typedef import L, StructProtocol, IcebergRootModel from pyiceberg.types import DoubleType, FloatType, NestedField from pyiceberg.utils.singleton import Singleton @@ -362,9 +364,10 @@ def __getnewargs__(self) -> Tuple[BooleanExpression]: return (self.child,) -class AlwaysTrue(BooleanExpression, Singleton): +class AlwaysTrue(IcebergRootModel, BooleanExpression, Singleton): """TRUE expression.""" + root: str = Field(default="true") def __invert__(self) -> AlwaysFalse: """Transform the Expression into its negated version.""" return AlwaysFalse() @@ -378,9 +381,10 @@ def __repr__(self) -> str: return "AlwaysTrue()" -class AlwaysFalse(BooleanExpression, Singleton): +class AlwaysFalse(IcebergRootModel, BooleanExpression, Singleton): """FALSE expression.""" + root: str = Field(default="false") def __invert__(self) -> AlwaysTrue: """Transform the Expression into its negated version.""" return AlwaysTrue() diff --git a/tests/table/test_partitioning.py b/tests/table/test_partitioning.py index 0fe22391c0..766cc13aea 100644 --- a/tests/table/test_partitioning.py +++ b/tests/table/test_partitioning.py @@ -20,7 +20,7 @@ from uuid import UUID import pytest - +from pyiceberg.expressions import AlwaysTrue, AlwaysFalse from pyiceberg.partitioning import UNPARTITIONED_PARTITION_SPEC, PartitionField, PartitionSpec from pyiceberg.schema import Schema from pyiceberg.transforms import ( @@ -32,7 +32,7 @@ TruncateTransform, YearTransform, ) -from pyiceberg.typedef import Record +from pyiceberg.typedef import Record, IcebergBaseModel from pyiceberg.types import ( BinaryType, DateType, @@ -112,6 +112,36 @@ def test_unpartitioned() -> None: def test_serialize_unpartitioned_spec() -> None: assert UNPARTITIONED_PARTITION_SPEC.model_dump_json() == """{"spec-id":0,"fields":[]}""" +def test_always_true_serializes_to_json_true(): + expr = AlwaysTrue() + assert expr.model_dump_json() == "true" + +def test_always_false_serializes_to_json_false(): + expr = AlwaysFalse() + assert expr.model_dump_json() == "false" + +def test_serialize_partition_spec_trye() -> None: + partitioned = PartitionSpec( + PartitionField(source_id=1, field_id=1000, transform=TruncateTransform(width=19), name="str_truncate"), + PartitionField(source_id=2, field_id=1001, transform=BucketTransform(num_buckets=25), name="int_bucket"), + spec_id=3, + ) + assert ( + partitioned.model_dump_json() + == """{"spec-id":3,"fields":[{"source-id":1,"field-id":1000,"transform":"truncate[19]","name":"str_truncate"},{"source-id":2,"field-id":1001,"transform":"bucket[25]","name":"int_bucket"}]}""" + ) + +def test_serialize_partition_spec() -> None: + partitioned = PartitionSpec( + PartitionField(source_id=1, field_id=1000, transform=TruncateTransform(width=19), name="str_truncate"), + PartitionField(source_id=2, field_id=1001, transform=BucketTransform(num_buckets=25), name="int_bucket"), + spec_id=3, + ) + assert ( + partitioned.model_dump_json() + == """{"spec-id":3,"fields":[{"source-id":1,"field-id":1000,"transform":"truncate[19]","name":"str_truncate"},{"source-id":2,"field-id":1001,"transform":"bucket[25]","name":"int_bucket"}]}""" + ) + def test_serialize_partition_spec() -> None: partitioned = PartitionSpec(