2020from abc import ABC , abstractmethod
2121from collections .abc import Callable , Iterable , Sequence
2222from functools import cached_property
23- from typing import Any
23+ from typing import Annotated , Any , TypeAlias
2424from typing import Literal as TypingLiteral
2525
26- from pydantic import ConfigDict , Field , model_validator
26+ from pydantic import ConfigDict , Discriminator , Field , Tag , model_validator
2727from pydantic_core .core_schema import ValidatorFunctionWrapHandler
2828
2929from pyiceberg .expressions .literals import AboveMax , BelowMin , Literal , literal
@@ -290,16 +290,42 @@ def as_bound(self) -> type[BoundReference]:
290290 return BoundReference
291291
292292
293+ Predicates : TypeAlias = Annotated [
294+ Annotated ["IsNull" , Tag ("is-null" )]
295+ | Annotated ["NotNull" , Tag ("not-null" )]
296+ | Annotated ["IsNaN" , Tag ("is-nan" )]
297+ | Annotated ["NotNaN" , Tag ("not-nan" )]
298+ | Annotated ["EqualTo" , Tag ("eq" )]
299+ | Annotated ["NotEqualTo" , Tag ("not-eq" )]
300+ | Annotated ["LessThan" , Tag ("lt" )]
301+ | Annotated ["LessThanOrEqual" , Tag ("lt-eq" )]
302+ | Annotated ["GreaterThan" , Tag ("gt" )]
303+ | Annotated ["GreaterThanOrEqual" , Tag ("gt-eq" )]
304+ | Annotated ["StartsWith" , Tag ("starts-with" )]
305+ | Annotated ["NotStartsWith" , Tag ("not-starts-with" )]
306+ | Annotated ["In" , Tag ("in" )]
307+ | Annotated ["NotIn" , Tag ("not-in" )]
308+ | Annotated ["And" , Tag ("and" )]
309+ | Annotated ["Or" , Tag ("or" )]
310+ | Annotated ["Not" , Tag ("not" )],
311+ Discriminator ("type" ),
312+ ]
313+
314+
293315class And (BooleanExpression ):
294316 """AND operation expression - logical conjunction."""
295317
296318 model_config = ConfigDict (arbitrary_types_allowed = True )
297319
298320 type : TypingLiteral ["and" ] = Field (default = "and" , alias = "type" )
299- left : BooleanExpression
300- right : BooleanExpression
321+ left : Predicates
322+ right : Predicates
301323
302- def __new__ (cls , left : BooleanExpression , right : BooleanExpression , * rest : BooleanExpression ) -> BooleanExpression :
324+ def __init__ (self , left : BooleanExpression , right : BooleanExpression , * rest : BooleanExpression , ** _ : Any ) -> None :
325+ if isinstance (self , And ) and not hasattr (self , "left" ) and not hasattr (self , "right" ):
326+ super ().__init__ (left = left , right = right )
327+
328+ def __new__ (cls , left : BooleanExpression , right : BooleanExpression , * rest : BooleanExpression , ** _ : Any ) -> BooleanExpression :
303329 if rest :
304330 return _build_balanced_tree (And , (left , right , * rest ))
305331 if left is AlwaysFalse () or right is AlwaysFalse ():
@@ -311,10 +337,6 @@ def __new__(cls, left: BooleanExpression, right: BooleanExpression, *rest: Boole
311337 else :
312338 return super ().__new__ (cls )
313339
314- def __init__ (self , left : BooleanExpression , right : BooleanExpression , * rest : BooleanExpression ) -> None :
315- if isinstance (self , And ) and not hasattr (self , "left" ) and not hasattr (self , "right" ):
316- super ().__init__ (left = left , right = right )
317-
318340 def __eq__ (self , other : Any ) -> bool :
319341 """Return the equality of two instances of the And class."""
320342 return self .left == other .left and self .right == other .right if isinstance (other , And ) else False
@@ -343,8 +365,8 @@ class Or(BooleanExpression):
343365 model_config = ConfigDict (arbitrary_types_allowed = True )
344366
345367 type : TypingLiteral ["or" ] = Field (default = "or" , alias = "type" )
346- left : BooleanExpression
347- right : BooleanExpression
368+ left : Predicates
369+ right : Predicates
348370
349371 def __init__ (self , left : BooleanExpression , right : BooleanExpression , * rest : BooleanExpression ) -> None :
350372 if isinstance (self , Or ) and not hasattr (self , "left" ) and not hasattr (self , "right" ):
@@ -390,7 +412,7 @@ class Not(BooleanExpression):
390412 model_config = ConfigDict (arbitrary_types_allowed = True )
391413
392414 type : TypingLiteral ["not" ] = Field (default = "not" )
393- child : BooleanExpression = Field ()
415+ child : Predicates = Field ()
394416
395417 def __init__ (self , child : BooleanExpression , ** _ : Any ) -> None :
396418 super ().__init__ (child = child )
@@ -402,8 +424,8 @@ def __new__(cls, child: BooleanExpression, **_: Any) -> BooleanExpression:
402424 return AlwaysTrue ()
403425 elif isinstance (child , Not ):
404426 return child .child
405- obj = super (). __new__ ( cls )
406- return obj
427+ else :
428+ return super (). __new__ ( cls )
407429
408430 def __str__ (self ) -> str :
409431 """Return the string representation of the Not class."""
0 commit comments