From 8b5a99c321a475fd0f29a4823b0cd808ac8e3704 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Sun, 27 Nov 2022 11:05:33 +0000 Subject: [PATCH] Support negative offsets in SQL string::slice() function Closes #1490 --- lib/src/fnc/args.rs | 6 +++++ lib/src/fnc/string.rs | 14 +++++++++-- lib/tests/function.rs | 54 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/lib/src/fnc/args.rs b/lib/src/fnc/args.rs index 601c3c66..66118643 100644 --- a/lib/src/fnc/args.rs +++ b/lib/src/fnc/args.rs @@ -45,6 +45,12 @@ impl FromArg for i64 { } } +impl FromArg for isize { + fn from_arg(arg: Value) -> Result { + Ok(arg.as_int() as isize) + } +} + impl FromArg for usize { fn from_arg(arg: Value) -> Result { Ok(arg.as_int() as usize) diff --git a/lib/src/fnc/string.rs b/lib/src/fnc/string.rs index ac06cc38..e2d8969f 100644 --- a/lib/src/fnc/string.rs +++ b/lib/src/fnc/string.rs @@ -51,8 +51,18 @@ pub fn reverse((string,): (String,)) -> Result { Ok(string.chars().rev().collect::().into()) } -pub fn slice((val, beg, lim): (String, usize, usize)) -> Result { - Ok(val.chars().skip(beg).take(lim).collect::().into()) +pub fn slice((val, beg, lim): (String, Option, Option)) -> Result { + let val = match beg { + Some(v) if v < 0 => val.chars().skip(val.len() - v.unsigned_abs()).collect::(), + Some(v) => val.chars().skip(v as usize).collect::(), + None => val, + }; + let val = match lim { + Some(v) if v < 0 => val.chars().take(val.len() - v.unsigned_abs()).collect::(), + Some(v) => val.chars().take(v as usize).collect::(), + None => val, + }; + Ok(val.into()) } pub fn slug((string,): (String,)) -> Result { diff --git a/lib/tests/function.rs b/lib/tests/function.rs index 98c64bcb..f485efe2 100644 --- a/lib/tests/function.rs +++ b/lib/tests/function.rs @@ -6,12 +6,12 @@ use surrealdb::Error; use surrealdb::Session; #[tokio::test] -async fn array_distinct() -> Result<(), Error> { +async fn function_array_distinct() -> Result<(), Error> { let sql = r#" - SELECT * FROM array::distinct([1, 3, 2, 1, 3, 3, 4]); - SELECT * FROM array::distinct([]); - SELECT * FROM array::distinct("something"); - SELECT * FROM array::distinct(["something"]); + RETURN array::distinct([1, 3, 2, 1, 3, 3, 4]); + RETURN array::distinct([]); + RETURN array::distinct("something"); + RETURN array::distinct(["something"]); "#; let dbs = Datastore::new("memory").await?; let ses = Session::for_kv().with_ns("test").with_db("test"); @@ -27,7 +27,7 @@ async fn array_distinct() -> Result<(), Error> { assert_eq!(tmp, val); // let tmp = res.remove(0).result?; - let val = Value::parse("[NONE]"); + let val = Value::None; assert_eq!(tmp, val); // let tmp = res.remove(0).result?; @@ -36,3 +36,45 @@ async fn array_distinct() -> Result<(), Error> { // Ok(()) } + +#[tokio::test] +async fn function_string_slice() -> Result<(), Error> { + let sql = r#" + RETURN string::slice("the quick brown fox jumps over the lazy dog."); + RETURN string::slice("the quick brown fox jumps over the lazy dog.", 16); + RETURN string::slice("the quick brown fox jumps over the lazy dog.", 0, 60); + RETURN string::slice("the quick brown fox jumps over the lazy dog.", 0, -1); + RETURN string::slice("the quick brown fox jumps over the lazy dog.", 16, -1); + RETURN string::slice("the quick brown fox jumps over the lazy dog.", -9, -1); + "#; + let dbs = Datastore::new("memory").await?; + let ses = Session::for_kv().with_ns("test").with_db("test"); + let res = &mut dbs.execute(&sql, &ses, None, false).await?; + assert_eq!(res.len(), 6); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'the quick brown fox jumps over the lazy dog.'"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'fox jumps over the lazy dog.'"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'the quick brown fox jumps over the lazy dog.'"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'the quick brown fox jumps over the lazy dog'"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'fox jumps over the lazy dog'"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::parse("'lazy dog'"); + assert_eq!(tmp, val); + // + Ok(()) +}