Add UUID data type to SQL for efficient storage of UUIDs
This commit is contained in:
parent
d04db02ee0
commit
ccdce709f2
7 changed files with 164 additions and 18 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2623,9 +2623,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
|||
|
||||
[[package]]
|
||||
name = "storekey"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c486bc18d702687cb3265288657cfe89df0f2f1a88900f104a2cc86889bddd7"
|
||||
checksum = "3c05ac79ed7dcd90b469801242eb9f348cd5749404a567bf36d2d6c3c5ff6698"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
|
|
|
@ -43,7 +43,7 @@ regex = "1.5.6"
|
|||
msgpack = { version = "1.1.0", package = "rmp-serde" }
|
||||
scrypt = "0.10.0"
|
||||
serde = { version = "1.0.137", features = ["derive"] }
|
||||
storekey = "0.2.0"
|
||||
storekey = "0.3.0"
|
||||
sha-1 = "0.10.0"
|
||||
sha2 = "0.10.2"
|
||||
slug = "0.1.4"
|
||||
|
|
|
@ -2,11 +2,11 @@ use crate::cnf::ID_CHARS;
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::datetime::Datetime;
|
||||
use crate::sql::uuid::Uuid;
|
||||
use crate::sql::value::Value;
|
||||
use nanoid::nanoid;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn rand(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(rand::random::<f64>().into())
|
||||
|
@ -147,5 +147,5 @@ pub fn time(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
|
||||
pub fn uuid(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(Uuid::new_v4().to_string().into())
|
||||
Ok(Uuid::new().into())
|
||||
}
|
||||
|
|
|
@ -23,6 +23,11 @@ pub fn commas(i: &str) -> IResult<&str, ()> {
|
|||
Ok((i, ()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_hex(chr: char) -> bool {
|
||||
chr.is_ascii_hexdigit()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_digit(chr: char) -> bool {
|
||||
(0x30..=0x39).contains(&(chr as u8))
|
||||
|
|
|
@ -48,6 +48,7 @@ pub(crate) mod subquery;
|
|||
pub(crate) mod table;
|
||||
pub(crate) mod thing;
|
||||
pub(crate) mod timeout;
|
||||
pub(crate) mod uuid;
|
||||
pub(crate) mod value;
|
||||
pub(crate) mod version;
|
||||
pub(crate) mod view;
|
||||
|
@ -112,6 +113,7 @@ pub use self::table::Table;
|
|||
pub use self::table::Tables;
|
||||
pub use self::thing::Thing;
|
||||
pub use self::timeout::Timeout;
|
||||
pub use self::uuid::Uuid;
|
||||
pub use self::value::Value;
|
||||
pub use self::value::Values;
|
||||
pub use self::version::Version;
|
||||
|
|
121
lib/src/sql/uuid.rs
Normal file
121
lib/src/sql/uuid.rs
Normal file
|
@ -0,0 +1,121 @@
|
|||
use crate::sql::common::is_hex;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::serde::is_internal_serialization;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::take_while_m_n;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::recognize;
|
||||
use nom::sequence::delimited;
|
||||
use nom::sequence::tuple;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
|
||||
const SINGLE: char = '\'';
|
||||
const DOUBLE: char = '"';
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
|
||||
pub struct Uuid(pub uuid::Uuid);
|
||||
|
||||
impl From<&str> for Uuid {
|
||||
fn from(s: &str) -> Self {
|
||||
match uuid::Uuid::try_parse(s) {
|
||||
Ok(v) => Uuid(v),
|
||||
_ => Uuid::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Uuid {
|
||||
fn from(s: String) -> Self {
|
||||
match uuid::Uuid::try_parse(&s) {
|
||||
Ok(v) => Uuid(v),
|
||||
_ => Uuid::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Uuid {
|
||||
type Target = uuid::Uuid;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Uuid {
|
||||
pub fn new() -> Self {
|
||||
Uuid(uuid::Uuid::new_v4())
|
||||
}
|
||||
pub fn to_raw(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Uuid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\"{}\"", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Uuid {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
if is_internal_serialization() {
|
||||
serializer.serialize_newtype_struct("Uuid", &self.0)
|
||||
} else {
|
||||
serializer.serialize_some(&self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uuid(i: &str) -> IResult<&str, Uuid> {
|
||||
alt((
|
||||
delimited(char(DOUBLE), uuid_raw, char(DOUBLE)),
|
||||
delimited(char(SINGLE), uuid_raw, char(SINGLE)),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn uuid_raw(i: &str) -> IResult<&str, Uuid> {
|
||||
let (i, v) = recognize(tuple((
|
||||
take_while_m_n(8, 8, is_hex),
|
||||
char('-'),
|
||||
take_while_m_n(4, 4, is_hex),
|
||||
char('-'),
|
||||
alt((char('1'), char('2'), char('3'), char('4'))),
|
||||
take_while_m_n(3, 3, is_hex),
|
||||
char('-'),
|
||||
take_while_m_n(4, 4, is_hex),
|
||||
char('-'),
|
||||
take_while_m_n(12, 12, is_hex),
|
||||
)))(i)?;
|
||||
Ok((i, Uuid::from(v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn uuid_v1() {
|
||||
let sql = "e72bee20-f49b-11ec-b939-0242ac120002";
|
||||
let res = uuid_raw(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("\"e72bee20-f49b-11ec-b939-0242ac120002\"", format!("{}", out));
|
||||
assert_eq!(out, Uuid::from("e72bee20-f49b-11ec-b939-0242ac120002"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid_v4() {
|
||||
let sql = "b19bc00b-aa98-486c-ae37-c8e1c54295b1";
|
||||
let res = uuid_raw(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!("\"b19bc00b-aa98-486c-ae37-c8e1c54295b1\"", format!("{}", out));
|
||||
assert_eq!(out, Uuid::from("b19bc00b-aa98-486c-ae37-c8e1c54295b1"));
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ use crate::sql::strand::{strand, Strand};
|
|||
use crate::sql::subquery::{subquery, Subquery};
|
||||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::thing::{thing, Thing};
|
||||
use crate::sql::uuid::{uuid as unique, Uuid};
|
||||
use async_recursion::async_recursion;
|
||||
use bigdecimal::BigDecimal;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -101,6 +102,7 @@ pub enum Value {
|
|||
Strand(Strand),
|
||||
Duration(Duration),
|
||||
Datetime(Datetime),
|
||||
Uuid(Uuid),
|
||||
Array(Array),
|
||||
Object(Object),
|
||||
Geometry(Geometry),
|
||||
|
@ -140,6 +142,12 @@ impl From<bool> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for Value {
|
||||
fn from(v: Uuid) -> Self {
|
||||
Value::Uuid(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Param> for Value {
|
||||
fn from(v: Param) -> Self {
|
||||
Value::Param(v)
|
||||
|
@ -823,6 +831,10 @@ impl Value {
|
|||
},
|
||||
_ => false,
|
||||
},
|
||||
Value::Uuid(v) => match other {
|
||||
Value::Uuid(w) => v == w,
|
||||
_ => false,
|
||||
},
|
||||
Value::Array(v) => match other {
|
||||
Value::Array(w) => v == w,
|
||||
_ => false,
|
||||
|
@ -989,6 +1001,7 @@ impl fmt::Display for Value {
|
|||
Value::Strand(v) => write!(f, "{}", v),
|
||||
Value::Duration(v) => write!(f, "{}", v),
|
||||
Value::Datetime(v) => write!(f, "{}", v),
|
||||
Value::Uuid(v) => write!(f, "{}", v),
|
||||
Value::Array(v) => write!(f, "{}", v),
|
||||
Value::Object(v) => write!(f, "{}", v),
|
||||
Value::Geometry(v) => write!(f, "{}", v),
|
||||
|
@ -1061,19 +1074,20 @@ impl Serialize for Value {
|
|||
Value::Strand(v) => s.serialize_newtype_variant("Value", 6, "Strand", v),
|
||||
Value::Duration(v) => s.serialize_newtype_variant("Value", 7, "Duration", v),
|
||||
Value::Datetime(v) => s.serialize_newtype_variant("Value", 8, "Datetime", v),
|
||||
Value::Array(v) => s.serialize_newtype_variant("Value", 9, "Array", v),
|
||||
Value::Object(v) => s.serialize_newtype_variant("Value", 10, "Object", v),
|
||||
Value::Geometry(v) => s.serialize_newtype_variant("Value", 11, "Geometry", v),
|
||||
Value::Param(v) => s.serialize_newtype_variant("Value", 12, "Param", v),
|
||||
Value::Idiom(v) => s.serialize_newtype_variant("Value", 13, "Idiom", v),
|
||||
Value::Table(v) => s.serialize_newtype_variant("Value", 14, "Table", v),
|
||||
Value::Thing(v) => s.serialize_newtype_variant("Value", 15, "Thing", v),
|
||||
Value::Model(v) => s.serialize_newtype_variant("Value", 16, "Model", v),
|
||||
Value::Regex(v) => s.serialize_newtype_variant("Value", 17, "Regex", v),
|
||||
Value::Edges(v) => s.serialize_newtype_variant("Value", 18, "Edges", v),
|
||||
Value::Function(v) => s.serialize_newtype_variant("Value", 19, "Function", v),
|
||||
Value::Subquery(v) => s.serialize_newtype_variant("Value", 20, "Subquery", v),
|
||||
Value::Expression(v) => s.serialize_newtype_variant("Value", 21, "Expression", v),
|
||||
Value::Uuid(v) => s.serialize_newtype_variant("Value", 9, "Uuid", v),
|
||||
Value::Array(v) => s.serialize_newtype_variant("Value", 10, "Array", v),
|
||||
Value::Object(v) => s.serialize_newtype_variant("Value", 11, "Object", v),
|
||||
Value::Geometry(v) => s.serialize_newtype_variant("Value", 12, "Geometry", v),
|
||||
Value::Param(v) => s.serialize_newtype_variant("Value", 13, "Param", v),
|
||||
Value::Idiom(v) => s.serialize_newtype_variant("Value", 14, "Idiom", v),
|
||||
Value::Table(v) => s.serialize_newtype_variant("Value", 15, "Table", v),
|
||||
Value::Thing(v) => s.serialize_newtype_variant("Value", 16, "Thing", v),
|
||||
Value::Model(v) => s.serialize_newtype_variant("Value", 17, "Model", v),
|
||||
Value::Regex(v) => s.serialize_newtype_variant("Value", 18, "Regex", v),
|
||||
Value::Edges(v) => s.serialize_newtype_variant("Value", 19, "Edges", v),
|
||||
Value::Function(v) => s.serialize_newtype_variant("Value", 20, "Function", v),
|
||||
Value::Subquery(v) => s.serialize_newtype_variant("Value", 21, "Subquery", v),
|
||||
Value::Expression(v) => s.serialize_newtype_variant("Value", 22, "Expression", v),
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
|
@ -1083,6 +1097,7 @@ impl Serialize for Value {
|
|||
Value::True => s.serialize_bool(true),
|
||||
Value::False => s.serialize_bool(false),
|
||||
Value::Thing(v) => s.serialize_some(v),
|
||||
Value::Uuid(v) => s.serialize_some(v),
|
||||
Value::Array(v) => s.serialize_some(v),
|
||||
Value::Object(v) => s.serialize_some(v),
|
||||
Value::Number(v) => s.serialize_some(v),
|
||||
|
@ -1164,6 +1179,7 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
|||
map(datetime, Value::from),
|
||||
map(duration, Value::from),
|
||||
map(geometry, Value::from),
|
||||
map(unique, Value::from),
|
||||
map(number, Value::from),
|
||||
map(strand, Value::from),
|
||||
map(object, Value::from),
|
||||
|
@ -1188,6 +1204,7 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
|||
map(datetime, Value::from),
|
||||
map(duration, Value::from),
|
||||
map(geometry, Value::from),
|
||||
map(unique, Value::from),
|
||||
map(number, Value::from),
|
||||
map(strand, Value::from),
|
||||
map(object, Value::from),
|
||||
|
@ -1221,6 +1238,7 @@ pub fn json(i: &str) -> IResult<&str, Value> {
|
|||
map(datetime, Value::from),
|
||||
map(duration, Value::from),
|
||||
map(geometry, Value::from),
|
||||
map(unique, Value::from),
|
||||
map(number, Value::from),
|
||||
map(object, Value::from),
|
||||
map(array, Value::from),
|
||||
|
|
Loading…
Reference in a new issue