Implement SQL Strand as a newtype tuple struct

This commit is contained in:
Tobie Morgan Hitchcock 2022-05-05 05:30:32 +01:00
parent ed92fb4d85
commit 1ed5df005e
13 changed files with 118 additions and 118 deletions

View file

@ -9,7 +9,7 @@ use sha2::Sha512;
pub fn md5(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Md5::new();
hasher.update(args.remove(0).as_strand().as_str());
hasher.update(args.remove(0).as_string().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
@ -17,7 +17,7 @@ pub fn md5(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
pub fn sha1(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha1::new();
hasher.update(args.remove(0).as_strand().as_str());
hasher.update(args.remove(0).as_string().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
@ -25,7 +25,7 @@ pub fn sha1(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
pub fn sha256(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha256::new();
hasher.update(args.remove(0).as_strand().as_str());
hasher.update(args.remove(0).as_string().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
@ -33,7 +33,7 @@ pub fn sha256(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
pub fn sha512(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha512::new();
hasher.update(args.remove(0).as_strand().as_str());
hasher.update(args.remove(0).as_string().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
@ -52,15 +52,15 @@ pub mod argon2 {
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default();
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let hash = args.remove(0).as_string();
let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap();
Ok(algo.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default();
let pass = args.remove(0).as_strand().value;
let pass = args.remove(0).as_string();
let salt = SaltString::generate(&mut OsRng);
let hash = algo.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())
@ -79,14 +79,14 @@ pub mod pbkdf2 {
use rand::rngs::OsRng;
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let hash = args.remove(0).as_string();
let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap();
Ok(Pbkdf2.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let pass = args.remove(0).as_strand().value;
let pass = args.remove(0).as_string();
let salt = SaltString::generate(&mut OsRng);
let hash = Pbkdf2.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())
@ -105,14 +105,14 @@ pub mod scrypt {
};
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let hash = args.remove(0).as_string();
let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap();
Ok(Scrypt.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let pass = args.remove(0).as_strand().value;
let pass = args.remove(0).as_string();
let salt = SaltString::generate(&mut OsRng);
let hash = Scrypt.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())

View file

@ -14,24 +14,24 @@ use std::char;
#[rustfmt::skip] static LONGITUDE_RE: Lazy<Regex> = Lazy::new(|| Regex::new("^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$").unwrap());
pub fn alphanum(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_alphanumeric).into())
Ok(args.remove(0).as_string().chars().all(char::is_alphanumeric).into())
}
pub fn alpha(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_alphabetic).into())
Ok(args.remove(0).as_string().chars().all(char::is_alphabetic).into())
}
pub fn ascii(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(|x| char::is_ascii(&x)).into())
Ok(args.remove(0).as_string().chars().all(|x| char::is_ascii(&x)).into())
}
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(DOMAIN_RE.is_match(args.remove(0).as_strand().as_str()).into())
Ok(DOMAIN_RE.is_match(args.remove(0).as_string().as_str()).into())
}
pub fn email(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Convert to a &str
let val = val.as_str();
// Check if value is empty
@ -57,25 +57,25 @@ pub fn email(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
}
pub fn hexadecimal(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(|x| char::is_ascii_hexdigit(&x)).into())
Ok(args.remove(0).as_string().chars().all(|x| char::is_ascii_hexdigit(&x)).into())
}
pub fn latitude(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(LATITUDE_RE.is_match(args.remove(0).as_strand().as_str()).into())
Ok(LATITUDE_RE.is_match(args.remove(0).as_string().as_str()).into())
}
pub fn longitude(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(LONGITUDE_RE.is_match(args.remove(0).as_strand().as_str()).into())
Ok(LONGITUDE_RE.is_match(args.remove(0).as_string().as_str()).into())
}
pub fn numeric(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_numeric).into())
Ok(args.remove(0).as_string().chars().all(char::is_numeric).into())
}
pub fn semver(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(SEMVER_RE.is_match(args.remove(0).as_strand().as_str()).into())
Ok(SEMVER_RE.is_match(args.remove(0).as_string().as_str()).into())
}
pub fn uuid(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(UUID_RE.is_match(args.remove(0).as_strand().as_str()).into())
Ok(UUID_RE.is_match(args.remove(0).as_string().as_str()).into())
}

View file

@ -11,7 +11,7 @@ pub mod email {
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Check if value is empty
if val.is_empty() {
return Ok(Value::None);
@ -36,7 +36,7 @@ pub mod email {
pub fn user(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Check if value is empty
if val.is_empty() {
return Ok(Value::None);
@ -69,7 +69,7 @@ pub mod url {
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.domain() {
@ -82,7 +82,7 @@ pub mod url {
pub fn fragment(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.fragment() {
@ -95,7 +95,7 @@ pub mod url {
pub fn host(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.host_str() {
@ -108,7 +108,7 @@ pub mod url {
pub fn path(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => Ok(v.path().into()),
@ -118,7 +118,7 @@ pub mod url {
pub fn port(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.port() {
@ -131,7 +131,7 @@ pub mod url {
pub fn query(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.query() {

View file

@ -4,51 +4,51 @@ use crate::sql::value::Value;
use slug::slugify;
pub fn concat(_: &Runtime, args: Vec<Value>) -> Result<Value, Error> {
Ok(args.into_iter().map(|x| x.as_strand().value).collect::<Vec<_>>().concat().into())
Ok(args.into_iter().map(|x| x.as_string()).collect::<Vec<_>>().concat().into())
}
pub fn ends_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let chr = args.remove(0).as_string();
Ok(val.ends_with(&chr).into())
}
pub fn join(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let chr = args.remove(0).as_strand().value;
let val = args.into_iter().map(|x| x.as_strand().value);
let chr = args.remove(0).as_string();
let val = args.into_iter().map(|x| x.as_string());
let val = val.collect::<Vec<_>>().join(&chr);
Ok(val.into())
}
pub fn length(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let num = val.chars().count() as i64;
Ok(num.into())
}
pub fn lowercase(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.to_lowercase().into())
Ok(args.remove(0).as_string().to_lowercase().into())
}
pub fn repeat(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let num = args.remove(0).as_int() as usize;
Ok(val.repeat(num).into())
}
pub fn replace(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let old = args.remove(0).as_strand().value;
let new = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let old = args.remove(0).as_string();
let new = args.remove(0).as_string();
Ok(val.replace(&old, &new).into())
}
pub fn reverse(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().rev().collect::<String>().into())
Ok(args.remove(0).as_string().chars().rev().collect::<String>().into())
}
pub fn slice(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let beg = args.remove(0).as_int() as usize;
let lim = args.remove(0).as_int() as usize;
let val = val.chars().skip(beg).take(lim).collect::<String>();
@ -56,30 +56,30 @@ pub fn slice(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
}
pub fn slug(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(slugify(&args.remove(0).as_strand().value).into())
Ok(slugify(&args.remove(0).as_string()).into())
}
pub fn split(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let chr = args.remove(0).as_string();
let val = val.split(&chr).collect::<Vec<&str>>();
Ok(val.into())
}
pub fn starts_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
let val = args.remove(0).as_string();
let chr = args.remove(0).as_string();
Ok(val.starts_with(&chr).into())
}
pub fn trim(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.trim().into())
Ok(args.remove(0).as_string().trim().into())
}
pub fn uppercase(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.to_uppercase().into())
Ok(args.remove(0).as_string().to_uppercase().into())
}
pub fn words(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.split(' ').collect::<Vec<&str>>().into())
Ok(args.remove(0).as_string().split(' ').collect::<Vec<&str>>().into())
}

View file

@ -37,7 +37,7 @@ pub fn floor(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
pub fn group(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Datetime(v) => match args.remove(0) {
Value::Strand(g) => match g.value.as_str() {
Value::Strand(g) => match g.as_str() {
"year" => Ok(Utc.ymd(v.value.year(), 1, 1).and_hms(0, 0, 0).into()),
"month" => Ok(Utc.ymd(v.value.year(), v.value.month(), 1).and_hms(0, 0, 0).into()),
"day" => Ok(Utc

View file

@ -100,12 +100,12 @@ pub fn thing(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let tb = args.remove(0);
match args.remove(0) {
Value::Thing(id) => Ok(Value::Thing(Thing {
tb: tb.as_strand().value,
tb: tb.as_string(),
id: id.id,
})),
id => Ok(Value::Thing(Thing {
tb: tb.as_strand().value,
id: id.as_strand().into(),
tb: tb.as_string(),
id: id.as_string().into(),
})),
}
}

View file

@ -4,7 +4,6 @@ use crate::sql::common::val_char;
use crate::sql::error::IResult;
use crate::sql::ident::ident_raw;
use crate::sql::number::{number, Number};
use crate::sql::strand::Strand;
use nanoid::nanoid;
use nom::branch::alt;
use nom::combinator::map;
@ -29,12 +28,6 @@ impl From<String> for Id {
}
}
impl From<Strand> for Id {
fn from(v: Strand) -> Self {
Id::String(v.value)
}
}
impl From<&str> for Id {
fn from(v: &str) -> Self {
Id::String(v.to_owned())

View file

@ -26,7 +26,7 @@ impl Default for Op {
impl From<&Value> for Op {
fn from(v: &Value) -> Self {
match &v.to_strand().value[..] {
match v.to_strand().as_str() {
"add" => Op::Add,
"remove" => Op::Remove,
"replace" => Op::Replace,

View file

@ -4,10 +4,10 @@ use nom::bytes::complete::escaped;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::character::complete::one_of;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops;
use std::ops::Deref;
use std::str;
const SINGLE: &str = r#"'"#;
@ -17,35 +17,39 @@ const DOUBLE: &str = r#"""#;
const DOUBLE_ESC: &str = r#"\""#;
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
pub struct Strand {
pub value: String,
}
pub struct Strand(pub String);
impl From<String> for Strand {
fn from(s: String) -> Self {
Strand {
value: s,
}
Strand(s)
}
}
impl<'a> From<&'a str> for Strand {
fn from(s: &str) -> Self {
Strand {
value: String::from(s),
Strand(String::from(s))
}
}
impl Deref for Strand {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Strand {
pub fn as_str(&self) -> &str {
self.value.as_str()
self.0.as_str()
}
pub fn as_string(self) -> String {
self.0
}
}
impl fmt::Display for Strand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{}\"", self.value)
write!(f, "\"{}\"", self.0)
}
}
@ -55,11 +59,9 @@ impl Serialize for Strand {
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_some(&self.value)
serializer.serialize_some(&self.0)
} else {
let mut val = serializer.serialize_struct("Strand", 1)?;
val.serialize_field("value", &self.value)?;
val.end()
serializer.serialize_newtype_struct("Strand", &self.0)
}
}
}
@ -67,13 +69,13 @@ impl Serialize for Strand {
impl ops::Add for Strand {
type Output = Self;
fn add(self, other: Self) -> Self {
Strand::from(self.value + &other.value)
Strand::from(self.0 + &other.0)
}
}
pub fn strand(i: &str) -> IResult<&str, Strand> {
let (i, v) = strand_raw(i)?;
Ok((i, Strand::from(v)))
Ok((i, Strand(v)))
}
pub fn strand_raw(i: &str) -> IResult<&str, String> {

View file

@ -3,7 +3,6 @@ use crate::sql::common::escape;
use crate::sql::common::val_char;
use crate::sql::error::IResult;
use crate::sql::ident::ident_raw;
use crate::sql::strand::Strand;
use nom::multi::separated_list1;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -33,12 +32,6 @@ impl From<String> for Table {
}
}
impl From<Strand> for Table {
fn from(v: Strand) -> Self {
Table(v.value)
}
}
impl Deref for Table {
type Target = String;
fn deref(&self) -> &Self::Target {

View file

@ -66,7 +66,7 @@ impl Value {
path,
value: {
let mut dmp = dmp::new();
let mut pch = dmp.patch_make1(&a.value, &b.value);
let mut pch = dmp.patch_make1(a, b);
let txt = dmp.patch_to_text(&mut pch);
txt.into()
},

View file

@ -26,8 +26,8 @@ impl Value {
if let Value::Strand(p) = o.value {
if let Value::Strand(v) = self.get(ctx, opt, txn, &o.path).await? {
let mut dmp = dmp::new();
let mut pch = dmp.patch_from_text(p.value);
let (txt, _) = dmp.patch_apply(&mut pch, &v.value);
let mut pch = dmp.patch_from_text(p.as_string());
let (txt, _) = dmp.patch_apply(&mut pch, v.as_str());
let txt = txt.into_iter().collect::<String>();
self.set(ctx, opt, txn, &o.path, Value::from(txt)).await?;
}

View file

@ -479,7 +479,7 @@ impl Value {
pub fn is_true(&self) -> bool {
match self {
Value::True => true,
Value::Strand(v) => v.value.to_ascii_lowercase() == "true",
Value::Strand(v) => v.to_ascii_lowercase() == "true",
_ => false,
}
}
@ -487,7 +487,7 @@ impl Value {
pub fn is_false(&self) -> bool {
match self {
Value::False => true,
Value::Strand(v) => v.value.to_ascii_lowercase() == "false",
Value::Strand(v) => v.to_ascii_lowercase() == "false",
_ => false,
}
}
@ -500,7 +500,7 @@ impl Value {
Value::Geometry(_) => true,
Value::Array(v) => !v.is_empty(),
Value::Object(v) => !v.is_empty(),
Value::Strand(v) => !v.value.is_empty() && v.value.to_ascii_lowercase() != "false",
Value::Strand(v) => !v.is_empty() && v.to_ascii_lowercase() != "false",
Value::Number(v) => v.is_truthy(),
Value::Duration(v) => v.value.as_nanos() > 0,
Value::Datetime(v) => v.value.timestamp() > 0,
@ -549,7 +549,7 @@ impl Value {
pub fn as_int(self) -> i64 {
match self {
Value::True => 1,
Value::Strand(v) => v.value.parse::<i64>().unwrap_or(0),
Value::Strand(v) => v.parse::<i64>().unwrap_or(0),
Value::Number(v) => v.as_int(),
Value::Duration(v) => v.value.as_secs() as i64,
Value::Datetime(v) => v.value.timestamp(),
@ -560,7 +560,7 @@ impl Value {
pub fn as_float(self) -> f64 {
match self {
Value::True => 1.0,
Value::Strand(v) => v.value.parse::<f64>().unwrap_or(0.0),
Value::Strand(v) => v.parse::<f64>().unwrap_or(0.0),
Value::Number(v) => v.as_float(),
Value::Duration(v) => v.value.as_secs() as f64,
Value::Datetime(v) => v.value.timestamp() as f64,
@ -590,13 +590,6 @@ impl Value {
}
}
pub fn as_string(self) -> String {
match self {
Value::Strand(v) => v.value,
_ => self.to_string(),
}
}
pub fn as_strand(self) -> Strand {
match self {
Value::Strand(v) => v,
@ -620,6 +613,13 @@ impl Value {
}
}
pub fn as_string(self) -> String {
match self {
Value::Strand(v) => v.as_string(),
_ => self.to_string(),
}
}
// -----------------------------------
// Expensive conversion of value
// -----------------------------------
@ -660,7 +660,7 @@ impl Value {
pub fn to_idiom(&self) -> Idiom {
self.to_strand()
.value
.as_str()
.trim_start_matches('/')
.split(&['.', '/'][..])
.map(Part::from)
@ -854,7 +854,7 @@ impl Value {
match self {
Value::Strand(v) => match other {
Value::Strand(w) => MATCHER.fuzzy_match(v.as_str(), w.as_str()).is_some(),
_ => MATCHER.fuzzy_match(v.as_str(), other.to_strand().as_str()).is_some(),
_ => MATCHER.fuzzy_match(v.as_str(), other.to_string().as_str()).is_some(),
},
_ => self.equal(other),
}
@ -878,8 +878,8 @@ impl Value {
match self {
Value::Array(v) => v.iter().any(|v| v.equal(other)),
Value::Strand(v) => match other {
Value::Strand(w) => v.value.contains(w.as_str()),
_ => v.value.contains(&other.to_strand().as_str()),
Value::Strand(w) => v.contains(w.as_str()),
_ => v.contains(&other.to_string().as_str()),
},
Value::Geometry(v) => match other {
Value::Geometry(w) => v.contains(w),
@ -927,27 +927,21 @@ impl Value {
pub fn lexical_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) {
(Value::Strand(a), Value::Strand(b)) => {
Some(lexical_sort::lexical_cmp(&a.value, &b.value))
}
(Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::lexical_cmp(a, b)),
_ => self.partial_cmp(other),
}
}
pub fn natural_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) {
(Value::Strand(a), Value::Strand(b)) => {
Some(lexical_sort::natural_cmp(&a.value, &b.value))
}
(Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::natural_cmp(a, b)),
_ => self.partial_cmp(other),
}
}
pub fn natural_lexical_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) {
(Value::Strand(a), Value::Strand(b)) => {
Some(lexical_sort::natural_lexical_cmp(&a.value, &b.value))
}
(Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::natural_lexical_cmp(a, b)),
_ => self.partial_cmp(other),
}
}
@ -1330,6 +1324,24 @@ mod tests {
assert_eq!(Strand::from("something"), Value::from("something").as_strand());
}
#[test]
fn convert_string() {
assert_eq!(String::from("NONE"), Value::None.as_string());
assert_eq!(String::from("NULL"), Value::Null.as_string());
assert_eq!(String::from("VOID"), Value::Void.as_string());
assert_eq!(String::from("true"), Value::True.as_string());
assert_eq!(String::from("false"), Value::False.as_string());
assert_eq!(String::from("0"), Value::from(0).as_string());
assert_eq!(String::from("1"), Value::from(1).as_string());
assert_eq!(String::from("-1"), Value::from(-1).as_string());
assert_eq!(String::from("1.1"), Value::from(1.1).as_string());
assert_eq!(String::from("-1.1"), Value::from(-1.1).as_string());
assert_eq!(String::from("3"), Value::from("3").as_string());
assert_eq!(String::from("true"), Value::from("true").as_string());
assert_eq!(String::from("false"), Value::from("false").as_string());
assert_eq!(String::from("something"), Value::from("something").as_string());
}
#[test]
fn serialize_deserialize() {
let val = Value::parse(