Skip to content

Commit

Permalink
implement SPARQL functions UCASE and LCASE
Browse files Browse the repository at this point in the history
  • Loading branch information
pchampin committed Dec 9, 2024
1 parent 2a9f0e8 commit 501f0df
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
24 changes: 22 additions & 2 deletions sparql/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,18 @@ pub fn call_function(function: &Function, mut arguments: Vec<EvalResult>) -> Opt
Some(str_len(string.as_string_lit()?.0))
}
Replace => todo("Replace"),
UCase => todo("UCase"),
LCase => todo("LCase"),
UCase => {
let [string] = &arguments[..] else {
unreachable!();
};
Some(u_case(string.as_string_lit()?))
}
LCase => {
let [string] = &arguments[..] else {
unreachable!();
};
Some(l_case(string.as_string_lit()?))
}
EncodeForUri => todo("EncodeForUri"),
Contains => todo("Contains"),
StrStarts => todo("StrStarts"),
Expand Down Expand Up @@ -329,6 +339,16 @@ pub fn str_len(string: &Arc<str>) -> EvalResult {
}
}

pub fn u_case(source: (&Arc<str>, Option<&LanguageTag<Arc<str>>>)) -> EvalResult {
let lex: String = source.0.chars().flat_map(char::to_uppercase).collect();
EvalResult::from((Arc::from(lex), source.1.cloned()))
}

pub fn l_case(source: (&Arc<str>, Option<&LanguageTag<Arc<str>>>)) -> EvalResult {
let lex: String = source.0.chars().flat_map(char::to_lowercase).collect();
EvalResult::from((Arc::from(lex), source.1.cloned()))
}

pub fn triple(s: &EvalResult, p: &EvalResult, o: &EvalResult) -> Option<EvalResult> {
let EvalResult::Term(s) = s else { return None };
let EvalResult::Term(p) = p else { return None };
Expand Down
35 changes: 34 additions & 1 deletion sparql/src/function/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,45 @@ fn sub_str(source: &str, start: f64, length: Option<f64>, exp: Option<&str>) ->
fn str_len(string: &str, exp: isize) -> TestResult {
let pair = txt2pair(string);
let string = &pair.0;
let source = (&pair.0, pair.1.as_ref());
let exp = EvalResult::from(SparqlNumber::from(exp));
assert!(eval_eq(Some(super::str_len(string)), Some(exp)));
Ok(())
}

#[test_case("foo", "FOO")]
#[test_case("foo@en", "FOO@en")]
#[test_case("FOO", "FOO"; "noop")]
#[test_case("FOO@en", "FOO@en"; "noop en")]
#[test_case("fooBAR 1!xY", "FOOBAR 1!XY")]
#[test_case("fooBAR 1!xY@en", "FOOBAR 1!XY@en")]
#[test_case("àéîôù", "ÀÉÎÔÙ"; "accents")]
#[test_case("àéîôù@fr", "ÀÉÎÔÙ@fr"; "accents fr")]
#[test_case("ff ʼn", "FF ʼN"; "multichar")]
#[test_case("ff ʼn@en", "FF ʼN@en"; "multichar en")]
fn u_case(string: &str, exp: &str) -> TestResult {
let pair = txt2pair(string);
let source = (&pair.0, pair.1.as_ref());
let exp = EvalResult::from(txt2pair(exp));
assert!(eval_eq(Some(super::u_case(source)), Some(exp)));
Ok(())
}

#[test_case("FOO", "foo")]
#[test_case("FOO@en", "foo@en")]
#[test_case("foo", "foo"; "noop")]
#[test_case("foo@en", "foo@en"; "noop en")]
#[test_case("fooBAR 1!xY", "foobar 1!xy")]
#[test_case("fooBAR 1!xY@en", "foobar 1!xy@en")]
#[test_case("ÀÉÎÔÙ", "àéîôù"; "accents")]
#[test_case("ÀÉÎÔÙ@fr", "àéîôù@fr"; "accents fr")]
fn l_case(string: &str, exp: &str) -> TestResult {
let pair = txt2pair(string);
let source = (&pair.0, pair.1.as_ref());
let exp = EvalResult::from(txt2pair(exp));
assert!(eval_eq(Some(super::l_case(source)), Some(exp)));
Ok(())
}

#[test_case("<tag:s>", "<tag:p>", "<tag:o>", true)]
#[test_case("<tag:s>", "<tag:p>", "bnode()", true)]
#[test_case("<tag:s>", "<tag:p>", " \"o\" ", true)]
Expand Down
15 changes: 15 additions & 0 deletions sparql/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,21 @@ fn test_expr_variable() -> TestResult {
#[test_case("strLen(\"foobar\"@en)", "6"; "strLen for language string")]
#[test_case("strLen(42)", ""; "strLen for number")]
#[test_case("strLen(<< <tag:s> <tag:p> <tag:o> >>)", ""; "strLen for triple")]
// TODO test replace
// test uCase
#[test_case("uCase(<tag:x>)", ""; "uCase for IRI")]
#[test_case("uCase(bnode())", ""; "uCase for bnode")]
#[test_case("uCase(\"fooBAR\")", "\"FOOBAR\""; "uCase for string")]
#[test_case("uCase(\"fooBAR\"@en)", "\"FOOBAR\"@en"; "uCase for language string")]
#[test_case("uCase(42)", ""; "uCase for number")]
#[test_case("uCase(<< <tag:s> <tag:p> <tag:o> >>)", ""; "uCase for triple")]
// test lCase
#[test_case("lCase(<tag:x>)", ""; "lCase for IRI")]
#[test_case("lCase(bnode())", ""; "lCase for bnode")]
#[test_case("lCase(\"fooBAR\")", "\"foobar\""; "lCase for string")]
#[test_case("lCase(\"fooBAR\"@en)", "\"foobar\"@en"; "lCase for language string")]
#[test_case("lCase(42)", ""; "lCase for number")]
#[test_case("lCase(<< <tag:s> <tag:p> <tag:o> >>)", ""; "lCase for triple")]
// TODO test other function calls
// test isIri
#[test_case("isIri(<tag:x>)", "true"; "isIri for IRI")]
Expand Down

0 comments on commit 501f0df

Please sign in to comment.