## Coverage Report

#### Created: 2024-10-13 08:39

    /Users/andrewlamb/Software/datafusion/datafusion/physical-expr/src/expressions/not.rs

    Line
    Count
    Source (jump to first uncovered line)
    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
    //! Not expression
    19
    20
    use std::any::Any;
    21
    use std::fmt;
    22
    use std::hash::{Hash, Hasher};
    23
    use std::sync::Arc;
    24
    25
    use crate::physical_expr::down_cast_any_ref;
    26
    use crate::PhysicalExpr;
    27
    use arrow::datatypes::{DataType, Schema};
    28
    use arrow::record_batch::RecordBatch;
    29
    use datafusion_common::{cast::as_boolean_array, Result, ScalarValue};
    30
    use datafusion_expr::ColumnarValue;
    31
    32
    /// Not expression
    33
    #[derive(Debug, Hash)]
    34
    pub struct NotExpr {
    35
        /// Input expression
    36
        arg: Arc<dyn PhysicalExpr>,
    37
    }
    38
    39
    impl NotExpr {
    40
        /// Create new not expression
    41
    0
        pub fn new(arg: Arc<dyn PhysicalExpr>) -> Self {
    42
    0
            Self { arg }
    43
    0
        }
    44
    45
        /// Get the input expression
    46
    0
        pub fn arg(&self) -> &Arc<dyn PhysicalExpr> {
    47
    0
            &self.arg
    48
    0
        }
    49
    }
    50
    51
    impl fmt::Display for NotExpr {
    52
    0
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    53
    0
            write!(f, "NOT {}", self.arg)
    54
    0
        }
    55
    }
    56
    57
    impl PhysicalExpr for NotExpr {
    58
        /// Return a reference to Any that can be used for downcasting
    59
    0
        fn as_any(&self) -> &dyn Any {
    60
    0
            self
    61
    0
        }
    62
    63
    0
        fn data_type(&self, _input_schema: &Schema) -> Result<DataType> {
    64
    0
            Ok(DataType::Boolean)
    65
    0
        }
    66
    67
    0
        fn nullable(&self, input_schema: &Schema) -> Result<bool> {
    68
    0
            self.arg.nullable(input_schema)
    69
    0
        }
    70
    71
    0
        fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
    72
    0
            let evaluate_arg = self.arg.evaluate(batch)?;
    73
    0
            match evaluate_arg {
    74
    0
                ColumnarValue::Array(array) => {
    75
    0
                    let array = as_boolean_array(&array)?;
    76
                    Ok(ColumnarValue::Array(Arc::new(
    77
    0
                        arrow::compute::kernels::boolean::not(array)?,
    78
                    )))
    79
                }
    80
    0
                ColumnarValue::Scalar(scalar) => {
    81
    0
                    if scalar.is_null() {
    82
    0
                        return Ok(ColumnarValue::Scalar(ScalarValue::Boolean(None)));
    83
    0
                    }
    84
    0
                    let bool_value: bool = scalar.try_into()?;
    85
    0
                    Ok(ColumnarValue::Scalar(ScalarValue::Boolean(Some(
    86
    0
                        !bool_value,
    87
    0
                    ))))
    88
                }
    89
            }
    90
    0
        }
    91
    92
    0
        fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {
    93
    0
            vec![&self.arg]
    94
    0
        }
    95
    96
    0
        fn with_new_children(
    97
    0
            self: Arc<Self>,
    98
    0
            children: Vec<Arc<dyn PhysicalExpr>>,
    99
    0
        ) -> Result<Arc<dyn PhysicalExpr>> {
    100
    0
            Ok(Arc::new(NotExpr::new(Arc::clone(&children[0]))))
    101
    0
        }
    102
    103
    0
        fn dyn_hash(&self, state: &mut dyn Hasher) {
    104
    0
            let mut s = state;
    105
    0
            self.hash(&mut s);
    106
    0
        }
    107
    }
    108
    109
    impl PartialEq<dyn Any> for NotExpr {
    110
    0
        fn eq(&self, other: &dyn Any) -> bool {
    111
    0
            down_cast_any_ref(other)
    112
    0
                .downcast_ref::<Self>()
    113
    0
                .map(|x| self.arg.eq(&x.arg))
    114
    0
                .unwrap_or(false)
    115
    0
        }
    116
    }
    117
    118
    /// Creates a unary expression NOT
    119
    0
    pub fn not(arg: Arc<dyn PhysicalExpr>) -> Result<Arc<dyn PhysicalExpr>> {
    120
    0
        Ok(Arc::new(NotExpr::new(arg)))
    121
    0
    }
    122
    123
    #[cfg(test)]
    124
    mod tests {
    125
        use super::*;
    126
        use crate::expressions::col;
    127
        use arrow::{array::BooleanArray, datatypes::*};
    128
    129
        #[test]
    130
        fn neg_op() -> Result<()> {
    131
            let schema = Schema::new(vec![Field::new("a", DataType::Boolean, true)]);
    132
    133
            let expr = not(col("a", &schema)?)?;
    134
            assert_eq!(expr.data_type(&schema)?, DataType::Boolean);
    135
            assert!(expr.nullable(&schema)?);
    136
    137
            let input = BooleanArray::from(vec![Some(true), None, Some(false)]);
    138
            let expected = &BooleanArray::from(vec![Some(false), None, Some(true)]);
    139
    140
            let batch =
    141
                RecordBatch::try_new(Arc::new(schema.clone()), vec![Arc::new(input)])?;
    142
    143
            let result = expr
    144
                .evaluate(&batch)?
    145
                .into_array(batch.num_rows())
    146
                .expect("Failed to convert to array");
    147
            let result =
    148
                as_boolean_array(&result).expect("failed to downcast to BooleanArray");
    149
            assert_eq!(result, expected);
    150
    151
            Ok(())
    152
        }
    153
    }