rdf_fusion_functions/scalar/strings/
str_after.rs

1use crate::scalar::dispatch::dispatch_binary_typed_value;
2use crate::scalar::sparql_op_impl::{
3    ScalarSparqlOpImpl, create_typed_value_sparql_op_impl,
4};
5use crate::scalar::{ScalarSparqlOp, ScalarSparqlOpSignature, SparqlOpArity};
6use rdf_fusion_encoding::typed_value::TypedValueEncoding;
7use rdf_fusion_extensions::functions::BuiltinName;
8use rdf_fusion_extensions::functions::FunctionName;
9use rdf_fusion_model::{
10    CompatibleStringArgs, LanguageStringRef, SimpleLiteralRef, StringLiteralRef,
11    ThinError, TypedValueRef,
12};
13
14/// Implementation of the SPARQL `strafter` function.
15#[derive(Debug, Hash, PartialEq, Eq)]
16pub struct StrAfterSparqlOp;
17
18impl Default for StrAfterSparqlOp {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl StrAfterSparqlOp {
25    const NAME: FunctionName = FunctionName::Builtin(BuiltinName::StrAfter);
26
27    /// Creates a new [StrAfterSparqlOp].
28    pub fn new() -> Self {
29        Self {}
30    }
31}
32
33impl ScalarSparqlOp for StrAfterSparqlOp {
34    fn name(&self) -> &FunctionName {
35        &Self::NAME
36    }
37
38    fn signature(&self) -> ScalarSparqlOpSignature {
39        ScalarSparqlOpSignature::default_with_arity(SparqlOpArity::Fixed(2))
40    }
41
42    fn typed_value_encoding_op(
43        &self,
44    ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
45        Some(create_typed_value_sparql_op_impl(|args| {
46            dispatch_binary_typed_value(
47                &args.args[0],
48                &args.args[1],
49                |lhs_value, rhs_value| {
50                    let lhs_value = StringLiteralRef::try_from(lhs_value)?;
51                    let rhs_value = StringLiteralRef::try_from(rhs_value)?;
52
53                    let args = CompatibleStringArgs::try_from(lhs_value, rhs_value)?;
54
55                    let value = if let Some(position) = args.lhs.find(args.rhs) {
56                        let start = position + args.rhs.len();
57                        &args.lhs[start..]
58                    } else {
59                        return Ok(TypedValueRef::SimpleLiteral(SimpleLiteralRef {
60                            value: "",
61                        }));
62                    };
63
64                    Ok(match args.language {
65                        None => TypedValueRef::SimpleLiteral(SimpleLiteralRef { value }),
66                        Some(language) => {
67                            TypedValueRef::LanguageStringLiteral(LanguageStringRef {
68                                value,
69                                language,
70                            })
71                        }
72                    })
73                },
74                |_, _| ThinError::expected(),
75            )
76        }))
77    }
78}