Allow generating ulid and uuid based on a timestamp (#4384)
This commit is contained in:
parent
c471dc0317
commit
70c682987c
3 changed files with 131 additions and 6 deletions
|
@ -2,6 +2,7 @@ use crate::cnf::ID_CHARS;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::uuid::Uuid;
|
use crate::sql::uuid::Uuid;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
use crate::sql::Datetime;
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use rand::distributions::{Alphanumeric, DistString};
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
|
@ -150,12 +151,21 @@ pub fn time((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
||||||
Ok(Utc.timestamp_opt(val, 0).earliest().unwrap().into())
|
Ok(Utc.timestamp_opt(val, 0).earliest().unwrap().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ulid(_: ()) -> Result<Value, Error> {
|
pub fn ulid((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||||
Ok(Ulid::new().to_string().into())
|
let ulid = match timestamp {
|
||||||
|
Some(timestamp) => Ulid::from_datetime(timestamp.0.into()),
|
||||||
|
None => Ulid::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ulid.to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uuid(_: ()) -> Result<Value, Error> {
|
pub fn uuid((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||||
Ok(Uuid::new().into())
|
let uuid = match timestamp {
|
||||||
|
Some(timestamp) => Uuid::new_v7_from_datetime(timestamp),
|
||||||
|
None => Uuid::new(),
|
||||||
|
};
|
||||||
|
Ok(uuid.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod uuid {
|
pub mod uuid {
|
||||||
|
@ -163,12 +173,17 @@ pub mod uuid {
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::uuid::Uuid;
|
use crate::sql::uuid::Uuid;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
use crate::sql::Datetime;
|
||||||
|
|
||||||
pub fn v4(_: ()) -> Result<Value, Error> {
|
pub fn v4(_: ()) -> Result<Value, Error> {
|
||||||
Ok(Uuid::new_v4().into())
|
Ok(Uuid::new_v4().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn v7(_: ()) -> Result<Value, Error> {
|
pub fn v7((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||||
Ok(Uuid::new_v7().into())
|
let uuid = match timestamp {
|
||||||
|
Some(timestamp) => Uuid::new_v7_from_datetime(timestamp),
|
||||||
|
None => Uuid::new(),
|
||||||
|
};
|
||||||
|
Ok(uuid.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ use std::ops::Deref;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use super::Datetime;
|
||||||
|
|
||||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Uuid";
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Uuid";
|
||||||
|
|
||||||
#[revisioned(revision = 1)]
|
#[revisioned(revision = 1)]
|
||||||
|
@ -78,6 +80,15 @@ impl Uuid {
|
||||||
pub fn new_v7() -> Self {
|
pub fn new_v7() -> Self {
|
||||||
Self(uuid::Uuid::now_v7())
|
Self(uuid::Uuid::now_v7())
|
||||||
}
|
}
|
||||||
|
/// Generate a new V7 UUID
|
||||||
|
pub fn new_v7_from_datetime(timestamp: Datetime) -> Self {
|
||||||
|
let ts = uuid::Timestamp::from_unix(
|
||||||
|
uuid::NoContext,
|
||||||
|
timestamp.0.timestamp() as u64,
|
||||||
|
timestamp.0.timestamp_subsec_nanos(),
|
||||||
|
);
|
||||||
|
Self(uuid::Uuid::new_v7(ts))
|
||||||
|
}
|
||||||
/// Convert the Uuid to a raw String
|
/// Convert the Uuid to a raw String
|
||||||
pub fn to_raw(&self) -> String {
|
pub fn to_raw(&self) -> String {
|
||||||
self.0.to_string()
|
self.0.to_string()
|
||||||
|
|
|
@ -2953,6 +2953,39 @@ async fn function_rand_ulid() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn function_rand_ulid_from_datetime() -> Result<(), Error> {
|
||||||
|
let sql = r#"
|
||||||
|
CREATE ONLY test:[rand::ulid()] SET created = time::now(), num = 1;
|
||||||
|
SLEEP 1ms;
|
||||||
|
LET $rec = CREATE ONLY test:[rand::ulid()] SET created = time::now(), num = 2;
|
||||||
|
SLEEP 1ms;
|
||||||
|
CREATE ONLY test:[rand::ulid()] SET created = time::now(), num = 3;
|
||||||
|
SELECT VALUE num FROM test:[rand::ulid($rec.created - 1ms)]..;
|
||||||
|
"#;
|
||||||
|
let mut test = Test::new(sql).await?;
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert_eq!(tmp, Value::parse("[2, 3]"));
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn function_rand_uuid() -> Result<(), Error> {
|
async fn function_rand_uuid() -> Result<(), Error> {
|
||||||
let sql = r#"
|
let sql = r#"
|
||||||
|
@ -2966,6 +2999,39 @@ async fn function_rand_uuid() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn function_rand_uuid_from_datetime() -> Result<(), Error> {
|
||||||
|
let sql = r#"
|
||||||
|
CREATE ONLY test:[rand::uuid()] SET created = time::now(), num = 1;
|
||||||
|
SLEEP 1ms;
|
||||||
|
LET $rec = CREATE ONLY test:[rand::uuid()] SET created = time::now(), num = 2;
|
||||||
|
SLEEP 1ms;
|
||||||
|
CREATE ONLY test:[rand::uuid()] SET created = time::now(), num = 3;
|
||||||
|
SELECT VALUE num FROM test:[rand::uuid($rec.created - 1ms)]..;
|
||||||
|
"#;
|
||||||
|
let mut test = Test::new(sql).await?;
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert_eq!(tmp, Value::parse("[2, 3]"));
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn function_rand_uuid_v4() -> Result<(), Error> {
|
async fn function_rand_uuid_v4() -> Result<(), Error> {
|
||||||
let sql = r#"
|
let sql = r#"
|
||||||
|
@ -2992,6 +3058,39 @@ async fn function_rand_uuid_v7() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn function_rand_uuid_v7_from_datetime() -> Result<(), Error> {
|
||||||
|
let sql = r#"
|
||||||
|
CREATE ONLY test:[rand::uuid::v7()] SET created = time::now(), num = 1;
|
||||||
|
SLEEP 1ms;
|
||||||
|
LET $rec = CREATE ONLY test:[rand::uuid::v7()] SET created = time::now(), num = 2;
|
||||||
|
SLEEP 1ms;
|
||||||
|
CREATE ONLY test:[rand::uuid::v7()] SET created = time::now(), num = 3;
|
||||||
|
SELECT VALUE num FROM test:[rand::uuid::v7($rec.created - 1ms)]..;
|
||||||
|
"#;
|
||||||
|
let mut test = Test::new(sql).await?;
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_none());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert!(tmp.is_object());
|
||||||
|
//
|
||||||
|
let tmp = test.next()?.result?;
|
||||||
|
assert_eq!(tmp, Value::parse("[2, 3]"));
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// string
|
// string
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue