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]]
|
[[package]]
|
||||||
name = "storekey"
|
name = "storekey"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c486bc18d702687cb3265288657cfe89df0f2f1a88900f104a2cc86889bddd7"
|
checksum = "3c05ac79ed7dcd90b469801242eb9f348cd5749404a567bf36d2d6c3c5ff6698"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -43,7 +43,7 @@ regex = "1.5.6"
|
||||||
msgpack = { version = "1.1.0", package = "rmp-serde" }
|
msgpack = { version = "1.1.0", package = "rmp-serde" }
|
||||||
scrypt = "0.10.0"
|
scrypt = "0.10.0"
|
||||||
serde = { version = "1.0.137", features = ["derive"] }
|
serde = { version = "1.0.137", features = ["derive"] }
|
||||||
storekey = "0.2.0"
|
storekey = "0.3.0"
|
||||||
sha-1 = "0.10.0"
|
sha-1 = "0.10.0"
|
||||||
sha2 = "0.10.2"
|
sha2 = "0.10.2"
|
||||||
slug = "0.1.4"
|
slug = "0.1.4"
|
||||||
|
|
|
@ -2,11 +2,11 @@ use crate::cnf::ID_CHARS;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::datetime::Datetime;
|
use crate::sql::datetime::Datetime;
|
||||||
|
use crate::sql::uuid::Uuid;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distributions::Alphanumeric;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
pub fn rand(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
pub fn rand(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||||
Ok(rand::random::<f64>().into())
|
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> {
|
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, ()))
|
Ok((i, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_hex(chr: char) -> bool {
|
||||||
|
chr.is_ascii_hexdigit()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_digit(chr: char) -> bool {
|
pub fn is_digit(chr: char) -> bool {
|
||||||
(0x30..=0x39).contains(&(chr as u8))
|
(0x30..=0x39).contains(&(chr as u8))
|
||||||
|
|
|
@ -48,6 +48,7 @@ pub(crate) mod subquery;
|
||||||
pub(crate) mod table;
|
pub(crate) mod table;
|
||||||
pub(crate) mod thing;
|
pub(crate) mod thing;
|
||||||
pub(crate) mod timeout;
|
pub(crate) mod timeout;
|
||||||
|
pub(crate) mod uuid;
|
||||||
pub(crate) mod value;
|
pub(crate) mod value;
|
||||||
pub(crate) mod version;
|
pub(crate) mod version;
|
||||||
pub(crate) mod view;
|
pub(crate) mod view;
|
||||||
|
@ -112,6 +113,7 @@ pub use self::table::Table;
|
||||||
pub use self::table::Tables;
|
pub use self::table::Tables;
|
||||||
pub use self::thing::Thing;
|
pub use self::thing::Thing;
|
||||||
pub use self::timeout::Timeout;
|
pub use self::timeout::Timeout;
|
||||||
|
pub use self::uuid::Uuid;
|
||||||
pub use self::value::Value;
|
pub use self::value::Value;
|
||||||
pub use self::value::Values;
|
pub use self::value::Values;
|
||||||
pub use self::version::Version;
|
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::subquery::{subquery, Subquery};
|
||||||
use crate::sql::table::{table, Table};
|
use crate::sql::table::{table, Table};
|
||||||
use crate::sql::thing::{thing, Thing};
|
use crate::sql::thing::{thing, Thing};
|
||||||
|
use crate::sql::uuid::{uuid as unique, Uuid};
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use bigdecimal::BigDecimal;
|
use bigdecimal::BigDecimal;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
@ -101,6 +102,7 @@ pub enum Value {
|
||||||
Strand(Strand),
|
Strand(Strand),
|
||||||
Duration(Duration),
|
Duration(Duration),
|
||||||
Datetime(Datetime),
|
Datetime(Datetime),
|
||||||
|
Uuid(Uuid),
|
||||||
Array(Array),
|
Array(Array),
|
||||||
Object(Object),
|
Object(Object),
|
||||||
Geometry(Geometry),
|
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 {
|
impl From<Param> for Value {
|
||||||
fn from(v: Param) -> Self {
|
fn from(v: Param) -> Self {
|
||||||
Value::Param(v)
|
Value::Param(v)
|
||||||
|
@ -823,6 +831,10 @@ impl Value {
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
Value::Uuid(v) => match other {
|
||||||
|
Value::Uuid(w) => v == w,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
Value::Array(v) => match other {
|
Value::Array(v) => match other {
|
||||||
Value::Array(w) => v == w,
|
Value::Array(w) => v == w,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -989,6 +1001,7 @@ impl fmt::Display for Value {
|
||||||
Value::Strand(v) => write!(f, "{}", v),
|
Value::Strand(v) => write!(f, "{}", v),
|
||||||
Value::Duration(v) => write!(f, "{}", v),
|
Value::Duration(v) => write!(f, "{}", v),
|
||||||
Value::Datetime(v) => write!(f, "{}", v),
|
Value::Datetime(v) => write!(f, "{}", v),
|
||||||
|
Value::Uuid(v) => write!(f, "{}", v),
|
||||||
Value::Array(v) => write!(f, "{}", v),
|
Value::Array(v) => write!(f, "{}", v),
|
||||||
Value::Object(v) => write!(f, "{}", v),
|
Value::Object(v) => write!(f, "{}", v),
|
||||||
Value::Geometry(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::Strand(v) => s.serialize_newtype_variant("Value", 6, "Strand", v),
|
||||||
Value::Duration(v) => s.serialize_newtype_variant("Value", 7, "Duration", v),
|
Value::Duration(v) => s.serialize_newtype_variant("Value", 7, "Duration", v),
|
||||||
Value::Datetime(v) => s.serialize_newtype_variant("Value", 8, "Datetime", v),
|
Value::Datetime(v) => s.serialize_newtype_variant("Value", 8, "Datetime", v),
|
||||||
Value::Array(v) => s.serialize_newtype_variant("Value", 9, "Array", v),
|
Value::Uuid(v) => s.serialize_newtype_variant("Value", 9, "Uuid", v),
|
||||||
Value::Object(v) => s.serialize_newtype_variant("Value", 10, "Object", v),
|
Value::Array(v) => s.serialize_newtype_variant("Value", 10, "Array", v),
|
||||||
Value::Geometry(v) => s.serialize_newtype_variant("Value", 11, "Geometry", v),
|
Value::Object(v) => s.serialize_newtype_variant("Value", 11, "Object", v),
|
||||||
Value::Param(v) => s.serialize_newtype_variant("Value", 12, "Param", v),
|
Value::Geometry(v) => s.serialize_newtype_variant("Value", 12, "Geometry", v),
|
||||||
Value::Idiom(v) => s.serialize_newtype_variant("Value", 13, "Idiom", v),
|
Value::Param(v) => s.serialize_newtype_variant("Value", 13, "Param", v),
|
||||||
Value::Table(v) => s.serialize_newtype_variant("Value", 14, "Table", v),
|
Value::Idiom(v) => s.serialize_newtype_variant("Value", 14, "Idiom", v),
|
||||||
Value::Thing(v) => s.serialize_newtype_variant("Value", 15, "Thing", v),
|
Value::Table(v) => s.serialize_newtype_variant("Value", 15, "Table", v),
|
||||||
Value::Model(v) => s.serialize_newtype_variant("Value", 16, "Model", v),
|
Value::Thing(v) => s.serialize_newtype_variant("Value", 16, "Thing", v),
|
||||||
Value::Regex(v) => s.serialize_newtype_variant("Value", 17, "Regex", v),
|
Value::Model(v) => s.serialize_newtype_variant("Value", 17, "Model", v),
|
||||||
Value::Edges(v) => s.serialize_newtype_variant("Value", 18, "Edges", v),
|
Value::Regex(v) => s.serialize_newtype_variant("Value", 18, "Regex", v),
|
||||||
Value::Function(v) => s.serialize_newtype_variant("Value", 19, "Function", v),
|
Value::Edges(v) => s.serialize_newtype_variant("Value", 19, "Edges", v),
|
||||||
Value::Subquery(v) => s.serialize_newtype_variant("Value", 20, "Subquery", v),
|
Value::Function(v) => s.serialize_newtype_variant("Value", 20, "Function", v),
|
||||||
Value::Expression(v) => s.serialize_newtype_variant("Value", 21, "Expression", v),
|
Value::Subquery(v) => s.serialize_newtype_variant("Value", 21, "Subquery", v),
|
||||||
|
Value::Expression(v) => s.serialize_newtype_variant("Value", 22, "Expression", v),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1083,6 +1097,7 @@ impl Serialize for Value {
|
||||||
Value::True => s.serialize_bool(true),
|
Value::True => s.serialize_bool(true),
|
||||||
Value::False => s.serialize_bool(false),
|
Value::False => s.serialize_bool(false),
|
||||||
Value::Thing(v) => s.serialize_some(v),
|
Value::Thing(v) => s.serialize_some(v),
|
||||||
|
Value::Uuid(v) => s.serialize_some(v),
|
||||||
Value::Array(v) => s.serialize_some(v),
|
Value::Array(v) => s.serialize_some(v),
|
||||||
Value::Object(v) => s.serialize_some(v),
|
Value::Object(v) => s.serialize_some(v),
|
||||||
Value::Number(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(datetime, Value::from),
|
||||||
map(duration, Value::from),
|
map(duration, Value::from),
|
||||||
map(geometry, Value::from),
|
map(geometry, Value::from),
|
||||||
|
map(unique, Value::from),
|
||||||
map(number, Value::from),
|
map(number, Value::from),
|
||||||
map(strand, Value::from),
|
map(strand, Value::from),
|
||||||
map(object, Value::from),
|
map(object, Value::from),
|
||||||
|
@ -1188,6 +1204,7 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
map(datetime, Value::from),
|
map(datetime, Value::from),
|
||||||
map(duration, Value::from),
|
map(duration, Value::from),
|
||||||
map(geometry, Value::from),
|
map(geometry, Value::from),
|
||||||
|
map(unique, Value::from),
|
||||||
map(number, Value::from),
|
map(number, Value::from),
|
||||||
map(strand, Value::from),
|
map(strand, Value::from),
|
||||||
map(object, Value::from),
|
map(object, Value::from),
|
||||||
|
@ -1221,6 +1238,7 @@ pub fn json(i: &str) -> IResult<&str, Value> {
|
||||||
map(datetime, Value::from),
|
map(datetime, Value::from),
|
||||||
map(duration, Value::from),
|
map(duration, Value::from),
|
||||||
map(geometry, Value::from),
|
map(geometry, Value::from),
|
||||||
|
map(unique, Value::from),
|
||||||
map(number, Value::from),
|
map(number, Value::from),
|
||||||
map(object, Value::from),
|
map(object, Value::from),
|
||||||
map(array, Value::from),
|
map(array, Value::from),
|
||||||
|
|
Loading…
Reference in a new issue