rdf_fusion_functions/scalar/functional_form/
bound.rs1use 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}