rdf_fusion_functions/scalar/terms/
iri.rs1use 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}