Add value::diff() and value::patch() functions (#4608)

This commit is contained in:
Tobie Morgan Hitchcock 2024-08-25 15:13:23 +01:00 committed by GitHub
parent 419f5d52c7
commit f4e3d4f4e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 200 additions and 106 deletions

View file

@ -33,6 +33,7 @@ pub mod string;
pub mod time;
pub mod r#type;
pub mod util;
pub mod value;
pub mod vector;
/// Attempts to run any function
@ -394,6 +395,9 @@ pub fn synchronous(
"type::is::string" => r#type::is::string,
"type::is::uuid" => r#type::is::uuid,
//
"value::diff" => value::diff,
"value::patch" => value::patch,
//
"vector::add" => vector::add,
"vector::angle" => vector::angle,
"vector::cross" => vector::cross,
@ -542,8 +546,8 @@ pub async fn idiom(
"bearing" => geo::bearing,
"centroid" => geo::centroid,
"distance" => geo::distance,
"hash::decode" => geo::hash::decode,
"hash::encode" => geo::hash::encode,
"hash_decode" => geo::hash::decode,
"hash_encode" => geo::hash::encode,
)
}
Value::Thing(_) => {
@ -618,12 +622,12 @@ pub async fn idiom(
"semver_major" => string::semver::major,
"semver_minor" => string::semver::minor,
"semver_patch" => string::semver::patch,
"semver_inc::major" => string::semver::inc::major,
"semver_inc::minor" => string::semver::inc::minor,
"semver_inc::patch" => string::semver::inc::patch,
"semver_set::major" => string::semver::set::major,
"semver_set::minor" => string::semver::set::minor,
"semver_set::patch" => string::semver::set::patch,
"semver_inc_major" => string::semver::inc::major,
"semver_inc_minor" => string::semver::inc::minor,
"semver_inc_patch" => string::semver::inc::patch,
"semver_set_major" => string::semver::set::major,
"semver_set_minor" => string::semver::set::minor,
"semver_set_patch" => string::semver::set::patch,
)
}
Value::Datetime(_) => {
@ -631,24 +635,24 @@ pub async fn idiom(
name,
args.clone(),
"no such method found for the datetime type",
"time_ceil" => time::ceil,
"time_day" => time::day,
"time_floor" => time::floor,
"time_format" => time::format,
"time_group" => time::group,
"time_hour" => time::hour,
"time_minute" => time::minute,
"time_month" => time::month,
"time_nano" => time::nano,
"time_micros" => time::micros,
"time_millis" => time::millis,
"time_round" => time::round,
"time_second" => time::second,
"time_unix" => time::unix,
"time_wday" => time::wday,
"time_week" => time::week,
"time_yday" => time::yday,
"time_year" => time::year,
"ceil" => time::ceil,
"day" => time::day,
"floor" => time::floor,
"format" => time::format,
"group" => time::group,
"hour" => time::hour,
"micros" => time::micros,
"millis" => time::millis,
"minute" => time::minute,
"month" => time::month,
"nano" => time::nano,
"round" => time::round,
"second" => time::second,
"unix" => time::unix,
"wday" => time::wday,
"week" => time::week,
"yday" => time::yday,
"year" => time::year,
)
}
_ => Err(Error::InvalidFunction {
@ -666,6 +670,7 @@ pub async fn idiom(
name,
args,
message,
//
"is_array" => r#type::is::array,
"is_bool" => r#type::is::bool,
"is_bytes" => r#type::is::bytes,
@ -706,6 +711,9 @@ pub async fn idiom(
"to_string" => r#type::string,
"to_uuid" => r#type::uuid,
//
"diff" => value::diff,
"patch" => value::patch,
//
"repeat" => array::repeat,
//
"chain" => shared::chain((stk, ctx, opt, doc)).await,

View file

@ -1,8 +1,7 @@
use std::collections::BTreeMap;
use crate::err::Error;
use crate::sql::value::Value;
use crate::sql::{Array, Object, Strand};
use std::collections::BTreeMap;
pub fn entries((object,): (Object,)) -> Result<Value, Error> {
Ok(Value::Array(Array(

View file

@ -25,6 +25,7 @@ mod session;
mod string;
mod time;
mod r#type;
mod value;
mod vector;
#[non_exhaustive]
@ -53,6 +54,7 @@ impl_module_def!(
"string" => (string::Package),
"time" => (time::Package),
"type" => (r#type::Package),
"value" => (value::Package),
"vector" => (vector::Package)
);

View file

@ -0,0 +1,12 @@
use super::run;
use crate::fnc::script::modules::impl_module_def;
#[non_exhaustive]
pub struct Package;
impl_module_def!(
Package,
"value",
"diff" => run,
"patch" => run
);

11
core/src/fnc/value.rs Normal file
View file

@ -0,0 +1,11 @@
use crate::err::Error;
use crate::sql::{Idiom, Value};
pub fn diff((val1, val2): (Value, Value)) -> Result<Value, Error> {
Ok(val1.diff(&val2, Idiom::default()).into())
}
pub fn patch((mut val, diff): (Value, Value)) -> Result<Value, Error> {
val.patch(diff)?;
Ok(val)
}

View file

@ -2298,6 +2298,7 @@ impl Value {
match self {
// Arrays are allowed
Value::Array(v) => Ok(v),
// Ranges convert to an array
Value::Range(r) => {
let range: std::ops::Range<i64> = r.deref().to_owned().try_into()?;
Ok(range.into_iter().map(Value::from).collect::<Vec<Value>>().into())
@ -2313,6 +2314,8 @@ impl Value {
/// Try to convert this value to a `Range`
pub(crate) fn convert_to_range(self) -> Result<Range, Error> {
match self {
// Ranges are allowed
Value::Range(r) => Ok(*r),
// Arrays with two elements are allowed
Value::Array(v) if v.len() == 2 => {
let mut v = v;
@ -2321,7 +2324,6 @@ impl Value {
end: Bound::Excluded(v.remove(0)),
})
}
Value::Range(r) => Ok(*r),
// Anything else raises an error
_ => Err(Error::ConvertTo {
from: self,

View file

@ -112,34 +112,27 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("array::logical_and") => PathKind::Function,
UniCase::ascii("array::logical_or") => PathKind::Function,
UniCase::ascii("array::logical_xor") => PathKind::Function,
UniCase::ascii("array::matches") => PathKind::Function,
UniCase::ascii("array::map") => PathKind::Function,
UniCase::ascii("array::matches") => PathKind::Function,
UniCase::ascii("array::max") => PathKind::Function,
UniCase::ascii("array::min") => PathKind::Function,
UniCase::ascii("array::pop") => PathKind::Function,
UniCase::ascii("array::prepend") => PathKind::Function,
UniCase::ascii("array::push") => PathKind::Function,
UniCase::ascii("array::range") => PathKind::Function,
UniCase::ascii("array::remove") => PathKind::Function,
UniCase::ascii("array::repeat") => PathKind::Function,
UniCase::ascii("array::range") => PathKind::Function,
UniCase::ascii("array::reverse") => PathKind::Function,
UniCase::ascii("array::shuffle") => PathKind::Function,
UniCase::ascii("array::slice") => PathKind::Function,
UniCase::ascii("array::sort::asc") => PathKind::Function,
UniCase::ascii("array::sort::desc") => PathKind::Function,
UniCase::ascii("array::sort") => PathKind::Function,
UniCase::ascii("array::swap") => PathKind::Function,
UniCase::ascii("array::transpose") => PathKind::Function,
UniCase::ascii("array::union") => PathKind::Function,
UniCase::ascii("array::sort::asc") => PathKind::Function,
UniCase::ascii("array::sort::desc") => PathKind::Function,
UniCase::ascii("array::windows") => PathKind::Function,
//
UniCase::ascii("object::entries") => PathKind::Function,
UniCase::ascii("object::from_entries") => PathKind::Function,
UniCase::ascii("object::keys") => PathKind::Function,
UniCase::ascii("object::len") => PathKind::Function,
UniCase::ascii("object::values") => PathKind::Function,
UniCase::ascii("object::matches") => PathKind::Function,
//
UniCase::ascii("bytes::len") => PathKind::Function,
//
UniCase::ascii("count") => PathKind::Function,
@ -149,6 +142,14 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("crypto::sha1") => PathKind::Function,
UniCase::ascii("crypto::sha256") => PathKind::Function,
UniCase::ascii("crypto::sha512") => PathKind::Function,
UniCase::ascii("crypto::argon2::compare") => PathKind::Function,
UniCase::ascii("crypto::argon2::generate") => PathKind::Function,
UniCase::ascii("crypto::bcrypt::compare") => PathKind::Function,
UniCase::ascii("crypto::bcrypt::generate") => PathKind::Function,
UniCase::ascii("crypto::pbkdf2::compare") => PathKind::Function,
UniCase::ascii("crypto::pbkdf2::generate") => PathKind::Function,
UniCase::ascii("crypto::scrypt::compare") => PathKind::Function,
UniCase::ascii("crypto::scrypt::generate") => PathKind::Function,
//
UniCase::ascii("duration::days") => PathKind::Function,
UniCase::ascii("duration::hours") => PathKind::Function,
@ -178,10 +179,17 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("geo::hash::decode") => PathKind::Function,
UniCase::ascii("geo::hash::encode") => PathKind::Function,
//
UniCase::ascii("http::head") => PathKind::Function,
UniCase::ascii("http::get") => PathKind::Function,
UniCase::ascii("http::put") => PathKind::Function,
UniCase::ascii("http::post") => PathKind::Function,
UniCase::ascii("http::patch") => PathKind::Function,
UniCase::ascii("http::delete") => PathKind::Function,
//
UniCase::ascii("math::abs") => PathKind::Function,
UniCase::ascii("math::acos") => PathKind::Function,
UniCase::ascii("math::asin") => PathKind::Function,
UniCase::ascii("math::acot") => PathKind::Function,
UniCase::ascii("math::asin") => PathKind::Function,
UniCase::ascii("math::atan") => PathKind::Function,
UniCase::ascii("math::bottom") => PathKind::Function,
UniCase::ascii("math::ceil") => PathKind::Function,
@ -196,8 +204,8 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("math::lerpangle") => PathKind::Function,
UniCase::ascii("math::ln") => PathKind::Function,
UniCase::ascii("math::log") => PathKind::Function,
UniCase::ascii("math::log2") => PathKind::Function,
UniCase::ascii("math::log10") => PathKind::Function,
UniCase::ascii("math::log2") => PathKind::Function,
UniCase::ascii("math::max") => PathKind::Function,
UniCase::ascii("math::mean") => PathKind::Function,
UniCase::ascii("math::median") => PathKind::Function,
@ -208,21 +216,28 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("math::percentile") => PathKind::Function,
UniCase::ascii("math::pow") => PathKind::Function,
UniCase::ascii("math::product") => PathKind::Function,
UniCase::ascii("math::round") => PathKind::Function,
UniCase::ascii("math::rad2deg") => PathKind::Function,
UniCase::ascii("math::round") => PathKind::Function,
UniCase::ascii("math::sign") => PathKind::Function,
UniCase::ascii("math::sin") => PathKind::Function,
UniCase::ascii("math::spread") => PathKind::Function,
UniCase::ascii("math::sqrt") => PathKind::Function,
UniCase::ascii("math::tan") => PathKind::Function,
UniCase::ascii("math::stddev") => PathKind::Function,
UniCase::ascii("math::sum") => PathKind::Function,
UniCase::ascii("math::tan") => PathKind::Function,
UniCase::ascii("math::top") => PathKind::Function,
UniCase::ascii("math::trimean") => PathKind::Function,
UniCase::ascii("math::variance") => PathKind::Function,
//
UniCase::ascii("not") => PathKind::Function,
//
UniCase::ascii("object::entries") => PathKind::Function,
UniCase::ascii("object::from_entries") => PathKind::Function,
UniCase::ascii("object::keys") => PathKind::Function,
UniCase::ascii("object::len") => PathKind::Function,
UniCase::ascii("object::matches") => PathKind::Function,
UniCase::ascii("object::values") => PathKind::Function,
//
UniCase::ascii("parse::email::host") => PathKind::Function,
UniCase::ascii("parse::email::user") => PathKind::Function,
UniCase::ascii("parse::url::domain") => PathKind::Function,
@ -251,15 +266,22 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("record::table") => PathKind::Function,
UniCase::ascii("record::tb") => PathKind::Function,
//
UniCase::ascii("search::analyze") => PathKind::Function,
UniCase::ascii("search::score") => PathKind::Function,
UniCase::ascii("search::highlight") => PathKind::Function,
UniCase::ascii("search::offsets") => PathKind::Function,
//
UniCase::ascii("session::ac") => PathKind::Function,
UniCase::ascii("session::db") => PathKind::Function,
UniCase::ascii("session::id") => PathKind::Function,
UniCase::ascii("session::ip") => PathKind::Function,
UniCase::ascii("session::ns") => PathKind::Function,
UniCase::ascii("session::origin") => PathKind::Function,
UniCase::ascii("session::ac") => PathKind::Function,
UniCase::ascii("session::rd") => PathKind::Function,
UniCase::ascii("session::token") => PathKind::Function,
//
UniCase::ascii("sleep") => PathKind::Function,
//
UniCase::ascii("string::concat") => PathKind::Function,
UniCase::ascii("string::contains") => PathKind::Function,
UniCase::ascii("string::endsWith") => PathKind::Function,
@ -319,12 +341,12 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("time::group") => PathKind::Function,
UniCase::ascii("time::hour") => PathKind::Function,
UniCase::ascii("time::max") => PathKind::Function,
UniCase::ascii("time::micros") => PathKind::Function,
UniCase::ascii("time::millis") => PathKind::Function,
UniCase::ascii("time::min") => PathKind::Function,
UniCase::ascii("time::minute") => PathKind::Function,
UniCase::ascii("time::month") => PathKind::Function,
UniCase::ascii("time::nano") => PathKind::Function,
UniCase::ascii("time::micros") => PathKind::Function,
UniCase::ascii("time::millis") => PathKind::Function,
UniCase::ascii("time::now") => PathKind::Function,
UniCase::ascii("time::round") => PathKind::Function,
UniCase::ascii("time::second") => PathKind::Function,
@ -334,9 +356,9 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("time::week") => PathKind::Function,
UniCase::ascii("time::yday") => PathKind::Function,
UniCase::ascii("time::year") => PathKind::Function,
UniCase::ascii("time::from::nanos") => PathKind::Function,
UniCase::ascii("time::from::micros") => PathKind::Function,
UniCase::ascii("time::from::millis") => PathKind::Function,
UniCase::ascii("time::from::nanos") => PathKind::Function,
UniCase::ascii("time::from::secs") => PathKind::Function,
UniCase::ascii("time::from::unix") => PathKind::Function,
//
@ -346,17 +368,19 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("type::datetime") => PathKind::Function,
UniCase::ascii("type::decimal") => PathKind::Function,
UniCase::ascii("type::duration") => PathKind::Function,
UniCase::ascii("type::field") => PathKind::Function,
UniCase::ascii("type::fields") => PathKind::Function,
UniCase::ascii("type::float") => PathKind::Function,
UniCase::ascii("type::geometry") => PathKind::Function,
UniCase::ascii("type::int") => PathKind::Function,
UniCase::ascii("type::number") => PathKind::Function,
UniCase::ascii("type::point") => PathKind::Function,
UniCase::ascii("type::range") => PathKind::Function,
UniCase::ascii("type::record") => PathKind::Function,
UniCase::ascii("type::string") => PathKind::Function,
UniCase::ascii("type::table") => PathKind::Function,
UniCase::ascii("type::thing") => PathKind::Function,
UniCase::ascii("type::range") => PathKind::Function,
UniCase::ascii("type::record") => PathKind::Function,
UniCase::ascii("type::uuid") => PathKind::Function,
UniCase::ascii("type::geometry") => PathKind::Function,
UniCase::ascii("type::is::array") => PathKind::Function,
UniCase::ascii("type::is::bool") => PathKind::Function,
UniCase::ascii("type::is::bytes") => PathKind::Function,
@ -368,11 +392,11 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("type::is::geometry") => PathKind::Function,
UniCase::ascii("type::is::int") => PathKind::Function,
UniCase::ascii("type::is::line") => PathKind::Function,
UniCase::ascii("type::is::null") => PathKind::Function,
UniCase::ascii("type::is::none") => PathKind::Function,
UniCase::ascii("type::is::multiline") => PathKind::Function,
UniCase::ascii("type::is::multipoint") => PathKind::Function,
UniCase::ascii("type::is::multipolygon") => PathKind::Function,
UniCase::ascii("type::is::none") => PathKind::Function,
UniCase::ascii("type::is::null") => PathKind::Function,
UniCase::ascii("type::is::number") => PathKind::Function,
UniCase::ascii("type::is::object") => PathKind::Function,
UniCase::ascii("type::is::point") => PathKind::Function,
@ -381,11 +405,14 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("type::is::string") => PathKind::Function,
UniCase::ascii("type::is::uuid") => PathKind::Function,
//
UniCase::ascii("value::diff") => PathKind::Function,
UniCase::ascii("value::patch") => PathKind::Function,
//
UniCase::ascii("vector::add") => PathKind::Function,
UniCase::ascii("vector::angle") => PathKind::Function,
UniCase::ascii("vector::cross") => PathKind::Function,
UniCase::ascii("vector::dot") => PathKind::Function,
UniCase::ascii("vector::divide") => PathKind::Function,
UniCase::ascii("vector::dot") => PathKind::Function,
UniCase::ascii("vector::magnitude") => PathKind::Function,
UniCase::ascii("vector::multiply") => PathKind::Function,
UniCase::ascii("vector::normalize") => PathKind::Function,
@ -403,33 +430,6 @@ pub(crate) static PATHS: phf::Map<UniCase<&'static str>, PathKind> = phf_map! {
UniCase::ascii("vector::similarity::jaccard") => PathKind::Function,
UniCase::ascii("vector::similarity::pearson") => PathKind::Function,
UniCase::ascii("vector::similarity::spearman") => PathKind::Function,
//
UniCase::ascii("crypto::argon2::compare") => PathKind::Function,
UniCase::ascii("crypto::argon2::generate") => PathKind::Function,
UniCase::ascii("crypto::bcrypt::compare") => PathKind::Function,
UniCase::ascii("crypto::bcrypt::generate") => PathKind::Function,
UniCase::ascii("crypto::pbkdf2::compare") => PathKind::Function,
UniCase::ascii("crypto::pbkdf2::generate") => PathKind::Function,
UniCase::ascii("crypto::scrypt::compare") => PathKind::Function,
UniCase::ascii("crypto::scrypt::generate") => PathKind::Function,
//
UniCase::ascii("http::head") => PathKind::Function,
UniCase::ascii("http::get") => PathKind::Function,
UniCase::ascii("http::put") => PathKind::Function,
UniCase::ascii("http::post") => PathKind::Function,
UniCase::ascii("http::patch") => PathKind::Function,
UniCase::ascii("http::delete") => PathKind::Function,
//
UniCase::ascii("search::analyze") => PathKind::Function,
UniCase::ascii("search::score") => PathKind::Function,
UniCase::ascii("search::highlight") => PathKind::Function,
UniCase::ascii("search::offsets") => PathKind::Function,
//
UniCase::ascii("sleep") => PathKind::Function,
//
UniCase::ascii("type::field") => PathKind::Function,
UniCase::ascii("type::fields") => PathKind::Function,
// constants
UniCase::ascii("math::E") => PathKind::Constant(Constant::MathE),
UniCase::ascii("math::FRAC_1_PI") => PathKind::Constant(Constant::MathFrac1Pi),

View file

@ -1182,7 +1182,7 @@ async fn changefeed() {
let CoreValue::Object(a) = a.clone() else {
unreachable!()
};
let CoreValue::Number(_versionstamp1) = a.get("versionstamp").clone().unwrap() else {
let CoreValue::Number(_versionstamp1) = a.get("versionstamp").unwrap() else {
unreachable!()
};
let changes = a.get("changes").unwrap().clone().to_owned();

View file

@ -3210,7 +3210,7 @@ async fn function_rand_uuid_v7_from_datetime() -> Result<(), Error> {
// --------------------------------------------------
#[tokio::test]
async fn function_parse_record_exists() -> Result<(), Error> {
async fn function_record_exists() -> Result<(), Error> {
let sql = r#"
RETURN record::exists(r"person:tobie");
CREATE ONLY person:tobie;
@ -3233,7 +3233,7 @@ async fn function_parse_record_exists() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_record_id() -> Result<(), Error> {
async fn function_record_id() -> Result<(), Error> {
let sql = r#"
RETURN record::id(r"person:tobie");
"#;
@ -3247,7 +3247,7 @@ async fn function_parse_record_id() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_record_table() -> Result<(), Error> {
async fn function_record_table() -> Result<(), Error> {
let sql = r#"
RETURN record::table(r"person:tobie");
"#;
@ -3502,7 +3502,7 @@ async fn function_search_analyzer_invalid_function_name() -> Result<(), Error> {
}
#[tokio::test]
async fn function_encode_html() -> Result<(), Error> {
async fn function_string_html_encode() -> Result<(), Error> {
let sql = r#"
RETURN string::html::encode("<div>Hello world!</div>");
"#;
@ -3516,7 +3516,7 @@ async fn function_encode_html() -> Result<(), Error> {
}
#[tokio::test]
async fn function_sanitize_html() -> Result<(), Error> {
async fn function_string_html_sanitize() -> Result<(), Error> {
let sql = r#"
RETURN string::html::sanitize("XSS<script>attack</script>");
"#;
@ -3530,7 +3530,7 @@ async fn function_sanitize_html() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_alphanum() -> Result<(), Error> {
async fn function_string_is_alphanum() -> Result<(), Error> {
let sql = r#"
RETURN string::is::alphanum("abcdefg123");
RETURN string::is::alphanum("this is a test!");
@ -3549,7 +3549,7 @@ async fn function_parse_is_alphanum() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_alpha() -> Result<(), Error> {
async fn function_string_is_alpha() -> Result<(), Error> {
let sql = r#"
RETURN string::is::alpha("abcdefg");
RETURN string::is::alpha("this is a test!");
@ -3568,7 +3568,7 @@ async fn function_parse_is_alpha() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_ascii() -> Result<(), Error> {
async fn function_string_is_ascii() -> Result<(), Error> {
let sql = r#"
RETURN string::is::ascii("abcdefg123");
RETURN string::is::ascii("this is a test 😀");
@ -3587,7 +3587,7 @@ async fn function_parse_is_ascii() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_datetime() -> Result<(), Error> {
async fn function_string_is_datetime() -> Result<(), Error> {
let sql = r#"
RETURN string::is::datetime("2015-09-05 23:56:04", "%Y-%m-%d %H:%M:%S");
RETURN string::is::datetime("2012-06-22 23:56:04", "%T");
@ -3606,7 +3606,7 @@ async fn function_parse_is_datetime() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_domain() -> Result<(), Error> {
async fn function_string_is_domain() -> Result<(), Error> {
let sql = r#"
RETURN string::is::domain("surrealdb.com");
RETURN string::is::domain("this is a test!");
@ -3625,7 +3625,7 @@ async fn function_parse_is_domain() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_email() -> Result<(), Error> {
async fn function_string_is_email() -> Result<(), Error> {
let sql = r#"
RETURN string::is::email("info@surrealdb.com");
RETURN string::is::email("this is a test!");
@ -3644,7 +3644,7 @@ async fn function_parse_is_email() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_hexadecimal() -> Result<(), Error> {
async fn function_string_is_hexadecimal() -> Result<(), Error> {
let sql = r#"
RETURN string::is::hexadecimal("ff009e");
RETURN string::is::hexadecimal("this is a test!");
@ -3663,7 +3663,7 @@ async fn function_parse_is_hexadecimal() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_ip() -> Result<(), Error> {
async fn function_string_is_ip() -> Result<(), Error> {
let sql = r#"
RETURN string::is::ip("127.0.0.1");
RETURN string::is::ip("127.0.0");
@ -3682,7 +3682,7 @@ async fn function_parse_is_ip() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_ipv4() -> Result<(), Error> {
async fn function_string_is_ipv4() -> Result<(), Error> {
let sql = r#"
RETURN string::is::ipv4("127.0.0.1");
RETURN string::is::ipv4("127.0.0");
@ -3701,7 +3701,7 @@ async fn function_parse_is_ipv4() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_ipv6() -> Result<(), Error> {
async fn function_string_is_ipv6() -> Result<(), Error> {
let sql = r#"
RETURN string::is::ipv6("::1");
RETURN string::is::ipv6("200t:db8::");
@ -3720,7 +3720,7 @@ async fn function_parse_is_ipv6() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_latitude() -> Result<(), Error> {
async fn function_string_is_latitude() -> Result<(), Error> {
let sql = r#"
RETURN string::is::latitude("51.509865");
RETURN string::is::latitude("this is a test!");
@ -3739,7 +3739,7 @@ async fn function_parse_is_latitude() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_longitude() -> Result<(), Error> {
async fn function_string_is_longitude() -> Result<(), Error> {
let sql = r#"
RETURN string::is::longitude("-90.136439");
RETURN string::is::longitude("this is a test!");
@ -3758,7 +3758,7 @@ async fn function_parse_is_longitude() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_numeric() -> Result<(), Error> {
async fn function_string_is_numeric() -> Result<(), Error> {
let sql = r#"
RETURN string::is::numeric("13136439");
RETURN string::is::numeric("this is a test!");
@ -3777,7 +3777,7 @@ async fn function_parse_is_numeric() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_semver() -> Result<(), Error> {
async fn function_string_is_semver() -> Result<(), Error> {
let sql = r#"
RETURN string::is::semver("1.0.0-rc.1");
RETURN string::is::semver("this is a test!");
@ -3796,7 +3796,7 @@ async fn function_parse_is_semver() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_url() -> Result<(), Error> {
async fn function_string_is_url() -> Result<(), Error> {
let sql = r#"
RETURN string::is::url("https://surrealdb.com/docs");
RETURN string::is::url("this is a test!");
@ -3815,7 +3815,7 @@ async fn function_parse_is_url() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_uuid() -> Result<(), Error> {
async fn function_string_is_uuid() -> Result<(), Error> {
let sql = r#"
RETURN string::is::uuid("e72bee20-f49b-11ec-b939-0242ac120002");
RETURN string::is::uuid("this is a test!");
@ -3834,7 +3834,7 @@ async fn function_parse_is_uuid() -> Result<(), Error> {
}
#[tokio::test]
async fn function_parse_is_record() -> Result<(), Error> {
async fn function_string_is_record() -> Result<(), Error> {
let sql = r#"
RETURN string::is::record("test:123");
RETURN string::is::record("invalid record id!");
@ -5571,6 +5571,66 @@ async fn function_type_range() -> Result<(), Error> {
Ok(())
}
// --------------------------------------------------
// value
// --------------------------------------------------
#[tokio::test]
async fn function_value_diff() -> Result<(), Error> {
let sql = r#"
RETURN value::diff({ a: 1, b: 2 }, { c: 3, b: 2 });
"#;
let mut test = Test::new(sql).await?;
//
let tmp = test.next()?.result?;
let val = Value::parse(
r#"
[
{
op: 'remove',
path: '/a'
},
{
op: 'add',
path: '/c',
value: 3
}
]
"#,
);
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn function_value_patch() -> Result<(), Error> {
let sql = r#"
RETURN value::patch({ a: 1, b: 2 }, [
{
op: 'remove',
path: '/a'
},
{
op: 'add',
path: '/c',
value: 3
}
]);
"#;
let mut test = Test::new(sql).await?;
//
let tmp = test.next()?.result?;
let val = Value::parse("{ b: 2, c: 3 }");
assert_eq!(tmp, val);
//
Ok(())
}
// --------------------------------------------------
// vector
// --------------------------------------------------
#[tokio::test]
async fn function_vector_add() -> Result<(), Error> {
test_queries(

View file

@ -2597,7 +2597,7 @@ async fn select_from_standard_index_ascending() -> Result<(), Error> {
let mut t = Test::new(sql).await?;
t.skip_ok(7)?;
//
t.expect_vals(&vec![
t.expect_vals(&[
"[
{
detail: {
@ -2704,7 +2704,7 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
let mut t = Test::new(sql).await?;
t.skip_ok(7)?;
//
t.expect_vals(&vec![
t.expect_vals(&[
"[
{
detail: {