Support negative offsets in SQL string::slice() function

Closes #1490
This commit is contained in:
Tobie Morgan Hitchcock 2022-11-27 11:05:33 +00:00
parent f0520313b5
commit 8b5a99c321
3 changed files with 66 additions and 8 deletions

View file

@ -45,6 +45,12 @@ impl FromArg for i64 {
} }
} }
impl FromArg for isize {
fn from_arg(arg: Value) -> Result<Self, Error> {
Ok(arg.as_int() as isize)
}
}
impl FromArg for usize { impl FromArg for usize {
fn from_arg(arg: Value) -> Result<Self, Error> { fn from_arg(arg: Value) -> Result<Self, Error> {
Ok(arg.as_int() as usize) Ok(arg.as_int() as usize)

View file

@ -51,8 +51,18 @@ pub fn reverse((string,): (String,)) -> Result<Value, Error> {
Ok(string.chars().rev().collect::<String>().into()) Ok(string.chars().rev().collect::<String>().into())
} }
pub fn slice((val, beg, lim): (String, usize, usize)) -> Result<Value, Error> { pub fn slice((val, beg, lim): (String, Option<isize>, Option<isize>)) -> Result<Value, Error> {
Ok(val.chars().skip(beg).take(lim).collect::<String>().into()) let val = match beg {
Some(v) if v < 0 => val.chars().skip(val.len() - v.unsigned_abs()).collect::<String>(),
Some(v) => val.chars().skip(v as usize).collect::<String>(),
None => val,
};
let val = match lim {
Some(v) if v < 0 => val.chars().take(val.len() - v.unsigned_abs()).collect::<String>(),
Some(v) => val.chars().take(v as usize).collect::<String>(),
None => val,
};
Ok(val.into())
} }
pub fn slug((string,): (String,)) -> Result<Value, Error> { pub fn slug((string,): (String,)) -> Result<Value, Error> {

View file

@ -6,12 +6,12 @@ use surrealdb::Error;
use surrealdb::Session; use surrealdb::Session;
#[tokio::test] #[tokio::test]
async fn array_distinct() -> Result<(), Error> { async fn function_array_distinct() -> Result<(), Error> {
let sql = r#" let sql = r#"
SELECT * FROM array::distinct([1, 3, 2, 1, 3, 3, 4]); RETURN array::distinct([1, 3, 2, 1, 3, 3, 4]);
SELECT * FROM array::distinct([]); RETURN array::distinct([]);
SELECT * FROM array::distinct("something"); RETURN array::distinct("something");
SELECT * FROM array::distinct(["something"]); RETURN array::distinct(["something"]);
"#; "#;
let dbs = Datastore::new("memory").await?; let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test"); 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); assert_eq!(tmp, val);
// //
let tmp = res.remove(0).result?; let tmp = res.remove(0).result?;
let val = Value::parse("[NONE]"); let val = Value::None;
assert_eq!(tmp, val); assert_eq!(tmp, val);
// //
let tmp = res.remove(0).result?; let tmp = res.remove(0).result?;
@ -36,3 +36,45 @@ async fn array_distinct() -> Result<(), Error> {
// //
Ok(()) 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(())
}