rdf_fusion_functions/builtin/native/
effective_boolean_value.rs

1use datafusion::arrow::array::BooleanArray;
2use datafusion::arrow::datatypes::DataType;
3use datafusion::common::{ScalarValue, exec_err};
4use datafusion::logical_expr::{
5    ColumnarValue, ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Signature,
6    TypeSignature, Volatility,
7};
8use rdf_fusion_encoding::typed_value::decoders::DefaultTypedValueDecoder;
9use rdf_fusion_encoding::typed_value::{TYPED_VALUE_ENCODING, TypedValueArray};
10use rdf_fusion_encoding::{TermDecoder, TermEncoding};
11use rdf_fusion_extensions::functions::BuiltinName;
12use rdf_fusion_model::DFResult;
13use rdf_fusion_model::{
14    Decimal, Double, Float, Int, Integer, Numeric, ThinError, ThinResult, TypedValueRef,
15};
16use std::any::Any;
17use std::hash::{Hash, Hasher};
18use std::sync::Arc;
19
20pub fn effective_boolean_value() -> ScalarUDF {
21    let udf_impl = EffectiveBooleanValue::new();
22    ScalarUDF::new_from_impl(udf_impl)
23}
24
25#[derive(Debug, Eq)]
26struct EffectiveBooleanValue {
27    name: String,
28    signature: Signature,
29}
30
31impl EffectiveBooleanValue {
32    /// Creates a new [EffectiveBooleanValue].
33    pub fn new() -> Self {
34        Self {
35            name: BuiltinName::EffectiveBooleanValue.to_string(),
36            signature: Signature::new(
37                TypeSignature::Exact(vec![TYPED_VALUE_ENCODING.data_type()]),
38                Volatility::Immutable,
39            ),
40        }
41    }
42}
43
44impl ScalarUDFImpl for EffectiveBooleanValue {
45    fn as_any(&self) -> &dyn Any {
46        self
47    }
48
49    fn name(&self) -> &str {
50        &self.name
51    }
52
53    fn signature(&self) -> &Signature {
54        &self.signature
55    }
56
57    fn return_type(&self, _arg_types: &[DataType]) -> DFResult<DataType> {
58        Ok(DataType::Boolean)
59    }
60
61    fn invoke_with_args(
62        &self,
63        args: ScalarFunctionArgs,
64    ) -> datafusion::common::Result<ColumnarValue> {
65        match TryInto::<[_; 1]>::try_into(args.args) {
66            Ok([ColumnarValue::Array(array)]) => {
67                let array = TYPED_VALUE_ENCODING.try_new_array(array)?;
68                let result = ebv(&array);
69                Ok(ColumnarValue::Array(Arc::new(result)))
70            }
71            Ok([ColumnarValue::Scalar(scalar)]) => {
72                let scalar = TYPED_VALUE_ENCODING.try_new_scalar(scalar)?;
73                let result = DefaultTypedValueDecoder::decode_term(&scalar)
74                    .and_then(evaluate)
75                    .ok();
76                Ok(ColumnarValue::Scalar(ScalarValue::Boolean(result)))
77            }
78            _ => exec_err!("Unexpected number of arguments"),
79        }
80    }
81}
82
83impl Hash for EffectiveBooleanValue {
84    fn hash<H: Hasher>(&self, state: &mut H) {
85        self.as_any().type_id().hash(state);
86    }
87}
88
89impl PartialEq for EffectiveBooleanValue {
90    fn eq(&self, other: &Self) -> bool {
91        self.as_any().type_id() == other.as_any().type_id()
92    }
93}
94
95/// Calculates the effective boolean value (EBV) from `array`.
96pub fn ebv(array: &TypedValueArray) -> BooleanArray {
97    DefaultTypedValueDecoder::decode_terms(array)
98        .map(|res| res.and_then(evaluate).ok())
99        .collect::<BooleanArray>()
100}
101
102fn evaluate(value: TypedValueRef<'_>) -> ThinResult<bool> {
103    let result = match value {
104        TypedValueRef::BooleanLiteral(value) => value.as_bool(),
105        TypedValueRef::NumericLiteral(value) => match value {
106            Numeric::Int(value) => value != Int::from(0),
107            Numeric::Integer(value) => value != Integer::from(0),
108            Numeric::Float(value) => value != Float::from(0_f32),
109            Numeric::Double(value) => value != Double::from(0_f64),
110            Numeric::Decimal(value) => value != Decimal::from(0),
111        },
112        TypedValueRef::SimpleLiteral(value) => !value.is_empty(),
113        _ => return ThinError::expected(),
114    };
115    Ok(result)
116}