rdf_fusion_functions/builtin/native/
effective_boolean_value.rs1use 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 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
95pub 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}