rdf_fusion_functions/scalar/terms/
str.rs

1use crate::scalar::dispatch::dispatch_unary_owned_typed_value;
2use crate::scalar::sparql_op_impl::{
3    ScalarSparqlOpImpl, create_plain_term_sparql_op_impl,
4    create_typed_value_sparql_op_impl,
5};
6use crate::scalar::{ScalarSparqlOp, ScalarSparqlOpSignature, SparqlOpArity};
7use datafusion::arrow::array::{Array, StringArray, UInt8Array};
8use datafusion::logical_expr::ColumnarValue;
9use itertools::repeat_n;
10use rdf_fusion_encoding::plain_term::{
11    PlainTermArray, PlainTermArrayBuilder, PlainTermEncoding, PlainTermEncodingField,
12    PlainTermType,
13};
14use rdf_fusion_encoding::typed_value::TypedValueEncoding;
15use rdf_fusion_encoding::{EncodingArray, EncodingDatum, EncodingScalar};
16use rdf_fusion_extensions::functions::BuiltinName;
17use rdf_fusion_extensions::functions::FunctionName;
18use rdf_fusion_model::ThinError;
19use rdf_fusion_model::vocab::xsd;
20use rdf_fusion_model::{SimpleLiteral, TypedValue, TypedValueRef};
21use std::sync::Arc;
22
23#[derive(Debug, Hash, PartialEq, Eq)]
24pub struct StrSparqlOp;
25
26impl Default for StrSparqlOp {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl StrSparqlOp {
33    const NAME: FunctionName = FunctionName::Builtin(BuiltinName::Str);
34
35    pub fn new() -> Self {
36        Self {}
37    }
38}
39
40impl ScalarSparqlOp for StrSparqlOp {
41    fn name(&self) -> &FunctionName {
42        &Self::NAME
43    }
44
45    fn signature(&self) -> ScalarSparqlOpSignature {
46        ScalarSparqlOpSignature::default_with_arity(SparqlOpArity::Fixed(1))
47    }
48
49    fn typed_value_encoding_op(
50        &self,
51    ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
52        Some(create_typed_value_sparql_op_impl(|args| {
53            dispatch_unary_owned_typed_value(
54                &args.args[0],
55                |value| {
56                    let converted = match value {
57                        TypedValueRef::NamedNode(value) => value.as_str().to_owned(),
58                        TypedValueRef::BlankNode(value) => value.as_str().to_owned(),
59                        TypedValueRef::BooleanLiteral(value) => value.to_string(),
60                        TypedValueRef::NumericLiteral(value) => value.format_value(),
61                        TypedValueRef::SimpleLiteral(value) => value.value.to_owned(),
62                        TypedValueRef::LanguageStringLiteral(value) => {
63                            value.value.to_owned()
64                        }
65                        TypedValueRef::DateTimeLiteral(value) => value.to_string(),
66                        TypedValueRef::TimeLiteral(value) => value.to_string(),
67                        TypedValueRef::DateLiteral(value) => value.to_string(),
68                        TypedValueRef::DurationLiteral(value) => value.to_string(),
69                        TypedValueRef::YearMonthDurationLiteral(value) => {
70                            value.to_string()
71                        }
72                        TypedValueRef::DayTimeDurationLiteral(value) => value.to_string(),
73                        TypedValueRef::OtherLiteral(value) => value.value().to_owned(),
74                    };
75                    Ok(TypedValue::SimpleLiteral(SimpleLiteral {
76                        value: converted,
77                    }))
78                },
79                ThinError::expected,
80            )
81        }))
82    }
83
84    fn plain_term_encoding_op(
85        &self,
86    ) -> Option<Box<dyn ScalarSparqlOpImpl<PlainTermEncoding>>> {
87        Some(create_plain_term_sparql_op_impl(|args| {
88            match &args.args[0] {
89                EncodingDatum::Array(array) => Ok(ColumnarValue::Array(
90                    impl_str_plain_term(array).into_array(),
91                )),
92                EncodingDatum::Scalar(scalar, _) => {
93                    let array = scalar.to_array(1)?;
94                    impl_str_plain_term(&array)
95                        .try_as_scalar(0)
96                        .map(|scalar| ColumnarValue::Scalar(scalar.into_scalar_value()))
97                }
98            }
99        }))
100    }
101}
102
103fn impl_str_plain_term(array: &PlainTermArray) -> PlainTermArray {
104    let parts = array.as_parts();
105
106    let value = Arc::clone(
107        parts
108            .struct_array
109            .column(PlainTermEncodingField::Value.index()),
110    );
111
112    let term_types_data =
113        UInt8Array::from_iter(repeat_n(u8::from(PlainTermType::Literal), value.len()))
114            .to_data()
115            .into_builder()
116            .nulls(value.nulls().cloned())
117            .build()
118            .unwrap();
119    let term_types = UInt8Array::from(term_types_data);
120
121    let data_types_data =
122        StringArray::from_iter_values(repeat_n(xsd::STRING.as_str(), value.len()))
123            .to_data()
124            .into_builder()
125            .nulls(value.nulls().cloned())
126            .build()
127            .unwrap();
128    let data_types = StringArray::from(data_types_data);
129
130    PlainTermArrayBuilder::new(Arc::new(term_types), value)
131        .with_data_types(Arc::new(data_types))
132        .finish()
133}