1919//! Predicate expressions are used to filter data, and evaluates to a boolean value. For example,
2020//! `a > 10` is a predicate expression, and it evaluates to `true` if `a` is greater than `10`,
2121
22- use crate :: expr:: { BoundReference , PredicateOperator , Reference } ;
23- use crate :: spec:: Datum ;
22+ use std:: fmt:: { Debug , Display , Formatter } ;
23+ use std:: mem:: MaybeUninit ;
24+ use std:: ops:: Not ;
25+
26+ use fnv:: FnvHashSet ;
2427use itertools:: Itertools ;
25- use std :: collections :: HashSet ;
28+
2629use crate :: error:: Result ;
2730use crate :: expr:: { Bind , BoundReference , PredicateOperator , Reference } ;
2831use crate :: spec:: { Datum , SchemaRef } ;
2932use crate :: { Error , ErrorKind } ;
30- use fnv:: FnvHashSet ;
31-
32- use std:: fmt:: { Debug , Display , Formatter } ;
33- use std:: mem:: MaybeUninit ;
34- use std:: ops:: Not ;
3533
3634/// Logical expression, such as `AND`, `OR`, `NOT`.
3735#[ derive( PartialEq ) ]
@@ -490,7 +488,11 @@ impl Predicate {
490488impl Not for Predicate {
491489 type Output = Predicate ;
492490
493- /// Create a predicate which is the reverse of this predicate. For example: `NOT (a > 10)`
491+ /// Create a predicate which is the reverse of this predicate. For example: `NOT (a > 10)`.
492+ ///
493+ /// This is different from [`Predicate::negate()`] since it doesn't rewrite expression, but
494+ /// just adds a `NOT` operator.
495+ ///
494496 /// # Example
495497 ///
496498 ///```rust
@@ -530,12 +532,46 @@ pub enum BoundPredicate {
530532 Set ( SetExpression < BoundReference > ) ,
531533}
532534
535+ impl Display for BoundPredicate {
536+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
537+ match self {
538+ BoundPredicate :: AlwaysTrue => {
539+ write ! ( f, "True" )
540+ }
541+ BoundPredicate :: AlwaysFalse => {
542+ write ! ( f, "False" )
543+ }
544+ BoundPredicate :: And ( expr) => {
545+ write ! ( f, "({}) AND ({})" , expr. inputs( ) [ 0 ] , expr. inputs( ) [ 1 ] )
546+ }
547+ BoundPredicate :: Or ( expr) => {
548+ write ! ( f, "({}) OR ({})" , expr. inputs( ) [ 0 ] , expr. inputs( ) [ 1 ] )
549+ }
550+ BoundPredicate :: Not ( expr) => {
551+ write ! ( f, "NOT ({})" , expr. inputs( ) [ 0 ] )
552+ }
553+ BoundPredicate :: Unary ( expr) => {
554+ write ! ( f, "{}" , expr)
555+ }
556+ BoundPredicate :: Binary ( expr) => {
557+ write ! ( f, "{}" , expr)
558+ }
559+ BoundPredicate :: Set ( expr) => {
560+ write ! ( f, "{}" , expr)
561+ }
562+ }
563+ }
564+ }
565+
533566#[ cfg( test) ]
534567mod tests {
568+ use std:: ops:: Not ;
569+ use std:: sync:: Arc ;
570+
571+ use crate :: expr:: Bind ;
535572 use crate :: expr:: Reference ;
536573 use crate :: spec:: Datum ;
537- use std:: collections:: HashSet ;
538- use std:: ops:: Not ;
574+ use crate :: spec:: { NestedField , PrimitiveType , Schema , SchemaRef , Type } ;
539575
540576 #[ test]
541577 fn test_predicate_negate_and ( ) {
@@ -604,20 +640,15 @@ mod tests {
604640
605641 #[ test]
606642 fn test_predicate_negate_set ( ) {
607- let expression = Reference :: new ( "a" ) . is_in ( HashSet :: from ( [ Datum :: long ( 5 ) , Datum :: long ( 6 ) ] ) ) ;
643+ let expression = Reference :: new ( "a" ) . is_in ( [ Datum :: long ( 5 ) , Datum :: long ( 6 ) ] ) ;
608644
609- let expected =
610- Reference :: new ( "a" ) . is_not_in ( HashSet :: from ( [ Datum :: long ( 5 ) , Datum :: long ( 6 ) ] ) ) ;
645+ let expected = Reference :: new ( "a" ) . is_not_in ( [ Datum :: long ( 5 ) , Datum :: long ( 6 ) ] ) ;
611646
612647 let result = expression. negate ( ) ;
613648
614649 assert_eq ! ( result, expected) ;
615650 }
616651
617- use crate :: expr:: { Bind , Reference } ;
618- use crate :: spec:: { NestedField , PrimitiveType , Schema , SchemaRef , Type } ;
619- use std:: sync:: Arc ;
620-
621652 fn table_schema_simple ( ) -> SchemaRef {
622653 Arc :: new (
623654 Schema :: builder ( )
@@ -640,4 +671,208 @@ mod tests {
640671 let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
641672 assert_eq ! ( & format!( "{bound_expr}" ) , "foo IS NULL" ) ;
642673 }
674+
675+ #[ test]
676+ fn test_bind_is_null_required ( ) {
677+ let schema = table_schema_simple ( ) ;
678+ let expr = Reference :: new ( "bar" ) . is_null ( ) ;
679+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
680+ assert_eq ! ( & format!( "{bound_expr}" ) , "False" ) ;
681+ }
682+
683+ #[ test]
684+ fn test_bind_is_not_null ( ) {
685+ let schema = table_schema_simple ( ) ;
686+ let expr = Reference :: new ( "foo" ) . is_not_null ( ) ;
687+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
688+ assert_eq ! ( & format!( "{bound_expr}" ) , "foo IS NOT NULL" ) ;
689+ }
690+
691+ #[ test]
692+ fn test_bind_is_not_null_required ( ) {
693+ let schema = table_schema_simple ( ) ;
694+ let expr = Reference :: new ( "bar" ) . is_not_null ( ) ;
695+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
696+ assert_eq ! ( & format!( "{bound_expr}" ) , "True" ) ;
697+ }
698+
699+ #[ test]
700+ fn test_bind_less_than ( ) {
701+ let schema = table_schema_simple ( ) ;
702+ let expr = Reference :: new ( "bar" ) . less_than ( Datum :: int ( 10 ) ) ;
703+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
704+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar < 10" ) ;
705+ }
706+
707+ #[ test]
708+ fn test_bind_less_than_wrong_type ( ) {
709+ let schema = table_schema_simple ( ) ;
710+ let expr = Reference :: new ( "bar" ) . less_than ( Datum :: string ( "abcd" ) ) ;
711+ let bound_expr = expr. bind ( schema, true ) ;
712+ assert ! ( bound_expr. is_err( ) ) ;
713+ }
714+
715+ #[ test]
716+ fn test_bind_greater_than_or_eq ( ) {
717+ let schema = table_schema_simple ( ) ;
718+ let expr = Reference :: new ( "bar" ) . greater_than_or_equal_to ( Datum :: int ( 10 ) ) ;
719+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
720+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar >= 10" ) ;
721+ }
722+
723+ #[ test]
724+ fn test_bind_greater_than_or_eq_wrong_type ( ) {
725+ let schema = table_schema_simple ( ) ;
726+ let expr = Reference :: new ( "bar" ) . greater_than_or_equal_to ( Datum :: string ( "abcd" ) ) ;
727+ let bound_expr = expr. bind ( schema, true ) ;
728+ assert ! ( bound_expr. is_err( ) ) ;
729+ }
730+
731+ #[ test]
732+ fn test_bind_in ( ) {
733+ let schema = table_schema_simple ( ) ;
734+ let expr = Reference :: new ( "bar" ) . is_in ( [ Datum :: int ( 10 ) , Datum :: int ( 20 ) ] ) ;
735+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
736+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar IN (20, 10)" ) ;
737+ }
738+
739+ #[ test]
740+ fn test_bind_in_empty ( ) {
741+ let schema = table_schema_simple ( ) ;
742+ let expr = Reference :: new ( "bar" ) . is_in ( vec ! [ ] ) ;
743+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
744+ assert_eq ! ( & format!( "{bound_expr}" ) , "False" ) ;
745+ }
746+
747+ #[ test]
748+ fn test_bind_in_one_literal ( ) {
749+ let schema = table_schema_simple ( ) ;
750+ let expr = Reference :: new ( "bar" ) . is_in ( vec ! [ Datum :: int( 10 ) ] ) ;
751+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
752+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar = 10" ) ;
753+ }
754+
755+ #[ test]
756+ fn test_bind_in_wrong_type ( ) {
757+ let schema = table_schema_simple ( ) ;
758+ let expr = Reference :: new ( "bar" ) . is_in ( vec ! [ Datum :: int( 10 ) , Datum :: string( "abcd" ) ] ) ;
759+ let bound_expr = expr. bind ( schema, true ) ;
760+ assert ! ( bound_expr. is_err( ) ) ;
761+ }
762+
763+ #[ test]
764+ fn test_bind_not_in ( ) {
765+ let schema = table_schema_simple ( ) ;
766+ let expr = Reference :: new ( "bar" ) . is_not_in ( [ Datum :: int ( 10 ) , Datum :: int ( 20 ) ] ) ;
767+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
768+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar NOT IN (20, 10)" ) ;
769+ }
770+
771+ #[ test]
772+ fn test_bind_not_in_empty ( ) {
773+ let schema = table_schema_simple ( ) ;
774+ let expr = Reference :: new ( "bar" ) . is_not_in ( vec ! [ ] ) ;
775+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
776+ assert_eq ! ( & format!( "{bound_expr}" ) , "True" ) ;
777+ }
778+
779+ #[ test]
780+ fn test_bind_not_in_one_literal ( ) {
781+ let schema = table_schema_simple ( ) ;
782+ let expr = Reference :: new ( "bar" ) . is_not_in ( vec ! [ Datum :: int( 10 ) ] ) ;
783+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
784+ assert_eq ! ( & format!( "{bound_expr}" ) , "bar != 10" ) ;
785+ }
786+
787+ #[ test]
788+ fn test_bind_not_in_wrong_type ( ) {
789+ let schema = table_schema_simple ( ) ;
790+ let expr = Reference :: new ( "bar" ) . is_not_in ( [ Datum :: int ( 10 ) , Datum :: string ( "abcd" ) ] ) ;
791+ let bound_expr = expr. bind ( schema, true ) ;
792+ assert ! ( bound_expr. is_err( ) ) ;
793+ }
794+
795+ #[ test]
796+ fn test_bind_and ( ) {
797+ let schema = table_schema_simple ( ) ;
798+ let expr = Reference :: new ( "bar" )
799+ . less_than ( Datum :: int ( 10 ) )
800+ . and ( Reference :: new ( "foo" ) . is_null ( ) ) ;
801+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
802+ assert_eq ! ( & format!( "{bound_expr}" ) , "(bar < 10) AND (foo IS NULL)" ) ;
803+ }
804+
805+ #[ test]
806+ fn test_bind_and_always_false ( ) {
807+ let schema = table_schema_simple ( ) ;
808+ let expr = Reference :: new ( "foo" )
809+ . less_than ( Datum :: string ( "abcd" ) )
810+ . and ( Reference :: new ( "bar" ) . is_null ( ) ) ;
811+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
812+ assert_eq ! ( & format!( "{bound_expr}" ) , "False" ) ;
813+ }
814+
815+ #[ test]
816+ fn test_bind_and_always_true ( ) {
817+ let schema = table_schema_simple ( ) ;
818+ let expr = Reference :: new ( "foo" )
819+ . less_than ( Datum :: string ( "abcd" ) )
820+ . and ( Reference :: new ( "bar" ) . is_not_null ( ) ) ;
821+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
822+ assert_eq ! ( & format!( "{bound_expr}" ) , r#"foo < "abcd""# ) ;
823+ }
824+
825+ #[ test]
826+ fn test_bind_or ( ) {
827+ let schema = table_schema_simple ( ) ;
828+ let expr = Reference :: new ( "bar" )
829+ . less_than ( Datum :: int ( 10 ) )
830+ . or ( Reference :: new ( "foo" ) . is_null ( ) ) ;
831+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
832+ assert_eq ! ( & format!( "{bound_expr}" ) , "(bar < 10) OR (foo IS NULL)" ) ;
833+ }
834+
835+ #[ test]
836+ fn test_bind_or_always_true ( ) {
837+ let schema = table_schema_simple ( ) ;
838+ let expr = Reference :: new ( "foo" )
839+ . less_than ( Datum :: string ( "abcd" ) )
840+ . or ( Reference :: new ( "bar" ) . is_not_null ( ) ) ;
841+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
842+ assert_eq ! ( & format!( "{bound_expr}" ) , "True" ) ;
843+ }
844+
845+ #[ test]
846+ fn test_bind_or_always_false ( ) {
847+ let schema = table_schema_simple ( ) ;
848+ let expr = Reference :: new ( "foo" )
849+ . less_than ( Datum :: string ( "abcd" ) )
850+ . or ( Reference :: new ( "bar" ) . is_null ( ) ) ;
851+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
852+ assert_eq ! ( & format!( "{bound_expr}" ) , r#"foo < "abcd""# ) ;
853+ }
854+
855+ #[ test]
856+ fn test_bind_not ( ) {
857+ let schema = table_schema_simple ( ) ;
858+ let expr = !Reference :: new ( "bar" ) . less_than ( Datum :: int ( 10 ) ) ;
859+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
860+ assert_eq ! ( & format!( "{bound_expr}" ) , "NOT (bar < 10)" ) ;
861+ }
862+
863+ #[ test]
864+ fn test_bind_not_always_true ( ) {
865+ let schema = table_schema_simple ( ) ;
866+ let expr = !Reference :: new ( "bar" ) . is_not_null ( ) ;
867+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
868+ assert_eq ! ( & format!( "{bound_expr}" ) , "False" ) ;
869+ }
870+
871+ #[ test]
872+ fn test_bind_not_always_false ( ) {
873+ let schema = table_schema_simple ( ) ;
874+ let expr = !Reference :: new ( "bar" ) . is_null ( ) ;
875+ let bound_expr = expr. bind ( schema, true ) . unwrap ( ) ;
876+ assert_eq ! ( & format!( "{bound_expr}" ) , r#"True"# ) ;
877+ }
643878}
0 commit comments