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> { pub fn md5(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Md5::new(); 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 = hasher.finalize();
let val = format!("{:x}", val); let val = format!("{:x}", val);
Ok(val.into()) 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> { pub fn sha1(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha1::new(); 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 = hasher.finalize();
let val = format!("{:x}", val); let val = format!("{:x}", val);
Ok(val.into()) 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> { pub fn sha256(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha256::new(); 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 = hasher.finalize();
let val = format!("{:x}", val); let val = format!("{:x}", val);
Ok(val.into()) 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> { pub fn sha512(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha512::new(); 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 = hasher.finalize();
let val = format!("{:x}", val); let val = format!("{:x}", val);
Ok(val.into()) Ok(val.into())
@ -52,15 +52,15 @@ pub mod argon2 {
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default(); let algo = Argon2::default();
let hash = args.remove(0).as_strand().value; let hash = args.remove(0).as_string();
let pass = args.remove(0).as_strand().value; let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap(); let test = PasswordHash::new(&hash).unwrap();
Ok(algo.verify_password(pass.as_ref(), &test).is_ok().into()) Ok(algo.verify_password(pass.as_ref(), &test).is_ok().into())
} }
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default(); 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 salt = SaltString::generate(&mut OsRng);
let hash = algo.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string(); let hash = algo.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into()) Ok(hash.into())
@ -79,14 +79,14 @@ pub mod pbkdf2 {
use rand::rngs::OsRng; use rand::rngs::OsRng;
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value; let hash = args.remove(0).as_string();
let pass = args.remove(0).as_strand().value; let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap(); let test = PasswordHash::new(&hash).unwrap();
Ok(Pbkdf2.verify_password(pass.as_ref(), &test).is_ok().into()) Ok(Pbkdf2.verify_password(pass.as_ref(), &test).is_ok().into())
} }
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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 salt = SaltString::generate(&mut OsRng);
let hash = Pbkdf2.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string(); let hash = Pbkdf2.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into()) Ok(hash.into())
@ -105,14 +105,14 @@ pub mod scrypt {
}; };
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value; let hash = args.remove(0).as_string();
let pass = args.remove(0).as_strand().value; let pass = args.remove(0).as_string();
let test = PasswordHash::new(&hash).unwrap(); let test = PasswordHash::new(&hash).unwrap();
Ok(Scrypt.verify_password(pass.as_ref(), &test).is_ok().into()) Ok(Scrypt.verify_password(pass.as_ref(), &test).is_ok().into())
} }
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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 salt = SaltString::generate(&mut OsRng);
let hash = Scrypt.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string(); let hash = Scrypt.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into()) 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()); #[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> { 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> { 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> { 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> { 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> { pub fn email(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Convert to a &str // Convert to a &str
let val = val.as_str(); let val = val.as_str();
// Check if value is empty // 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> { 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> { 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> { 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> { 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> { 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> { 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> { pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Check if value is empty // Check if value is empty
if val.is_empty() { if val.is_empty() {
return Ok(Value::None); return Ok(Value::None);
@ -36,7 +36,7 @@ pub mod email {
pub fn user(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn user(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Check if value is empty // Check if value is empty
if val.is_empty() { if val.is_empty() {
return Ok(Value::None); return Ok(Value::None);
@ -69,7 +69,7 @@ pub mod url {
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => match v.domain() { Ok(v) => match v.domain() {
@ -82,7 +82,7 @@ pub mod url {
pub fn fragment(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn fragment(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => match v.fragment() { Ok(v) => match v.fragment() {
@ -95,7 +95,7 @@ pub mod url {
pub fn host(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn host(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => match v.host_str() { Ok(v) => match v.host_str() {
@ -108,7 +108,7 @@ pub mod url {
pub fn path(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn path(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => Ok(v.path().into()), Ok(v) => Ok(v.path().into()),
@ -118,7 +118,7 @@ pub mod url {
pub fn port(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn port(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => match v.port() { Ok(v) => match v.port() {
@ -131,7 +131,7 @@ pub mod url {
pub fn query(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn query(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String // Convert to a String
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
// Parse the URL // Parse the URL
match Url::parse(&val) { match Url::parse(&val) {
Ok(v) => match v.query() { Ok(v) => match v.query() {

View file

@ -4,51 +4,51 @@ use crate::sql::value::Value;
use slug::slugify; use slug::slugify;
pub fn concat(_: &Runtime, args: Vec<Value>) -> Result<Value, Error> { 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> { pub fn ends_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
let chr = args.remove(0).as_strand().value; let chr = args.remove(0).as_string();
Ok(val.ends_with(&chr).into()) Ok(val.ends_with(&chr).into())
} }
pub fn join(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn join(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let chr = args.remove(0).as_strand().value; let chr = args.remove(0).as_string();
let val = args.into_iter().map(|x| x.as_strand().value); let val = args.into_iter().map(|x| x.as_string());
let val = val.collect::<Vec<_>>().join(&chr); let val = val.collect::<Vec<_>>().join(&chr);
Ok(val.into()) Ok(val.into())
} }
pub fn length(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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; let num = val.chars().count() as i64;
Ok(num.into()) Ok(num.into())
} }
pub fn lowercase(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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> { 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; let num = args.remove(0).as_int() as usize;
Ok(val.repeat(num).into()) Ok(val.repeat(num).into())
} }
pub fn replace(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn replace(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
let old = args.remove(0).as_strand().value; let old = args.remove(0).as_string();
let new = args.remove(0).as_strand().value; let new = args.remove(0).as_string();
Ok(val.replace(&old, &new).into()) Ok(val.replace(&old, &new).into())
} }
pub fn reverse(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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> { 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 beg = args.remove(0).as_int() as usize;
let lim = 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>(); 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> { 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> { pub fn split(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
let chr = args.remove(0).as_strand().value; let chr = args.remove(0).as_string();
let val = val.split(&chr).collect::<Vec<&str>>(); let val = val.split(&chr).collect::<Vec<&str>>();
Ok(val.into()) Ok(val.into())
} }
pub fn starts_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { pub fn starts_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value; let val = args.remove(0).as_string();
let chr = args.remove(0).as_strand().value; let chr = args.remove(0).as_string();
Ok(val.starts_with(&chr).into()) Ok(val.starts_with(&chr).into())
} }
pub fn trim(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> { 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> { 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> { 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> { pub fn group(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) { match args.remove(0) {
Value::Datetime(v) => 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()), "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()), "month" => Ok(Utc.ymd(v.value.year(), v.value.month(), 1).and_hms(0, 0, 0).into()),
"day" => Ok(Utc "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); let tb = args.remove(0);
match args.remove(0) { match args.remove(0) {
Value::Thing(id) => Ok(Value::Thing(Thing { Value::Thing(id) => Ok(Value::Thing(Thing {
tb: tb.as_strand().value, tb: tb.as_string(),
id: id.id, id: id.id,
})), })),
id => Ok(Value::Thing(Thing { id => Ok(Value::Thing(Thing {
tb: tb.as_strand().value, tb: tb.as_string(),
id: id.as_strand().into(), 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::error::IResult;
use crate::sql::ident::ident_raw; use crate::sql::ident::ident_raw;
use crate::sql::number::{number, Number}; use crate::sql::number::{number, Number};
use crate::sql::strand::Strand;
use nanoid::nanoid; use nanoid::nanoid;
use nom::branch::alt; use nom::branch::alt;
use nom::combinator::map; 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 { impl From<&str> for Id {
fn from(v: &str) -> Self { fn from(v: &str) -> Self {
Id::String(v.to_owned()) Id::String(v.to_owned())

View file

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

View file

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

View file

@ -66,7 +66,7 @@ impl Value {
path, path,
value: { value: {
let mut dmp = dmp::new(); 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); let txt = dmp.patch_to_text(&mut pch);
txt.into() txt.into()
}, },

View file

@ -26,8 +26,8 @@ impl Value {
if let Value::Strand(p) = o.value { if let Value::Strand(p) = o.value {
if let Value::Strand(v) = self.get(ctx, opt, txn, &o.path).await? { if let Value::Strand(v) = self.get(ctx, opt, txn, &o.path).await? {
let mut dmp = dmp::new(); let mut dmp = dmp::new();
let mut pch = dmp.patch_from_text(p.value); let mut pch = dmp.patch_from_text(p.as_string());
let (txt, _) = dmp.patch_apply(&mut pch, &v.value); let (txt, _) = dmp.patch_apply(&mut pch, v.as_str());
let txt = txt.into_iter().collect::<String>(); let txt = txt.into_iter().collect::<String>();
self.set(ctx, opt, txn, &o.path, Value::from(txt)).await?; 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 { pub fn is_true(&self) -> bool {
match self { match self {
Value::True => true, Value::True => true,
Value::Strand(v) => v.value.to_ascii_lowercase() == "true", Value::Strand(v) => v.to_ascii_lowercase() == "true",
_ => false, _ => false,
} }
} }
@ -487,7 +487,7 @@ impl Value {
pub fn is_false(&self) -> bool { pub fn is_false(&self) -> bool {
match self { match self {
Value::False => true, Value::False => true,
Value::Strand(v) => v.value.to_ascii_lowercase() == "false", Value::Strand(v) => v.to_ascii_lowercase() == "false",
_ => false, _ => false,
} }
} }
@ -500,7 +500,7 @@ impl Value {
Value::Geometry(_) => true, Value::Geometry(_) => true,
Value::Array(v) => !v.is_empty(), Value::Array(v) => !v.is_empty(),
Value::Object(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::Number(v) => v.is_truthy(),
Value::Duration(v) => v.value.as_nanos() > 0, Value::Duration(v) => v.value.as_nanos() > 0,
Value::Datetime(v) => v.value.timestamp() > 0, Value::Datetime(v) => v.value.timestamp() > 0,
@ -549,7 +549,7 @@ impl Value {
pub fn as_int(self) -> i64 { pub fn as_int(self) -> i64 {
match self { match self {
Value::True => 1, 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::Number(v) => v.as_int(),
Value::Duration(v) => v.value.as_secs() as i64, Value::Duration(v) => v.value.as_secs() as i64,
Value::Datetime(v) => v.value.timestamp(), Value::Datetime(v) => v.value.timestamp(),
@ -560,7 +560,7 @@ impl Value {
pub fn as_float(self) -> f64 { pub fn as_float(self) -> f64 {
match self { match self {
Value::True => 1.0, 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::Number(v) => v.as_float(),
Value::Duration(v) => v.value.as_secs() as f64, Value::Duration(v) => v.value.as_secs() as f64,
Value::Datetime(v) => v.value.timestamp() 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 { pub fn as_strand(self) -> Strand {
match self { match self {
Value::Strand(v) => v, 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 // Expensive conversion of value
// ----------------------------------- // -----------------------------------
@ -660,7 +660,7 @@ impl Value {
pub fn to_idiom(&self) -> Idiom { pub fn to_idiom(&self) -> Idiom {
self.to_strand() self.to_strand()
.value .as_str()
.trim_start_matches('/') .trim_start_matches('/')
.split(&['.', '/'][..]) .split(&['.', '/'][..])
.map(Part::from) .map(Part::from)
@ -854,7 +854,7 @@ impl Value {
match self { match self {
Value::Strand(v) => match other { Value::Strand(v) => match other {
Value::Strand(w) => MATCHER.fuzzy_match(v.as_str(), w.as_str()).is_some(), 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), _ => self.equal(other),
} }
@ -878,8 +878,8 @@ impl Value {
match self { match self {
Value::Array(v) => v.iter().any(|v| v.equal(other)), Value::Array(v) => v.iter().any(|v| v.equal(other)),
Value::Strand(v) => match other { Value::Strand(v) => match other {
Value::Strand(w) => v.value.contains(w.as_str()), Value::Strand(w) => v.contains(w.as_str()),
_ => v.value.contains(&other.to_strand().as_str()), _ => v.contains(&other.to_string().as_str()),
}, },
Value::Geometry(v) => match other { Value::Geometry(v) => match other {
Value::Geometry(w) => v.contains(w), Value::Geometry(w) => v.contains(w),
@ -927,27 +927,21 @@ impl Value {
pub fn lexical_cmp(&self, other: &Value) -> Option<Ordering> { pub fn lexical_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) { match (self, other) {
(Value::Strand(a), Value::Strand(b)) => { (Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::lexical_cmp(a, b)),
Some(lexical_sort::lexical_cmp(&a.value, &b.value))
}
_ => self.partial_cmp(other), _ => self.partial_cmp(other),
} }
} }
pub fn natural_cmp(&self, other: &Value) -> Option<Ordering> { pub fn natural_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) { match (self, other) {
(Value::Strand(a), Value::Strand(b)) => { (Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::natural_cmp(a, b)),
Some(lexical_sort::natural_cmp(&a.value, &b.value))
}
_ => self.partial_cmp(other), _ => self.partial_cmp(other),
} }
} }
pub fn natural_lexical_cmp(&self, other: &Value) -> Option<Ordering> { pub fn natural_lexical_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) { match (self, other) {
(Value::Strand(a), Value::Strand(b)) => { (Value::Strand(a), Value::Strand(b)) => Some(lexical_sort::natural_lexical_cmp(a, b)),
Some(lexical_sort::natural_lexical_cmp(&a.value, &b.value))
}
_ => self.partial_cmp(other), _ => self.partial_cmp(other),
} }
} }
@ -1330,6 +1324,24 @@ mod tests {
assert_eq!(Strand::from("something"), Value::from("something").as_strand()); 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] #[test]
fn serialize_deserialize() { fn serialize_deserialize() {
let val = Value::parse( let val = Value::parse(