Skip to main content

iceberg_unofficial/expr/
predicate.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! This module contains predicate expressions.
19//! Predicate expressions are used to filter data, and evaluates to a boolean value. For example,
20//! `a > 10` is a predicate expression, and it evaluates to `true` if `a` is greater than `10`,
21
22use std::fmt::{Debug, Display, Formatter};
23use std::ops::Not;
24
25use array_init::array_init;
26use fnv::FnvHashSet;
27use itertools::Itertools;
28use serde::{Deserialize, Serialize};
29
30use crate::error::Result;
31use crate::expr::visitors::bound_predicate_visitor::visit as visit_bound;
32use crate::expr::visitors::predicate_visitor::visit;
33use crate::expr::visitors::rewrite_not::RewriteNotVisitor;
34use crate::expr::{Bind, BoundReference, PredicateOperator, Reference};
35use crate::spec::{Datum, PrimitiveLiteral, SchemaRef};
36use crate::{Error, ErrorKind};
37
38/// Logical expression, such as `AND`, `OR`, `NOT`.
39#[derive(PartialEq, Clone)]
40pub struct LogicalExpression<T, const N: usize> {
41    inputs: [Box<T>; N],
42}
43
44impl<T: Serialize, const N: usize> Serialize for LogicalExpression<T, N> {
45    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
46    where S: serde::Serializer {
47        self.inputs.serialize(serializer)
48    }
49}
50
51impl<'de, T: Deserialize<'de>, const N: usize> Deserialize<'de> for LogicalExpression<T, N> {
52    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
53    where D: serde::Deserializer<'de> {
54        let inputs = Vec::<Box<T>>::deserialize(deserializer)?;
55        Ok(LogicalExpression::new(
56            array_init::from_iter(inputs.into_iter()).ok_or_else(|| {
57                serde::de::Error::custom(format!("Failed to deserialize LogicalExpression: the len of inputs is not match with the len of LogicalExpression {}",N))
58            })?,
59        ))
60    }
61}
62
63impl<T: Debug, const N: usize> Debug for LogicalExpression<T, N> {
64    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
65        f.debug_struct("LogicalExpression")
66            .field("inputs", &self.inputs)
67            .finish()
68    }
69}
70
71impl<T, const N: usize> LogicalExpression<T, N> {
72    fn new(inputs: [Box<T>; N]) -> Self {
73        Self { inputs }
74    }
75
76    /// Return inputs of this logical expression.
77    pub fn inputs(&self) -> [&T; N] {
78        let mut ret: [&T; N] = [self.inputs[0].as_ref(); N];
79        for (i, item) in ret.iter_mut().enumerate() {
80            *item = &self.inputs[i];
81        }
82        ret
83    }
84}
85
86impl<T: Bind, const N: usize> Bind for LogicalExpression<T, N>
87where T::Bound: Sized
88{
89    type Bound = LogicalExpression<T::Bound, N>;
90
91    fn bind(&self, schema: SchemaRef, case_sensitive: bool) -> Result<Self::Bound> {
92        let mut outputs: [Option<Box<T::Bound>>; N] = array_init(|_| None);
93        for (i, input) in self.inputs.iter().enumerate() {
94            outputs[i] = Some(Box::new(input.bind(schema.clone(), case_sensitive)?));
95        }
96
97        // It's safe to use `unwrap` here since they are all `Some`.
98        let bound_inputs = array_init::from_iter(outputs.into_iter().map(Option::unwrap)).unwrap();
99        Ok(LogicalExpression::new(bound_inputs))
100    }
101}
102
103/// Unary predicate, for example, `a IS NULL`.
104#[derive(PartialEq, Clone, Serialize, Deserialize)]
105pub struct UnaryExpression<T> {
106    /// Operator of this predicate, must be single operand operator.
107    op: PredicateOperator,
108    /// Term of this predicate, for example, `a` in `a IS NULL`.
109    #[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
110    term: T,
111}
112
113impl<T: Debug> Debug for UnaryExpression<T> {
114    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115        f.debug_struct("UnaryExpression")
116            .field("op", &self.op)
117            .field("term", &self.term)
118            .finish()
119    }
120}
121
122impl<T: Display> Display for UnaryExpression<T> {
123    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
124        write!(f, "{} {}", self.term, self.op)
125    }
126}
127
128impl<T: Bind> Bind for UnaryExpression<T> {
129    type Bound = UnaryExpression<T::Bound>;
130
131    fn bind(&self, schema: SchemaRef, case_sensitive: bool) -> Result<Self::Bound> {
132        let bound_term = self.term.bind(schema, case_sensitive)?;
133        Ok(UnaryExpression::new(self.op, bound_term))
134    }
135}
136
137impl<T> UnaryExpression<T> {
138    /// Creates a unary expression with the given operator and term.
139    ///
140    /// # Example
141    ///
142    /// ```rust
143    /// use iceberg_unofficial::expr::{PredicateOperator, Reference, UnaryExpression};
144    ///
145    /// UnaryExpression::new(PredicateOperator::IsNull, Reference::new("c"));
146    /// ```
147    pub fn new(op: PredicateOperator, term: T) -> Self {
148        debug_assert!(op.is_unary());
149        Self { op, term }
150    }
151
152    /// Return the operator of this predicate.
153    pub fn op(&self) -> PredicateOperator {
154        self.op
155    }
156
157    /// Return the term of this predicate.
158    pub fn term(&self) -> &T {
159        &self.term
160    }
161}
162
163/// Binary predicate, for example, `a > 10`.
164#[derive(PartialEq, Clone, Serialize, Deserialize)]
165pub struct BinaryExpression<T> {
166    /// Operator of this predicate, must be binary operator, such as `=`, `>`, `<`, etc.
167    op: PredicateOperator,
168    /// Term of this predicate, for example, `a` in `a > 10`.
169    #[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
170    term: T,
171    /// Literal of this predicate, for example, `10` in `a > 10`.
172    literal: Datum,
173}
174
175impl<T: Debug> Debug for BinaryExpression<T> {
176    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
177        f.debug_struct("BinaryExpression")
178            .field("op", &self.op)
179            .field("term", &self.term)
180            .field("literal", &self.literal)
181            .finish()
182    }
183}
184
185impl<T> BinaryExpression<T> {
186    /// Creates a binary expression with the given operator, term and literal.
187    ///
188    /// # Example
189    ///
190    /// ```rust
191    /// use iceberg_unofficial::expr::{BinaryExpression, PredicateOperator, Reference};
192    /// use iceberg_unofficial::spec::Datum;
193    ///
194    /// BinaryExpression::new(
195    ///     PredicateOperator::LessThanOrEq,
196    ///     Reference::new("a"),
197    ///     Datum::int(10),
198    /// );
199    /// ```
200    pub fn new(op: PredicateOperator, term: T, literal: Datum) -> Self {
201        debug_assert!(op.is_binary());
202        Self { op, term, literal }
203    }
204
205    /// Return the operator used by this predicate expression.
206    pub fn op(&self) -> PredicateOperator {
207        self.op
208    }
209
210    /// Return the literal of this predicate.
211    pub fn literal(&self) -> &Datum {
212        &self.literal
213    }
214
215    /// Return the term of this predicate.
216    pub fn term(&self) -> &T {
217        &self.term
218    }
219}
220
221impl<T: Display> Display for BinaryExpression<T> {
222    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223        write!(f, "{} {} {}", self.term, self.op, self.literal)
224    }
225}
226
227impl<T: Bind> Bind for BinaryExpression<T> {
228    type Bound = BinaryExpression<T::Bound>;
229
230    fn bind(&self, schema: SchemaRef, case_sensitive: bool) -> Result<Self::Bound> {
231        let bound_term = self.term.bind(schema.clone(), case_sensitive)?;
232        Ok(BinaryExpression::new(
233            self.op,
234            bound_term,
235            self.literal.clone(),
236        ))
237    }
238}
239
240/// Set predicates, for example, `a in (1, 2, 3)`.
241#[derive(PartialEq, Clone, Serialize, Deserialize)]
242pub struct SetExpression<T> {
243    /// Operator of this predicate, must be set operator, such as `IN`, `NOT IN`, etc.
244    op: PredicateOperator,
245    /// Term of this predicate, for example, `a` in `a in (1, 2, 3)`.
246    term: T,
247    /// Literals of this predicate, for example, `(1, 2, 3)` in `a in (1, 2, 3)`.
248    literals: FnvHashSet<Datum>,
249}
250
251impl<T: Debug> Debug for SetExpression<T> {
252    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
253        f.debug_struct("SetExpression")
254            .field("op", &self.op)
255            .field("term", &self.term)
256            .field("literal", &self.literals)
257            .finish()
258    }
259}
260
261impl<T> SetExpression<T> {
262    pub(crate) fn new(op: PredicateOperator, term: T, literals: FnvHashSet<Datum>) -> Self {
263        debug_assert!(op.is_set());
264        Self { op, term, literals }
265    }
266
267    /// Return the operator of this predicate.
268    pub fn op(&self) -> PredicateOperator {
269        self.op
270    }
271
272    /// Return the hash set of values compared against the term in this expression.
273    pub fn literals(&self) -> &FnvHashSet<Datum> {
274        &self.literals
275    }
276
277    /// Return the term of this predicate.
278    pub fn term(&self) -> &T {
279        &self.term
280    }
281}
282
283impl<T: Bind> Bind for SetExpression<T> {
284    type Bound = SetExpression<T::Bound>;
285
286    fn bind(&self, schema: SchemaRef, case_sensitive: bool) -> Result<Self::Bound> {
287        let bound_term = self.term.bind(schema.clone(), case_sensitive)?;
288        Ok(SetExpression::new(
289            self.op,
290            bound_term,
291            self.literals.clone(),
292        ))
293    }
294}
295
296impl<T: Display + Debug> Display for SetExpression<T> {
297    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
298        let mut literal_strs = self.literals.iter().map(|l| format!("{}", l));
299
300        write!(f, "{} {} ({})", self.term, self.op, literal_strs.join(", "))
301    }
302}
303
304/// Unbound predicate expression before binding to a schema.
305#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
306pub enum Predicate {
307    /// AlwaysTrue predicate, for example, `TRUE`.
308    AlwaysTrue,
309    /// AlwaysFalse predicate, for example, `FALSE`.
310    AlwaysFalse,
311    /// And predicate, for example, `a > 10 AND b < 20`.
312    And(LogicalExpression<Predicate, 2>),
313    /// Or predicate, for example, `a > 10 OR b < 20`.
314    Or(LogicalExpression<Predicate, 2>),
315    /// Not predicate, for example, `NOT (a > 10)`.
316    Not(LogicalExpression<Predicate, 1>),
317    /// Unary expression, for example, `a IS NULL`.
318    Unary(UnaryExpression<Reference>),
319    /// Binary expression, for example, `a > 10`.
320    Binary(BinaryExpression<Reference>),
321    /// Set predicates, for example, `a in (1, 2, 3)`.
322    Set(SetExpression<Reference>),
323}
324
325impl Bind for Predicate {
326    type Bound = BoundPredicate;
327
328    fn bind(&self, schema: SchemaRef, case_sensitive: bool) -> Result<BoundPredicate> {
329        match self {
330            Predicate::And(expr) => {
331                let bound_expr = expr.bind(schema, case_sensitive)?;
332
333                let [left, right] = bound_expr.inputs;
334                Ok(match (left, right) {
335                    (_, r) if matches!(&*r, &BoundPredicate::AlwaysFalse) => {
336                        BoundPredicate::AlwaysFalse
337                    }
338                    (l, _) if matches!(&*l, &BoundPredicate::AlwaysFalse) => {
339                        BoundPredicate::AlwaysFalse
340                    }
341                    (left, r) if matches!(&*r, &BoundPredicate::AlwaysTrue) => *left,
342                    (l, right) if matches!(&*l, &BoundPredicate::AlwaysTrue) => *right,
343                    (left, right) => BoundPredicate::And(LogicalExpression::new([left, right])),
344                })
345            }
346            Predicate::Not(expr) => {
347                let bound_expr = expr.bind(schema, case_sensitive)?;
348                let [inner] = bound_expr.inputs;
349                Ok(match inner {
350                    e if matches!(&*e, &BoundPredicate::AlwaysTrue) => BoundPredicate::AlwaysFalse,
351                    e if matches!(&*e, &BoundPredicate::AlwaysFalse) => BoundPredicate::AlwaysTrue,
352                    e => BoundPredicate::Not(LogicalExpression::new([e])),
353                })
354            }
355            Predicate::Or(expr) => {
356                let bound_expr = expr.bind(schema, case_sensitive)?;
357                let [left, right] = bound_expr.inputs;
358                Ok(match (left, right) {
359                    (l, r)
360                        if matches!(&*r, &BoundPredicate::AlwaysTrue)
361                            || matches!(&*l, &BoundPredicate::AlwaysTrue) =>
362                    {
363                        BoundPredicate::AlwaysTrue
364                    }
365                    (left, r) if matches!(&*r, &BoundPredicate::AlwaysFalse) => *left,
366                    (l, right) if matches!(&*l, &BoundPredicate::AlwaysFalse) => *right,
367                    (left, right) => BoundPredicate::Or(LogicalExpression::new([left, right])),
368                })
369            }
370            Predicate::Unary(expr) => {
371                let bound_expr = expr.bind(schema, case_sensitive)?;
372
373                match &bound_expr.op {
374                    &PredicateOperator::IsNull => {
375                        if bound_expr.term.field().required {
376                            return Ok(BoundPredicate::AlwaysFalse);
377                        }
378                    }
379                    &PredicateOperator::NotNull => {
380                        if bound_expr.term.field().required {
381                            return Ok(BoundPredicate::AlwaysTrue);
382                        }
383                    }
384                    &PredicateOperator::IsNan | &PredicateOperator::NotNan => {
385                        if !bound_expr.term.field().field_type.is_floating_type() {
386                            return Err(Error::new(
387                                ErrorKind::DataInvalid,
388                                format!(
389                                    "Expecting floating point type, but found {}",
390                                    bound_expr.term.field().field_type
391                                ),
392                            ));
393                        }
394                    }
395                    op => {
396                        return Err(Error::new(
397                            ErrorKind::Unexpected,
398                            format!("Expecting unary operator, but found {op}"),
399                        ));
400                    }
401                }
402
403                Ok(BoundPredicate::Unary(bound_expr))
404            }
405            Predicate::Binary(expr) => {
406                let bound_expr = expr.bind(schema, case_sensitive)?;
407                let bound_literal = bound_expr.literal.to(&bound_expr.term.field().field_type)?;
408
409                match bound_literal.literal() {
410                    PrimitiveLiteral::AboveMax => match &bound_expr.op {
411                        &PredicateOperator::LessThan
412                        | &PredicateOperator::LessThanOrEq
413                        | &PredicateOperator::NotEq => {
414                            return Ok(BoundPredicate::AlwaysTrue);
415                        }
416                        &PredicateOperator::GreaterThan
417                        | &PredicateOperator::GreaterThanOrEq
418                        | &PredicateOperator::Eq => {
419                            return Ok(BoundPredicate::AlwaysFalse);
420                        }
421                        _ => {}
422                    },
423                    PrimitiveLiteral::BelowMin => match &bound_expr.op {
424                        &PredicateOperator::GreaterThan
425                        | &PredicateOperator::GreaterThanOrEq
426                        | &PredicateOperator::NotEq => {
427                            return Ok(BoundPredicate::AlwaysTrue);
428                        }
429                        &PredicateOperator::LessThan
430                        | &PredicateOperator::LessThanOrEq
431                        | &PredicateOperator::Eq => {
432                            return Ok(BoundPredicate::AlwaysFalse);
433                        }
434                        _ => {}
435                    },
436                    _ => {}
437                }
438
439                Ok(BoundPredicate::Binary(BinaryExpression::new(
440                    bound_expr.op,
441                    bound_expr.term,
442                    bound_literal,
443                )))
444            }
445            Predicate::Set(expr) => {
446                let bound_expr = expr.bind(schema, case_sensitive)?;
447                let bound_literals = bound_expr
448                    .literals
449                    .into_iter()
450                    .map(|l| l.to(&bound_expr.term.field().field_type))
451                    .collect::<Result<FnvHashSet<Datum>>>()?;
452
453                match &bound_expr.op {
454                    &PredicateOperator::In => {
455                        if bound_literals.is_empty() {
456                            return Ok(BoundPredicate::AlwaysFalse);
457                        }
458                        if bound_literals.len() == 1 {
459                            return Ok(BoundPredicate::Binary(BinaryExpression::new(
460                                PredicateOperator::Eq,
461                                bound_expr.term,
462                                bound_literals.into_iter().next().unwrap(),
463                            )));
464                        }
465                    }
466                    &PredicateOperator::NotIn => {
467                        if bound_literals.is_empty() {
468                            return Ok(BoundPredicate::AlwaysTrue);
469                        }
470                        if bound_literals.len() == 1 {
471                            return Ok(BoundPredicate::Binary(BinaryExpression::new(
472                                PredicateOperator::NotEq,
473                                bound_expr.term,
474                                bound_literals.into_iter().next().unwrap(),
475                            )));
476                        }
477                    }
478                    op => {
479                        return Err(Error::new(
480                            ErrorKind::Unexpected,
481                            format!("Expecting unary operator,but found {op}"),
482                        ));
483                    }
484                }
485
486                Ok(BoundPredicate::Set(SetExpression::new(
487                    bound_expr.op,
488                    bound_expr.term,
489                    bound_literals,
490                )))
491            }
492            Predicate::AlwaysTrue => Ok(BoundPredicate::AlwaysTrue),
493            Predicate::AlwaysFalse => Ok(BoundPredicate::AlwaysFalse),
494        }
495    }
496}
497
498impl Display for Predicate {
499    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
500        match self {
501            Predicate::AlwaysTrue => {
502                write!(f, "TRUE")
503            }
504            Predicate::AlwaysFalse => {
505                write!(f, "FALSE")
506            }
507            Predicate::And(expr) => {
508                write!(f, "({}) AND ({})", expr.inputs()[0], expr.inputs()[1])
509            }
510            Predicate::Or(expr) => {
511                write!(f, "({}) OR ({})", expr.inputs()[0], expr.inputs()[1])
512            }
513            Predicate::Not(expr) => {
514                write!(f, "NOT ({})", expr.inputs()[0])
515            }
516            Predicate::Unary(expr) => {
517                write!(f, "{}", expr)
518            }
519            Predicate::Binary(expr) => {
520                write!(f, "{}", expr)
521            }
522            Predicate::Set(expr) => {
523                write!(f, "{}", expr)
524            }
525        }
526    }
527}
528
529impl Predicate {
530    /// Combines two predicates with `AND`.
531    ///
532    /// # Example
533    ///
534    /// ```rust
535    /// use std::ops::Bound::Unbounded;
536    ///
537    /// use iceberg_unofficial::expr::BoundPredicate::Unary;
538    /// use iceberg_unofficial::expr::Reference;
539    /// use iceberg_unofficial::spec::Datum;
540    /// let expr1 = Reference::new("a").less_than(Datum::long(10));
541    ///
542    /// let expr2 = Reference::new("b").less_than(Datum::long(20));
543    ///
544    /// let expr = expr1.and(expr2);
545    ///
546    /// assert_eq!(&format!("{expr}"), "(a < 10) AND (b < 20)");
547    /// ```
548    pub fn and(self, other: Predicate) -> Predicate {
549        match (self, other) {
550            (Predicate::AlwaysFalse, _) => Predicate::AlwaysFalse,
551            (_, Predicate::AlwaysFalse) => Predicate::AlwaysFalse,
552            (Predicate::AlwaysTrue, rhs) => rhs,
553            (lhs, Predicate::AlwaysTrue) => lhs,
554            (lhs, rhs) => Predicate::And(LogicalExpression::new([Box::new(lhs), Box::new(rhs)])),
555        }
556    }
557
558    /// Combines two predicates with `OR`.
559    ///
560    /// # Example
561    ///
562    /// ```rust
563    /// use std::ops::Bound::Unbounded;
564    ///
565    /// use iceberg_unofficial::expr::BoundPredicate::Unary;
566    /// use iceberg_unofficial::expr::Reference;
567    /// use iceberg_unofficial::spec::Datum;
568    /// let expr1 = Reference::new("a").less_than(Datum::long(10));
569    ///
570    /// let expr2 = Reference::new("b").less_than(Datum::long(20));
571    ///
572    /// let expr = expr1.or(expr2);
573    ///
574    /// assert_eq!(&format!("{expr}"), "(a < 10) OR (b < 20)");
575    /// ```
576    pub fn or(self, other: Predicate) -> Predicate {
577        match (self, other) {
578            (Predicate::AlwaysTrue, _) => Predicate::AlwaysTrue,
579            (_, Predicate::AlwaysTrue) => Predicate::AlwaysTrue,
580            (Predicate::AlwaysFalse, rhs) => rhs,
581            (lhs, Predicate::AlwaysFalse) => lhs,
582            (lhs, rhs) => Predicate::Or(LogicalExpression::new([Box::new(lhs), Box::new(rhs)])),
583        }
584    }
585
586    /// Returns a predicate representing the negation ('NOT') of this one,
587    /// by using inverse predicates rather than wrapping in a `NOT`.
588    /// Used for `NOT` elimination.
589    ///
590    /// # Example
591    ///
592    /// ```rust
593    /// use std::ops::Bound::Unbounded;
594    ///
595    /// use iceberg_unofficial::expr::BoundPredicate::Unary;
596    /// use iceberg_unofficial::expr::{LogicalExpression, Predicate, Reference};
597    /// use iceberg_unofficial::spec::Datum;
598    /// let expr1 = Reference::new("a").less_than(Datum::long(10));
599    /// let expr2 = Reference::new("b")
600    ///     .less_than(Datum::long(5))
601    ///     .and(Reference::new("c").less_than(Datum::long(10)));
602    ///
603    /// let result = expr1.negate();
604    /// assert_eq!(&format!("{result}"), "a >= 10");
605    ///
606    /// let result = expr2.negate();
607    /// assert_eq!(&format!("{result}"), "(b >= 5) OR (c >= 10)");
608    /// ```
609    pub fn negate(self) -> Predicate {
610        match self {
611            Predicate::AlwaysTrue => Predicate::AlwaysFalse,
612            Predicate::AlwaysFalse => Predicate::AlwaysTrue,
613            Predicate::And(expr) => Predicate::Or(LogicalExpression::new(
614                expr.inputs.map(|expr| Box::new(expr.negate())),
615            )),
616            Predicate::Or(expr) => Predicate::And(LogicalExpression::new(
617                expr.inputs.map(|expr| Box::new(expr.negate())),
618            )),
619            Predicate::Not(expr) => {
620                let LogicalExpression { inputs: [input_0] } = expr;
621                *input_0
622            }
623            Predicate::Unary(expr) => {
624                Predicate::Unary(UnaryExpression::new(expr.op.negate(), expr.term))
625            }
626            Predicate::Binary(expr) => Predicate::Binary(BinaryExpression::new(
627                expr.op.negate(),
628                expr.term,
629                expr.literal,
630            )),
631            Predicate::Set(expr) => Predicate::Set(SetExpression::new(
632                expr.op.negate(),
633                expr.term,
634                expr.literals,
635            )),
636        }
637    }
638    /// Simplifies the expression by removing `NOT` predicates,
639    /// directly negating the inner expressions instead. The transformation
640    /// applies logical laws (such as De Morgan's laws) to
641    /// recursively negate and simplify inner expressions within `NOT`
642    /// predicates.
643    ///
644    /// # Example
645    ///
646    /// ```rust
647    /// use std::ops::Not;
648    ///
649    /// use iceberg_unofficial::expr::{LogicalExpression, Predicate, Reference};
650    /// use iceberg_unofficial::spec::Datum;
651    ///
652    /// let expression = Reference::new("a").less_than(Datum::long(5)).not();
653    /// let result = expression.rewrite_not();
654    ///
655    /// assert_eq!(&format!("{result}"), "a >= 5");
656    /// ```
657    pub fn rewrite_not(self) -> Predicate {
658        visit(&mut RewriteNotVisitor::new(), &self)
659            .expect("RewriteNotVisitor guarantees always success")
660    }
661}
662
663impl Not for Predicate {
664    type Output = Predicate;
665
666    /// Create a predicate which is the reverse of this predicate. For example: `NOT (a > 10)`.
667    ///
668    /// This is different from [`Predicate::negate()`] since it doesn't rewrite expression, but
669    /// just adds a `NOT` operator.
670    ///
671    /// # Example
672    ///     
673    ///```rust
674    /// use std::ops::Bound::Unbounded;
675    ///
676    /// use iceberg_unofficial::expr::BoundPredicate::Unary;
677    /// use iceberg_unofficial::expr::Reference;
678    /// use iceberg_unofficial::spec::Datum;
679    /// let expr1 = Reference::new("a").less_than(Datum::long(10));
680    ///
681    /// let expr = !expr1;
682    ///
683    /// assert_eq!(&format!("{expr}"), "NOT (a < 10)");
684    /// ```
685    fn not(self) -> Self::Output {
686        Predicate::Not(LogicalExpression::new([Box::new(self)]))
687    }
688}
689
690/// Bound predicate expression after binding to a schema.
691#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
692pub enum BoundPredicate {
693    /// An expression always evaluates to true.
694    AlwaysTrue,
695    /// An expression always evaluates to false.
696    AlwaysFalse,
697    /// An expression combined by `AND`, for example, `a > 10 AND b < 20`.
698    And(LogicalExpression<BoundPredicate, 2>),
699    /// An expression combined by `OR`, for example, `a > 10 OR b < 20`.
700    Or(LogicalExpression<BoundPredicate, 2>),
701    /// An expression combined by `NOT`, for example, `NOT (a > 10)`.
702    Not(LogicalExpression<BoundPredicate, 1>),
703    /// Unary expression, for example, `a IS NULL`.
704    Unary(UnaryExpression<BoundReference>),
705    /// Binary expression, for example, `a > 10`.
706    Binary(BinaryExpression<BoundReference>),
707    /// Set predicates, for example, `a IN (1, 2, 3)`.
708    Set(SetExpression<BoundReference>),
709}
710
711impl BoundPredicate {
712    pub(crate) fn and(self, other: BoundPredicate) -> BoundPredicate {
713        BoundPredicate::And(LogicalExpression::new([Box::new(self), Box::new(other)]))
714    }
715
716    pub(crate) fn or(self, other: BoundPredicate) -> BoundPredicate {
717        BoundPredicate::Or(LogicalExpression::new([Box::new(self), Box::new(other)]))
718    }
719
720    pub(crate) fn negate(self) -> BoundPredicate {
721        match self {
722            BoundPredicate::AlwaysTrue => BoundPredicate::AlwaysFalse,
723            BoundPredicate::AlwaysFalse => BoundPredicate::AlwaysTrue,
724            BoundPredicate::And(expr) => BoundPredicate::Or(LogicalExpression::new(
725                expr.inputs.map(|expr| Box::new(expr.negate())),
726            )),
727            BoundPredicate::Or(expr) => BoundPredicate::And(LogicalExpression::new(
728                expr.inputs.map(|expr| Box::new(expr.negate())),
729            )),
730            BoundPredicate::Not(expr) => {
731                let LogicalExpression { inputs: [input_0] } = expr;
732                *input_0
733            }
734            BoundPredicate::Unary(expr) => {
735                BoundPredicate::Unary(UnaryExpression::new(expr.op.negate(), expr.term))
736            }
737            BoundPredicate::Binary(expr) => BoundPredicate::Binary(BinaryExpression::new(
738                expr.op.negate(),
739                expr.term,
740                expr.literal,
741            )),
742            BoundPredicate::Set(expr) => BoundPredicate::Set(SetExpression::new(
743                expr.op.negate(),
744                expr.term,
745                expr.literals,
746            )),
747        }
748    }
749
750    /// Simplifies the expression by removing `NOT` predicates,
751    /// directly negating the inner expressions instead. The transformation
752    /// applies logical laws (such as De Morgan's laws) to
753    /// recursively negate and simplify inner expressions within `NOT`
754    /// predicates.
755    ///
756    /// # Example
757    ///
758    /// ```rust
759    /// use std::ops::Not;
760    ///
761    /// use iceberg_unofficial::expr::{Bind, BoundPredicate, Reference};
762    /// use iceberg_unofficial::spec::Datum;
763    ///
764    /// // This would need to be bound first, but the concept is:
765    /// // let expression = bound_predicate.not();
766    /// // let result = expression.rewrite_not();
767    /// ```
768    pub fn rewrite_not(self) -> BoundPredicate {
769        visit_bound(&mut RewriteNotVisitor::new(), &self)
770            .expect("RewriteNotVisitor guarantees always success")
771    }
772}
773
774impl Display for BoundPredicate {
775    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
776        match self {
777            BoundPredicate::AlwaysTrue => {
778                write!(f, "True")
779            }
780            BoundPredicate::AlwaysFalse => {
781                write!(f, "False")
782            }
783            BoundPredicate::And(expr) => {
784                write!(f, "({}) AND ({})", expr.inputs()[0], expr.inputs()[1])
785            }
786            BoundPredicate::Or(expr) => {
787                write!(f, "({}) OR ({})", expr.inputs()[0], expr.inputs()[1])
788            }
789            BoundPredicate::Not(expr) => {
790                write!(f, "NOT ({})", expr.inputs()[0])
791            }
792            BoundPredicate::Unary(expr) => {
793                write!(f, "{}", expr)
794            }
795            BoundPredicate::Binary(expr) => {
796                write!(f, "{}", expr)
797            }
798            BoundPredicate::Set(expr) => {
799                write!(f, "{}", expr)
800            }
801        }
802    }
803}
804
805#[cfg(test)]
806mod tests {
807    use std::ops::Not;
808    use std::sync::Arc;
809
810    use crate::expr::Predicate::{AlwaysFalse, AlwaysTrue};
811    use crate::expr::{Bind, BoundPredicate, Reference};
812    use crate::spec::{Datum, NestedField, PrimitiveType, Schema, SchemaRef, Type};
813
814    #[test]
815    fn test_logical_or_rewrite_not() {
816        let expression = Reference::new("b")
817            .less_than(Datum::long(5))
818            .or(Reference::new("c").less_than(Datum::long(10)))
819            .not();
820
821        let expected = Reference::new("b")
822            .greater_than_or_equal_to(Datum::long(5))
823            .and(Reference::new("c").greater_than_or_equal_to(Datum::long(10)));
824
825        let result = expression.rewrite_not();
826
827        assert_eq!(result, expected);
828    }
829
830    #[test]
831    fn test_logical_and_rewrite_not() {
832        let expression = Reference::new("b")
833            .less_than(Datum::long(5))
834            .and(Reference::new("c").less_than(Datum::long(10)))
835            .not();
836
837        let expected = Reference::new("b")
838            .greater_than_or_equal_to(Datum::long(5))
839            .or(Reference::new("c").greater_than_or_equal_to(Datum::long(10)));
840
841        let result = expression.rewrite_not();
842
843        assert_eq!(result, expected);
844    }
845
846    #[test]
847    fn test_set_rewrite_not() {
848        let expression = Reference::new("a")
849            .is_in([Datum::int(5), Datum::int(6)])
850            .not();
851
852        let expected = Reference::new("a").is_not_in([Datum::int(5), Datum::int(6)]);
853
854        let result = expression.rewrite_not();
855
856        assert_eq!(result, expected);
857    }
858
859    #[test]
860    fn test_binary_rewrite_not() {
861        let expression = Reference::new("a").less_than(Datum::long(5)).not();
862
863        let expected = Reference::new("a").greater_than_or_equal_to(Datum::long(5));
864
865        let result = expression.rewrite_not();
866
867        assert_eq!(result, expected);
868    }
869
870    #[test]
871    fn test_unary_rewrite_not() {
872        let expression = Reference::new("a").is_null().not();
873
874        let expected = Reference::new("a").is_not_null();
875
876        let result = expression.rewrite_not();
877
878        assert_eq!(result, expected);
879    }
880
881    #[test]
882    fn test_predicate_and_reduce_always_true_false() {
883        let true_or_expr = AlwaysTrue.and(Reference::new("b").less_than(Datum::long(5)));
884        assert_eq!(&format!("{true_or_expr}"), "b < 5");
885
886        let expr_or_true = Reference::new("b")
887            .less_than(Datum::long(5))
888            .and(AlwaysTrue);
889        assert_eq!(&format!("{expr_or_true}"), "b < 5");
890
891        let false_or_expr = AlwaysFalse.and(Reference::new("b").less_than(Datum::long(5)));
892        assert_eq!(&format!("{false_or_expr}"), "FALSE");
893
894        let expr_or_false = Reference::new("b")
895            .less_than(Datum::long(5))
896            .and(AlwaysFalse);
897        assert_eq!(&format!("{expr_or_false}"), "FALSE");
898    }
899
900    #[test]
901    fn test_predicate_or_reduce_always_true_false() {
902        let true_or_expr = AlwaysTrue.or(Reference::new("b").less_than(Datum::long(5)));
903        assert_eq!(&format!("{true_or_expr}"), "TRUE");
904
905        let expr_or_true = Reference::new("b").less_than(Datum::long(5)).or(AlwaysTrue);
906        assert_eq!(&format!("{expr_or_true}"), "TRUE");
907
908        let false_or_expr = AlwaysFalse.or(Reference::new("b").less_than(Datum::long(5)));
909        assert_eq!(&format!("{false_or_expr}"), "b < 5");
910
911        let expr_or_false = Reference::new("b")
912            .less_than(Datum::long(5))
913            .or(AlwaysFalse);
914        assert_eq!(&format!("{expr_or_false}"), "b < 5");
915    }
916
917    #[test]
918    fn test_predicate_negate_and() {
919        let expression = Reference::new("b")
920            .less_than(Datum::long(5))
921            .and(Reference::new("c").less_than(Datum::long(10)));
922
923        let expected = Reference::new("b")
924            .greater_than_or_equal_to(Datum::long(5))
925            .or(Reference::new("c").greater_than_or_equal_to(Datum::long(10)));
926
927        let result = expression.negate();
928
929        assert_eq!(result, expected);
930    }
931
932    #[test]
933    fn test_predicate_negate_or() {
934        let expression = Reference::new("b")
935            .greater_than_or_equal_to(Datum::long(5))
936            .or(Reference::new("c").greater_than_or_equal_to(Datum::long(10)));
937
938        let expected = Reference::new("b")
939            .less_than(Datum::long(5))
940            .and(Reference::new("c").less_than(Datum::long(10)));
941
942        let result = expression.negate();
943
944        assert_eq!(result, expected);
945    }
946
947    #[test]
948    fn test_predicate_negate_not() {
949        let expression = Reference::new("b")
950            .greater_than_or_equal_to(Datum::long(5))
951            .not();
952
953        let expected = Reference::new("b").greater_than_or_equal_to(Datum::long(5));
954
955        let result = expression.negate();
956
957        assert_eq!(result, expected);
958    }
959
960    #[test]
961    fn test_predicate_negate_unary() {
962        let expression = Reference::new("b").is_not_null();
963
964        let expected = Reference::new("b").is_null();
965
966        let result = expression.negate();
967
968        assert_eq!(result, expected);
969    }
970
971    #[test]
972    fn test_predicate_negate_binary() {
973        let expression = Reference::new("a").less_than(Datum::long(5));
974
975        let expected = Reference::new("a").greater_than_or_equal_to(Datum::long(5));
976
977        let result = expression.negate();
978
979        assert_eq!(result, expected);
980    }
981
982    #[test]
983    fn test_predicate_negate_set() {
984        let expression = Reference::new("a").is_in([Datum::long(5), Datum::long(6)]);
985
986        let expected = Reference::new("a").is_not_in([Datum::long(5), Datum::long(6)]);
987
988        let result = expression.negate();
989
990        assert_eq!(result, expected);
991    }
992
993    pub fn table_schema_simple() -> SchemaRef {
994        Arc::new(
995            Schema::builder()
996                .with_schema_id(1)
997                .with_identifier_field_ids(vec![2])
998                .with_fields(vec![
999                    NestedField::optional(1, "foo", Type::Primitive(PrimitiveType::String)).into(),
1000                    NestedField::required(2, "bar", Type::Primitive(PrimitiveType::Int)).into(),
1001                    NestedField::optional(3, "baz", Type::Primitive(PrimitiveType::Boolean)).into(),
1002                    NestedField::optional(4, "qux", Type::Primitive(PrimitiveType::Float)).into(),
1003                ])
1004                .build()
1005                .unwrap(),
1006        )
1007    }
1008
1009    fn test_bound_predicate_serialize_diserialize(bound_predicate: BoundPredicate) {
1010        let serialized = serde_json::to_string(&bound_predicate).unwrap();
1011        let deserialized: BoundPredicate = serde_json::from_str(&serialized).unwrap();
1012        assert_eq!(bound_predicate, deserialized);
1013    }
1014
1015    #[test]
1016    fn test_bind_is_null() {
1017        let schema = table_schema_simple();
1018        let expr = Reference::new("foo").is_null();
1019        let bound_expr = expr.bind(schema, true).unwrap();
1020        assert_eq!(&format!("{bound_expr}"), "foo IS NULL");
1021        test_bound_predicate_serialize_diserialize(bound_expr);
1022    }
1023
1024    #[test]
1025    fn test_bind_is_null_required() {
1026        let schema = table_schema_simple();
1027        let expr = Reference::new("bar").is_null();
1028        let bound_expr = expr.bind(schema, true).unwrap();
1029        assert_eq!(&format!("{bound_expr}"), "False");
1030        test_bound_predicate_serialize_diserialize(bound_expr);
1031    }
1032
1033    #[test]
1034    fn test_bind_is_not_null() {
1035        let schema = table_schema_simple();
1036        let expr = Reference::new("foo").is_not_null();
1037        let bound_expr = expr.bind(schema, true).unwrap();
1038        assert_eq!(&format!("{bound_expr}"), "foo IS NOT NULL");
1039        test_bound_predicate_serialize_diserialize(bound_expr);
1040    }
1041
1042    #[test]
1043    fn test_bind_is_not_null_required() {
1044        let schema = table_schema_simple();
1045        let expr = Reference::new("bar").is_not_null();
1046        let bound_expr = expr.bind(schema, true).unwrap();
1047        assert_eq!(&format!("{bound_expr}"), "True");
1048        test_bound_predicate_serialize_diserialize(bound_expr);
1049    }
1050
1051    #[test]
1052    fn test_bind_is_nan() {
1053        let schema = table_schema_simple();
1054        let expr = Reference::new("qux").is_nan();
1055        let bound_expr = expr.bind(schema, true).unwrap();
1056        assert_eq!(&format!("{bound_expr}"), "qux IS NAN");
1057
1058        let schema_string = table_schema_simple();
1059        let expr_string = Reference::new("foo").is_nan();
1060        let bound_expr_string = expr_string.bind(schema_string, true);
1061        assert!(bound_expr_string.is_err());
1062        test_bound_predicate_serialize_diserialize(bound_expr);
1063    }
1064
1065    #[test]
1066    fn test_bind_is_nan_wrong_type() {
1067        let schema = table_schema_simple();
1068        let expr = Reference::new("foo").is_nan();
1069        let bound_expr = expr.bind(schema, true);
1070        assert!(bound_expr.is_err());
1071    }
1072
1073    #[test]
1074    fn test_bind_is_not_nan() {
1075        let schema = table_schema_simple();
1076        let expr = Reference::new("qux").is_not_nan();
1077        let bound_expr = expr.bind(schema, true).unwrap();
1078        assert_eq!(&format!("{bound_expr}"), "qux IS NOT NAN");
1079        test_bound_predicate_serialize_diserialize(bound_expr);
1080    }
1081
1082    #[test]
1083    fn test_bind_is_not_nan_wrong_type() {
1084        let schema = table_schema_simple();
1085        let expr = Reference::new("foo").is_not_nan();
1086        let bound_expr = expr.bind(schema, true);
1087        assert!(bound_expr.is_err());
1088    }
1089
1090    #[test]
1091    fn test_bind_less_than() {
1092        let schema = table_schema_simple();
1093        let expr = Reference::new("bar").less_than(Datum::int(10));
1094        let bound_expr = expr.bind(schema, true).unwrap();
1095        assert_eq!(&format!("{bound_expr}"), "bar < 10");
1096        test_bound_predicate_serialize_diserialize(bound_expr);
1097    }
1098
1099    #[test]
1100    fn test_bind_less_than_wrong_type() {
1101        let schema = table_schema_simple();
1102        let expr = Reference::new("bar").less_than(Datum::string("abcd"));
1103        let bound_expr = expr.bind(schema, true);
1104        assert!(bound_expr.is_err());
1105    }
1106
1107    #[test]
1108    fn test_bind_less_than_or_eq() {
1109        let schema = table_schema_simple();
1110        let expr = Reference::new("bar").less_than_or_equal_to(Datum::int(10));
1111        let bound_expr = expr.bind(schema, true).unwrap();
1112        assert_eq!(&format!("{bound_expr}"), "bar <= 10");
1113        test_bound_predicate_serialize_diserialize(bound_expr);
1114    }
1115
1116    #[test]
1117    fn test_bind_less_than_or_eq_wrong_type() {
1118        let schema = table_schema_simple();
1119        let expr = Reference::new("bar").less_than_or_equal_to(Datum::string("abcd"));
1120        let bound_expr = expr.bind(schema, true);
1121        assert!(bound_expr.is_err());
1122    }
1123
1124    #[test]
1125    fn test_bind_greater_than() {
1126        let schema = table_schema_simple();
1127        let expr = Reference::new("bar").greater_than(Datum::int(10));
1128        let bound_expr = expr.bind(schema, true).unwrap();
1129        assert_eq!(&format!("{bound_expr}"), "bar > 10");
1130        test_bound_predicate_serialize_diserialize(bound_expr);
1131    }
1132
1133    #[test]
1134    fn test_bind_greater_than_wrong_type() {
1135        let schema = table_schema_simple();
1136        let expr = Reference::new("bar").greater_than(Datum::string("abcd"));
1137        let bound_expr = expr.bind(schema, true);
1138        assert!(bound_expr.is_err());
1139    }
1140
1141    #[test]
1142    fn test_bind_greater_than_or_eq() {
1143        let schema = table_schema_simple();
1144        let expr = Reference::new("bar").greater_than_or_equal_to(Datum::int(10));
1145        let bound_expr = expr.bind(schema, true).unwrap();
1146        assert_eq!(&format!("{bound_expr}"), "bar >= 10");
1147        test_bound_predicate_serialize_diserialize(bound_expr);
1148    }
1149
1150    #[test]
1151    fn test_bind_greater_than_or_eq_wrong_type() {
1152        let schema = table_schema_simple();
1153        let expr = Reference::new("bar").greater_than_or_equal_to(Datum::string("abcd"));
1154        let bound_expr = expr.bind(schema, true);
1155        assert!(bound_expr.is_err());
1156    }
1157
1158    #[test]
1159    fn test_bind_equal_to() {
1160        let schema = table_schema_simple();
1161        let expr = Reference::new("bar").equal_to(Datum::int(10));
1162        let bound_expr = expr.bind(schema, true).unwrap();
1163        assert_eq!(&format!("{bound_expr}"), "bar = 10");
1164        test_bound_predicate_serialize_diserialize(bound_expr);
1165    }
1166
1167    #[test]
1168    fn test_bind_equal_to_above_max() {
1169        let schema = table_schema_simple();
1170        // int32 can hold up to 2147483647
1171        let expr = Reference::new("bar").equal_to(Datum::long(2147483648i64));
1172        let bound_expr = expr.bind(schema, true).unwrap();
1173        assert_eq!(&format!("{bound_expr}"), "False");
1174        test_bound_predicate_serialize_diserialize(bound_expr);
1175    }
1176
1177    #[test]
1178    fn test_bind_equal_to_below_min() {
1179        let schema = table_schema_simple();
1180        // int32 can hold up to -2147483647
1181        let expr = Reference::new("bar").equal_to(Datum::long(-2147483649i64));
1182        let bound_expr = expr.bind(schema, true).unwrap();
1183        assert_eq!(&format!("{bound_expr}"), "False");
1184        test_bound_predicate_serialize_diserialize(bound_expr);
1185    }
1186
1187    #[test]
1188    fn test_bind_not_equal_to_above_max() {
1189        let schema = table_schema_simple();
1190        // int32 can hold up to 2147483647
1191        let expr = Reference::new("bar").not_equal_to(Datum::long(2147483648i64));
1192        let bound_expr = expr.bind(schema, true).unwrap();
1193        assert_eq!(&format!("{bound_expr}"), "True");
1194        test_bound_predicate_serialize_diserialize(bound_expr);
1195    }
1196
1197    #[test]
1198    fn test_bind_not_equal_to_below_min() {
1199        let schema = table_schema_simple();
1200        // int32 can hold up to -2147483647
1201        let expr = Reference::new("bar").not_equal_to(Datum::long(-2147483649i64));
1202        let bound_expr = expr.bind(schema, true).unwrap();
1203        assert_eq!(&format!("{bound_expr}"), "True");
1204        test_bound_predicate_serialize_diserialize(bound_expr);
1205    }
1206
1207    #[test]
1208    fn test_bind_less_than_above_max() {
1209        let schema = table_schema_simple();
1210        // int32 can hold up to 2147483647
1211        let expr = Reference::new("bar").less_than(Datum::long(2147483648i64));
1212        let bound_expr = expr.bind(schema, true).unwrap();
1213        assert_eq!(&format!("{bound_expr}"), "True");
1214        test_bound_predicate_serialize_diserialize(bound_expr);
1215    }
1216
1217    #[test]
1218    fn test_bind_less_than_below_min() {
1219        let schema = table_schema_simple();
1220        // int32 can hold up to -2147483647
1221        let expr = Reference::new("bar").less_than(Datum::long(-2147483649i64));
1222        let bound_expr = expr.bind(schema, true).unwrap();
1223        assert_eq!(&format!("{bound_expr}"), "False");
1224        test_bound_predicate_serialize_diserialize(bound_expr);
1225    }
1226
1227    #[test]
1228    fn test_bind_less_than_or_equal_to_above_max() {
1229        let schema = table_schema_simple();
1230        // int32 can hold up to 2147483647
1231        let expr = Reference::new("bar").less_than_or_equal_to(Datum::long(2147483648i64));
1232        let bound_expr = expr.bind(schema, true).unwrap();
1233        assert_eq!(&format!("{bound_expr}"), "True");
1234        test_bound_predicate_serialize_diserialize(bound_expr);
1235    }
1236
1237    #[test]
1238    fn test_bind_less_than_or_equal_to_below_min() {
1239        let schema = table_schema_simple();
1240        // int32 can hold up to -2147483647
1241        let expr = Reference::new("bar").less_than_or_equal_to(Datum::long(-2147483649i64));
1242        let bound_expr = expr.bind(schema, true).unwrap();
1243        assert_eq!(&format!("{bound_expr}"), "False");
1244        test_bound_predicate_serialize_diserialize(bound_expr);
1245    }
1246
1247    #[test]
1248    fn test_bind_great_than_above_max() {
1249        let schema = table_schema_simple();
1250        // int32 can hold up to 2147483647
1251        let expr = Reference::new("bar").greater_than(Datum::long(2147483648i64));
1252        let bound_expr = expr.bind(schema, true).unwrap();
1253        assert_eq!(&format!("{bound_expr}"), "False");
1254        test_bound_predicate_serialize_diserialize(bound_expr);
1255    }
1256
1257    #[test]
1258    fn test_bind_great_than_below_min() {
1259        let schema = table_schema_simple();
1260        // int32 can hold up to -2147483647
1261        let expr = Reference::new("bar").greater_than(Datum::long(-2147483649i64));
1262        let bound_expr = expr.bind(schema, true).unwrap();
1263        assert_eq!(&format!("{bound_expr}"), "True");
1264        test_bound_predicate_serialize_diserialize(bound_expr);
1265    }
1266
1267    #[test]
1268    fn test_bind_great_than_or_equal_to_above_max() {
1269        let schema = table_schema_simple();
1270        // int32 can hold up to 2147483647
1271        let expr = Reference::new("bar").greater_than_or_equal_to(Datum::long(2147483648i64));
1272        let bound_expr = expr.bind(schema, true).unwrap();
1273        assert_eq!(&format!("{bound_expr}"), "False");
1274        test_bound_predicate_serialize_diserialize(bound_expr);
1275    }
1276
1277    #[test]
1278    fn test_bind_great_than_or_equal_to_below_min() {
1279        let schema = table_schema_simple();
1280        // int32 can hold up to -2147483647
1281        let expr = Reference::new("bar").greater_than_or_equal_to(Datum::long(-2147483649i64));
1282        let bound_expr = expr.bind(schema, true).unwrap();
1283        assert_eq!(&format!("{bound_expr}"), "True");
1284        test_bound_predicate_serialize_diserialize(bound_expr);
1285    }
1286
1287    #[test]
1288    fn test_bind_equal_to_wrong_type() {
1289        let schema = table_schema_simple();
1290        let expr = Reference::new("bar").equal_to(Datum::string("abcd"));
1291        let bound_expr = expr.bind(schema, true);
1292        assert!(bound_expr.is_err());
1293    }
1294
1295    #[test]
1296    fn test_bind_not_equal_to() {
1297        let schema = table_schema_simple();
1298        let expr = Reference::new("bar").not_equal_to(Datum::int(10));
1299        let bound_expr = expr.bind(schema, true).unwrap();
1300        assert_eq!(&format!("{bound_expr}"), "bar != 10");
1301        test_bound_predicate_serialize_diserialize(bound_expr);
1302    }
1303
1304    #[test]
1305    fn test_bind_not_equal_to_wrong_type() {
1306        let schema = table_schema_simple();
1307        let expr = Reference::new("bar").not_equal_to(Datum::string("abcd"));
1308        let bound_expr = expr.bind(schema, true);
1309        assert!(bound_expr.is_err());
1310    }
1311
1312    #[test]
1313    fn test_bind_starts_with() {
1314        let schema = table_schema_simple();
1315        let expr = Reference::new("foo").starts_with(Datum::string("abcd"));
1316        let bound_expr = expr.bind(schema, true).unwrap();
1317        assert_eq!(&format!("{bound_expr}"), r#"foo STARTS WITH "abcd""#);
1318        test_bound_predicate_serialize_diserialize(bound_expr);
1319    }
1320
1321    #[test]
1322    fn test_bind_starts_with_wrong_type() {
1323        let schema = table_schema_simple();
1324        let expr = Reference::new("bar").starts_with(Datum::string("abcd"));
1325        let bound_expr = expr.bind(schema, true);
1326        assert!(bound_expr.is_err());
1327    }
1328
1329    #[test]
1330    fn test_bind_not_starts_with() {
1331        let schema = table_schema_simple();
1332        let expr = Reference::new("foo").not_starts_with(Datum::string("abcd"));
1333        let bound_expr = expr.bind(schema, true).unwrap();
1334        assert_eq!(&format!("{bound_expr}"), r#"foo NOT STARTS WITH "abcd""#);
1335        test_bound_predicate_serialize_diserialize(bound_expr);
1336    }
1337
1338    #[test]
1339    fn test_bind_not_starts_with_wrong_type() {
1340        let schema = table_schema_simple();
1341        let expr = Reference::new("bar").not_starts_with(Datum::string("abcd"));
1342        let bound_expr = expr.bind(schema, true);
1343        assert!(bound_expr.is_err());
1344    }
1345
1346    #[test]
1347    fn test_bind_in() {
1348        let schema = table_schema_simple();
1349        let expr = Reference::new("bar").is_in([Datum::int(10), Datum::int(20)]);
1350        let bound_expr = expr.bind(schema, true).unwrap();
1351        assert_eq!(&format!("{bound_expr}"), "bar IN (20, 10)");
1352        test_bound_predicate_serialize_diserialize(bound_expr);
1353    }
1354
1355    #[test]
1356    fn test_bind_in_empty() {
1357        let schema = table_schema_simple();
1358        let expr = Reference::new("bar").is_in(vec![]);
1359        let bound_expr = expr.bind(schema, true).unwrap();
1360        assert_eq!(&format!("{bound_expr}"), "False");
1361        test_bound_predicate_serialize_diserialize(bound_expr);
1362    }
1363
1364    #[test]
1365    fn test_bind_in_one_literal() {
1366        let schema = table_schema_simple();
1367        let expr = Reference::new("bar").is_in(vec![Datum::int(10)]);
1368        let bound_expr = expr.bind(schema, true).unwrap();
1369        assert_eq!(&format!("{bound_expr}"), "bar = 10");
1370        test_bound_predicate_serialize_diserialize(bound_expr);
1371    }
1372
1373    #[test]
1374    fn test_bind_in_wrong_type() {
1375        let schema = table_schema_simple();
1376        let expr = Reference::new("bar").is_in(vec![Datum::int(10), Datum::string("abcd")]);
1377        let bound_expr = expr.bind(schema, true);
1378        assert!(bound_expr.is_err());
1379    }
1380
1381    #[test]
1382    fn test_bind_not_in() {
1383        let schema = table_schema_simple();
1384        let expr = Reference::new("bar").is_not_in([Datum::int(10), Datum::int(20)]);
1385        let bound_expr = expr.bind(schema, true).unwrap();
1386        assert_eq!(&format!("{bound_expr}"), "bar NOT IN (20, 10)");
1387        test_bound_predicate_serialize_diserialize(bound_expr);
1388    }
1389
1390    #[test]
1391    fn test_bind_not_in_empty() {
1392        let schema = table_schema_simple();
1393        let expr = Reference::new("bar").is_not_in(vec![]);
1394        let bound_expr = expr.bind(schema, true).unwrap();
1395        assert_eq!(&format!("{bound_expr}"), "True");
1396        test_bound_predicate_serialize_diserialize(bound_expr);
1397    }
1398
1399    #[test]
1400    fn test_bind_not_in_one_literal() {
1401        let schema = table_schema_simple();
1402        let expr = Reference::new("bar").is_not_in(vec![Datum::int(10)]);
1403        let bound_expr = expr.bind(schema, true).unwrap();
1404        assert_eq!(&format!("{bound_expr}"), "bar != 10");
1405        test_bound_predicate_serialize_diserialize(bound_expr);
1406    }
1407
1408    #[test]
1409    fn test_bind_not_in_wrong_type() {
1410        let schema = table_schema_simple();
1411        let expr = Reference::new("bar").is_not_in([Datum::int(10), Datum::string("abcd")]);
1412        let bound_expr = expr.bind(schema, true);
1413        assert!(bound_expr.is_err());
1414    }
1415
1416    #[test]
1417    fn test_bind_and() {
1418        let schema = table_schema_simple();
1419        let expr = Reference::new("bar")
1420            .less_than(Datum::int(10))
1421            .and(Reference::new("foo").is_null());
1422        let bound_expr = expr.bind(schema, true).unwrap();
1423        assert_eq!(&format!("{bound_expr}"), "(bar < 10) AND (foo IS NULL)");
1424        test_bound_predicate_serialize_diserialize(bound_expr);
1425    }
1426
1427    #[test]
1428    fn test_bind_and_always_false() {
1429        let schema = table_schema_simple();
1430        let expr = Reference::new("foo")
1431            .less_than(Datum::string("abcd"))
1432            .and(Reference::new("bar").is_null());
1433        let bound_expr = expr.bind(schema, true).unwrap();
1434        assert_eq!(&format!("{bound_expr}"), "False");
1435        test_bound_predicate_serialize_diserialize(bound_expr);
1436    }
1437
1438    #[test]
1439    fn test_bind_and_always_true() {
1440        let schema = table_schema_simple();
1441        let expr = Reference::new("foo")
1442            .less_than(Datum::string("abcd"))
1443            .and(Reference::new("bar").is_not_null());
1444        let bound_expr = expr.bind(schema, true).unwrap();
1445        assert_eq!(&format!("{bound_expr}"), r#"foo < "abcd""#);
1446        test_bound_predicate_serialize_diserialize(bound_expr);
1447    }
1448
1449    #[test]
1450    fn test_bind_or() {
1451        let schema = table_schema_simple();
1452        let expr = Reference::new("bar")
1453            .less_than(Datum::int(10))
1454            .or(Reference::new("foo").is_null());
1455        let bound_expr = expr.bind(schema, true).unwrap();
1456        assert_eq!(&format!("{bound_expr}"), "(bar < 10) OR (foo IS NULL)");
1457        test_bound_predicate_serialize_diserialize(bound_expr);
1458    }
1459
1460    #[test]
1461    fn test_bind_or_always_true() {
1462        let schema = table_schema_simple();
1463        let expr = Reference::new("foo")
1464            .less_than(Datum::string("abcd"))
1465            .or(Reference::new("bar").is_not_null());
1466        let bound_expr = expr.bind(schema, true).unwrap();
1467        assert_eq!(&format!("{bound_expr}"), "True");
1468        test_bound_predicate_serialize_diserialize(bound_expr);
1469    }
1470
1471    #[test]
1472    fn test_bind_or_always_false() {
1473        let schema = table_schema_simple();
1474        let expr = Reference::new("foo")
1475            .less_than(Datum::string("abcd"))
1476            .or(Reference::new("bar").is_null());
1477        let bound_expr = expr.bind(schema, true).unwrap();
1478        assert_eq!(&format!("{bound_expr}"), r#"foo < "abcd""#);
1479        test_bound_predicate_serialize_diserialize(bound_expr);
1480    }
1481
1482    #[test]
1483    fn test_bind_not() {
1484        let schema = table_schema_simple();
1485        let expr = !Reference::new("bar").less_than(Datum::int(10));
1486        let bound_expr = expr.bind(schema, true).unwrap();
1487        assert_eq!(&format!("{bound_expr}"), "NOT (bar < 10)");
1488        test_bound_predicate_serialize_diserialize(bound_expr);
1489    }
1490
1491    #[test]
1492    fn test_bind_not_always_true() {
1493        let schema = table_schema_simple();
1494        let expr = !Reference::new("bar").is_not_null();
1495        let bound_expr = expr.bind(schema, true).unwrap();
1496        assert_eq!(&format!("{bound_expr}"), "False");
1497        test_bound_predicate_serialize_diserialize(bound_expr);
1498    }
1499
1500    #[test]
1501    fn test_bind_not_always_false() {
1502        let schema = table_schema_simple();
1503        let expr = !Reference::new("bar").is_null();
1504        let bound_expr = expr.bind(schema, true).unwrap();
1505        assert_eq!(&format!("{bound_expr}"), r#"True"#);
1506        test_bound_predicate_serialize_diserialize(bound_expr);
1507    }
1508
1509    #[test]
1510    fn test_bound_predicate_rewrite_not_binary() {
1511        let schema = table_schema_simple();
1512
1513        // Test NOT elimination on binary predicates: NOT(bar < 10) => bar >= 10
1514        let predicate = Reference::new("bar").less_than(Datum::int(10)).not();
1515        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1516        let result = bound_predicate.rewrite_not();
1517
1518        // The result should be bar >= 10
1519        let expected_predicate = Reference::new("bar").greater_than_or_equal_to(Datum::int(10));
1520        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1521
1522        assert_eq!(result, expected_bound);
1523        assert_eq!(&format!("{result}"), "bar >= 10");
1524    }
1525
1526    #[test]
1527    fn test_bound_predicate_rewrite_not_unary() {
1528        let schema = table_schema_simple();
1529
1530        // Test NOT elimination on unary predicates: NOT(foo IS NULL) => foo IS NOT NULL
1531        let predicate = Reference::new("foo").is_null().not();
1532        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1533        let result = bound_predicate.rewrite_not();
1534
1535        // The result should be foo IS NOT NULL
1536        let expected_predicate = Reference::new("foo").is_not_null();
1537        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1538
1539        assert_eq!(result, expected_bound);
1540        assert_eq!(&format!("{result}"), "foo IS NOT NULL");
1541    }
1542
1543    #[test]
1544    fn test_bound_predicate_rewrite_not_set() {
1545        let schema = table_schema_simple();
1546
1547        // Test NOT elimination on set predicates: NOT(bar IN (10, 20)) => bar NOT IN (10, 20)
1548        let predicate = Reference::new("bar")
1549            .is_in([Datum::int(10), Datum::int(20)])
1550            .not();
1551        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1552        let result = bound_predicate.rewrite_not();
1553
1554        // The result should be bar NOT IN (10, 20)
1555        let expected_predicate = Reference::new("bar").is_not_in([Datum::int(10), Datum::int(20)]);
1556        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1557
1558        assert_eq!(result, expected_bound);
1559        // Note: HashSet order may vary, so we check that it contains the expected format
1560        let result_str = format!("{result}");
1561        assert!(
1562            result_str.contains("bar NOT IN")
1563                && result_str.contains("10")
1564                && result_str.contains("20")
1565        );
1566    }
1567
1568    #[test]
1569    fn test_bound_predicate_rewrite_not_and_demorgan() {
1570        let schema = table_schema_simple();
1571
1572        // Test De Morgan's law: NOT(A AND B) = (NOT A) OR (NOT B)
1573        // NOT((bar < 10) AND (foo IS NULL)) => (bar >= 10) OR (foo IS NOT NULL)
1574        let predicate = Reference::new("bar")
1575            .less_than(Datum::int(10))
1576            .and(Reference::new("foo").is_null())
1577            .not();
1578
1579        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1580        let result = bound_predicate.rewrite_not();
1581
1582        // Expected: (bar >= 10) OR (foo IS NOT NULL)
1583        let expected_predicate = Reference::new("bar")
1584            .greater_than_or_equal_to(Datum::int(10))
1585            .or(Reference::new("foo").is_not_null());
1586
1587        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1588
1589        assert_eq!(result, expected_bound);
1590        assert_eq!(&format!("{result}"), "(bar >= 10) OR (foo IS NOT NULL)");
1591    }
1592
1593    #[test]
1594    fn test_bound_predicate_rewrite_not_or_demorgan() {
1595        let schema = table_schema_simple();
1596
1597        // Test De Morgan's law: NOT(A OR B) = (NOT A) AND (NOT B)
1598        // NOT((bar < 10) OR (foo IS NULL)) => (bar >= 10) AND (foo IS NOT NULL)
1599        let predicate = Reference::new("bar")
1600            .less_than(Datum::int(10))
1601            .or(Reference::new("foo").is_null())
1602            .not();
1603
1604        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1605        let result = bound_predicate.rewrite_not();
1606
1607        // Expected: (bar >= 10) AND (foo IS NOT NULL)
1608        let expected_predicate = Reference::new("bar")
1609            .greater_than_or_equal_to(Datum::int(10))
1610            .and(Reference::new("foo").is_not_null());
1611
1612        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1613
1614        assert_eq!(result, expected_bound);
1615        assert_eq!(&format!("{result}"), "(bar >= 10) AND (foo IS NOT NULL)");
1616    }
1617
1618    #[test]
1619    fn test_bound_predicate_rewrite_not_double_negative() {
1620        let schema = table_schema_simple();
1621
1622        // Test double negative elimination: NOT(NOT(bar < 10)) => bar < 10
1623        let predicate = Reference::new("bar").less_than(Datum::int(10)).not().not();
1624        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1625        let result = bound_predicate.rewrite_not();
1626
1627        // The result should be bar < 10 (original predicate)
1628        let expected_predicate = Reference::new("bar").less_than(Datum::int(10));
1629        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1630
1631        assert_eq!(result, expected_bound);
1632        assert_eq!(&format!("{result}"), "bar < 10");
1633    }
1634
1635    #[test]
1636    fn test_bound_predicate_rewrite_not_always_true_false() {
1637        let schema = table_schema_simple();
1638
1639        // Test NOT(AlwaysTrue) => AlwaysFalse
1640        let predicate = Reference::new("bar").is_not_null().not(); // This becomes NOT(AlwaysTrue) since bar is required
1641        let bound_predicate = predicate.bind(schema.clone(), true).unwrap();
1642        let result = bound_predicate.rewrite_not();
1643
1644        assert_eq!(result, BoundPredicate::AlwaysFalse);
1645        assert_eq!(&format!("{result}"), "False");
1646
1647        // Test NOT(AlwaysFalse) => AlwaysTrue
1648        let predicate2 = Reference::new("bar").is_null().not(); // This becomes NOT(AlwaysFalse) since bar is required
1649        let bound_predicate2 = predicate2.bind(schema, true).unwrap();
1650        let result2 = bound_predicate2.rewrite_not();
1651
1652        assert_eq!(result2, BoundPredicate::AlwaysTrue);
1653        assert_eq!(&format!("{result2}"), "True");
1654    }
1655
1656    #[test]
1657    fn test_bound_predicate_rewrite_not_complex_nested() {
1658        let schema = table_schema_simple();
1659
1660        // Test complex nested expression:
1661        // NOT(NOT((bar >= 10) AND (foo IS NOT NULL)) OR (bar < 5))
1662        // Should become: ((bar >= 10) AND (foo IS NOT NULL)) AND (bar >= 5)
1663        let inner_predicate = Reference::new("bar")
1664            .greater_than_or_equal_to(Datum::int(10))
1665            .and(Reference::new("foo").is_not_null())
1666            .not();
1667
1668        let complex_predicate = inner_predicate
1669            .or(Reference::new("bar").less_than(Datum::int(5)))
1670            .not();
1671
1672        let bound_predicate = complex_predicate.bind(schema.clone(), true).unwrap();
1673        let result = bound_predicate.rewrite_not();
1674
1675        // Expected: ((bar >= 10) AND (foo IS NOT NULL)) AND (bar >= 5)
1676        // This is because NOT(NOT(A) OR B) = A AND NOT(B)
1677        let expected_predicate = Reference::new("bar")
1678            .greater_than_or_equal_to(Datum::int(10))
1679            .and(Reference::new("foo").is_not_null())
1680            .and(Reference::new("bar").greater_than_or_equal_to(Datum::int(5)));
1681
1682        let expected_bound = expected_predicate.bind(schema, true).unwrap();
1683
1684        assert_eq!(result, expected_bound);
1685        assert_eq!(
1686            &format!("{result}"),
1687            "((bar >= 10) AND (foo IS NOT NULL)) AND (bar >= 5)"
1688        );
1689    }
1690}