rdf_fusion_functions/scalar/functional_form/
bound.rs

1use crate::scalar::sparql_op_impl::{ClosureSparqlOpImpl, ScalarSparqlOpImpl};
2use crate::scalar::{ScalarSparqlOp, ScalarSparqlOpSignature, SparqlOpArity};
3use datafusion::arrow::array::Array;
4use datafusion::arrow::compute::is_not_null;
5use datafusion::logical_expr::ColumnarValue;
6use rdf_fusion_encoding::object_id::ObjectIdEncoding;
7use rdf_fusion_encoding::plain_term::PlainTermEncoding;
8use rdf_fusion_encoding::typed_value::{
9    TYPED_VALUE_ENCODING, TypedValueArray, TypedValueArrayBuilder, TypedValueEncoding,
10};
11use rdf_fusion_encoding::{EncodingArray, EncodingDatum, EncodingScalar, TermEncoding};
12use rdf_fusion_extensions::functions::BuiltinName;
13use rdf_fusion_extensions::functions::FunctionName;
14use rdf_fusion_model::DFResult;
15
16#[derive(Debug, Hash, PartialEq, Eq)]
17pub struct BoundSparqlOp;
18
19impl Default for BoundSparqlOp {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl BoundSparqlOp {
26    const NAME: FunctionName = FunctionName::Builtin(BuiltinName::Bound);
27
28    pub fn new() -> Self {
29        Self {}
30    }
31}
32
33impl ScalarSparqlOp for BoundSparqlOp {
34    fn name(&self) -> &FunctionName {
35        &Self::NAME
36    }
37
38    fn signature(&self) -> ScalarSparqlOpSignature {
39        ScalarSparqlOpSignature::default_with_arity(SparqlOpArity::Fixed(1))
40    }
41
42    fn plain_term_encoding_op(
43        &self,
44    ) -> Option<Box<dyn ScalarSparqlOpImpl<PlainTermEncoding>>> {
45        Some(Box::new(ClosureSparqlOpImpl::new(
46            TYPED_VALUE_ENCODING.data_type(),
47            |args| impl_bound_plain_term(&args.args[0]),
48        )))
49    }
50
51    fn typed_value_encoding_op(
52        &self,
53    ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
54        Some(Box::new(ClosureSparqlOpImpl::new(
55            TYPED_VALUE_ENCODING.data_type(),
56            |args| impl_bound_typed_value(&args.args[0]),
57        )))
58    }
59
60    fn object_id_encoding_op(
61        &self,
62        _object_id_encoding: &ObjectIdEncoding,
63    ) -> Option<Box<dyn ScalarSparqlOpImpl<ObjectIdEncoding>>> {
64        Some(Box::new(ClosureSparqlOpImpl::<ObjectIdEncoding>::new(
65            TYPED_VALUE_ENCODING.data_type(),
66            |args| impl_bound_object_id(&args.args[0]),
67        )))
68    }
69}
70
71fn impl_bound_plain_term(
72    array: &EncodingDatum<PlainTermEncoding>,
73) -> DFResult<ColumnarValue> {
74    match array {
75        EncodingDatum::Array(array) => impl_bound_array(array.array().as_ref())
76            .map(|array| ColumnarValue::Array(array.into_array())),
77        EncodingDatum::Scalar(scalar, _) => {
78            let array = scalar.to_array(1)?.into_array();
79            impl_bound_array(array.as_ref())?
80                .try_as_scalar(0)
81                .map(|scalar| ColumnarValue::Scalar(scalar.into_scalar_value()))
82        }
83    }
84}
85
86fn impl_bound_typed_value(
87    array: &EncodingDatum<TypedValueEncoding>,
88) -> DFResult<ColumnarValue> {
89    match array {
90        EncodingDatum::Array(array) => impl_bound_array(array.array().as_ref())
91            .map(|array| ColumnarValue::Array(array.into_array())),
92        EncodingDatum::Scalar(scalar, _) => {
93            let array = scalar.to_array(1)?.into_array();
94            impl_bound_array(array.as_ref())?
95                .try_as_scalar(0)
96                .map(|scalar| ColumnarValue::Scalar(scalar.into_scalar_value()))
97        }
98    }
99}
100
101fn impl_bound_object_id(
102    array: &EncodingDatum<ObjectIdEncoding>,
103) -> DFResult<ColumnarValue> {
104    match array {
105        EncodingDatum::Array(array) => impl_bound_array(array.array().as_ref())
106            .map(|array| ColumnarValue::Array(array.into_array())),
107        EncodingDatum::Scalar(scalar, _) => {
108            let array = scalar.to_array(1)?.into_array();
109            impl_bound_array(array.as_ref())?
110                .try_as_scalar(0)
111                .map(|scalar| ColumnarValue::Scalar(scalar.into_scalar_value()))
112        }
113    }
114}
115
116fn impl_bound_array(array: &dyn Array) -> DFResult<TypedValueArray> {
117    let result = is_not_null(array)?;
118    assert_eq!(
119        result.null_count(),
120        0,
121        "is_not_null should never return null"
122    );
123
124    let mut builder = TypedValueArrayBuilder::default();
125    for value in result.values() {
126        builder.append_boolean(value.into())?;
127    }
128
129    Ok(builder.finish())
130}