2026-08-20 21:27:38 -04:00
|
|
|
use std::env::var;
|
2026-08-20 20:43:18 -04:00
|
|
|
use oxigraph::model::{Literal, TermRef};
|
2026-07-01 17:42:23 -04:00
|
|
|
use oxilangtag::LanguageTag;
|
2026-08-08 23:50:04 -04:00
|
|
|
use std::sync::LazyLock;
|
2026-08-20 20:43:18 -04:00
|
|
|
use spargebra::algebra::{Expression, Function, GraphPattern};
|
|
|
|
|
use spargebra::term::{NamedNode, NamedNodePattern, TermPattern, TriplePattern, Variable};
|
|
|
|
|
use tracing::debug;
|
2026-07-01 17:42:23 -04:00
|
|
|
|
2026-08-24 21:44:23 -04:00
|
|
|
pub static ENGLISH_TAG: LazyLock<LanguageTag<String>> = LazyLock::new(|| {
|
|
|
|
|
LanguageTag::parse("en".to_string()).unwrap()
|
|
|
|
|
});
|
2026-07-01 17:42:23 -04:00
|
|
|
|
|
|
|
|
pub static ENGLISH_OR_UNTAGGED: LazyLock<LanguageCondition> = LazyLock::new(|| {
|
2026-08-24 21:44:23 -04:00
|
|
|
LanguageCondition::ExactMatchOrUntagged(ENGLISH_TAG.clone())
|
2026-07-01 17:42:23 -04:00
|
|
|
});
|
|
|
|
|
|
2026-08-20 20:43:18 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2026-07-01 17:42:23 -04:00
|
|
|
pub enum LanguageCondition {
|
|
|
|
|
ExactMatchOnly(LanguageTag<String>),
|
|
|
|
|
ExactMatchOrUntagged(LanguageTag<String>),
|
|
|
|
|
UntaggedOnly,
|
|
|
|
|
AnyOrNone,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LanguageCondition {
|
2026-08-05 11:21:25 -04:00
|
|
|
pub fn primary_matches_term<'a>(&self, term: impl Into<TermRef<'a>>) -> bool {
|
|
|
|
|
if let TermRef::Literal(literal) = term.into() {
|
2026-08-08 23:50:04 -04:00
|
|
|
let tag = literal
|
|
|
|
|
.language()
|
2026-07-01 17:42:23 -04:00
|
|
|
.map(LanguageTag::parse_and_normalize)
|
|
|
|
|
.and_then(Result::ok);
|
|
|
|
|
|
|
|
|
|
match (tag, self) {
|
2026-08-08 23:50:04 -04:00
|
|
|
(Some(language), LanguageCondition::ExactMatchOnly(expectation))
|
|
|
|
|
| (Some(language), LanguageCondition::ExactMatchOrUntagged(expectation)) => {
|
|
|
|
|
language.primary_language() == expectation.primary_language()
|
|
|
|
|
}
|
2026-07-01 17:42:23 -04:00
|
|
|
(None, LanguageCondition::ExactMatchOrUntagged(_)) => true,
|
|
|
|
|
(None, LanguageCondition::UntaggedOnly) => true,
|
|
|
|
|
(_, LanguageCondition::AnyOrNone) => true,
|
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-05 11:21:25 -04:00
|
|
|
pub fn primary_language(&self) -> Option<&str> {
|
|
|
|
|
match self {
|
|
|
|
|
LanguageCondition::ExactMatchOnly(tag) => Some(tag.primary_language()),
|
|
|
|
|
LanguageCondition::ExactMatchOrUntagged(tag) => Some(tag.primary_language()),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-22 23:31:14 -04:00
|
|
|
pub fn filter(&self, variable: impl Into<String>) -> String {
|
|
|
|
|
let variable = variable.into();
|
|
|
|
|
|
|
|
|
|
let exact = |language: &LanguageTag<String>| Expression::FunctionCall(
|
2026-08-20 20:43:18 -04:00
|
|
|
Function::LangMatches, vec![
|
|
|
|
|
Expression::FunctionCall(Function::Lang, vec![
|
2026-08-22 23:31:14 -04:00
|
|
|
Expression::Variable(Variable::new_unchecked(&variable))
|
2026-08-20 20:43:18 -04:00
|
|
|
]),
|
2026-08-22 23:31:14 -04:00
|
|
|
Expression::Literal(Literal::new_simple_literal(language.to_string()))
|
2026-08-20 20:43:18 -04:00
|
|
|
],
|
|
|
|
|
);
|
2026-08-22 23:31:14 -04:00
|
|
|
|
|
|
|
|
let untagged = Expression::Not(
|
2026-08-20 20:43:18 -04:00
|
|
|
Box::new(Expression::FunctionCall(Function::HasLang, vec![
|
2026-08-22 23:31:14 -04:00
|
|
|
Expression::Variable(Variable::new_unchecked(&variable))
|
2026-08-20 20:43:18 -04:00
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
|
2026-08-22 23:31:14 -04:00
|
|
|
match self {
|
|
|
|
|
Self::ExactMatchOnly(language) => Some(exact(language)),
|
|
|
|
|
Self::ExactMatchOrUntagged(language) => Some(Expression::Or(
|
|
|
|
|
Box::new(exact(language)),
|
|
|
|
|
Box::new(untagged),
|
|
|
|
|
)),
|
|
|
|
|
Self::UntaggedOnly => Some(untagged),
|
|
|
|
|
Self::AnyOrNone => None,
|
|
|
|
|
}.map(|expr| GraphPattern::Filter {
|
|
|
|
|
expr,
|
|
|
|
|
inner: Box::new(GraphPattern::Bgp { patterns: vec![] }),
|
|
|
|
|
}.to_string()).unwrap_or_default()
|
2026-07-01 17:42:23 -04:00
|
|
|
}
|
2026-08-08 23:50:04 -04:00
|
|
|
}
|