rdf_fusion_functions/scalar/terms/
iri.rs

1use crate::scalar::dispatch::dispatch_unary_owned_typed_value;
2use crate::scalar::sparql_op_impl::{
3    ScalarSparqlOpImpl, create_typed_value_sparql_op_impl,
4};
5use crate::scalar::{
6    ScalarSparqlOp, ScalarSparqlOpArgs, ScalarSparqlOpSignature, SparqlOpArity,
7};
8use datafusion::common::{exec_datafusion_err, exec_err};
9use datafusion::logical_expr::Volatility;
10use rdf_fusion_encoding::typed_value::TypedValueEncoding;
11use rdf_fusion_encoding::typed_value::decoders::DefaultTypedValueDecoder;
12use rdf_fusion_encoding::{EncodingDatum, TermDecoder};
13use rdf_fusion_extensions::functions::BuiltinName;
14use rdf_fusion_extensions::functions::FunctionName;
15use rdf_fusion_model::DFResult;
16use rdf_fusion_model::{Iri, NamedNode, ThinError, TypedValue, TypedValueRef};
17
18#[derive(Debug, Default, Hash, PartialEq, Eq)]
19pub struct IriSparqlOp;
20
21impl IriSparqlOp {
22    const NAME: FunctionName = FunctionName::Builtin(BuiltinName::Iri);
23
24    fn get_base_iri(
25        args: &ScalarSparqlOpArgs<TypedValueEncoding>,
26    ) -> DFResult<Option<Iri<String>>> {
27        match &args.args[1] {
28            EncodingDatum::Array(_) => {
29                exec_err!("IRI does not support a scalar base_iri")
30            }
31            EncodingDatum::Scalar(value, _) => {
32                let term = DefaultTypedValueDecoder::decode_term(value).ok();
33                term.map(|t| match t {
34                    TypedValueRef::SimpleLiteral(lit) => Iri::parse(lit.value.to_owned())
35                        .map_err(|_| exec_datafusion_err!("Invalid IRI: {}", lit.value)),
36                    _ => exec_err!("Unexpected typed value for base_iri."),
37                })
38                .transpose()
39            }
40        }
41    }
42}
43
44impl ScalarSparqlOp for IriSparqlOp {
45    fn name(&self) -> &FunctionName {
46        &Self::NAME
47    }
48
49    fn signature(&self) -> ScalarSparqlOpSignature {
50        ScalarSparqlOpSignature {
51            volatility: Volatility::Immutable,
52            arity: SparqlOpArity::Fixed(2),
53        }
54    }
55
56    fn typed_value_encoding_op(
57        &self,
58    ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
59        Some(create_typed_value_sparql_op_impl(move |args| {
60            let base_iri = Self::get_base_iri(&args)?;
61            dispatch_unary_owned_typed_value(
62                &args.args[0],
63                |value| match value {
64                    TypedValueRef::NamedNode(named_node) => {
65                        Ok(TypedValue::NamedNode(named_node.into_owned()))
66                    }
67                    TypedValueRef::SimpleLiteral(simple_literal) => {
68                        let resolving_result = if let Some(base_iri) = &base_iri {
69                            base_iri.resolve(simple_literal.value)?
70                        } else {
71                            Iri::parse(simple_literal.value.to_owned())?
72                        };
73                        Ok(TypedValue::NamedNode(NamedNode::from(resolving_result)))
74                    }
75                    _ => ThinError::expected(),
76                },
77                ThinError::expected,
78            )
79        }))
80    }
81}