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::sql::uuid::Uuid;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Datetime;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use nanoid::nanoid;
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn ulid(_: ()) -> Result<Value, Error> {
|
||||
Ok(Ulid::new().to_string().into())
|
||||
pub fn ulid((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||
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> {
|
||||
Ok(Uuid::new().into())
|
||||
pub fn uuid((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||
let uuid = match timestamp {
|
||||
Some(timestamp) => Uuid::new_v7_from_datetime(timestamp),
|
||||
None => Uuid::new(),
|
||||
};
|
||||
Ok(uuid.into())
|
||||
}
|
||||
|
||||
pub mod uuid {
|
||||
|
@ -163,12 +173,17 @@ pub mod uuid {
|
|||
use crate::err::Error;
|
||||
use crate::sql::uuid::Uuid;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Datetime;
|
||||
|
||||
pub fn v4(_: ()) -> Result<Value, Error> {
|
||||
Ok(Uuid::new_v4().into())
|
||||
}
|
||||
|
||||
pub fn v7(_: ()) -> Result<Value, Error> {
|
||||
Ok(Uuid::new_v7().into())
|
||||
pub fn v7((timestamp,): (Option<Datetime>,)) -> Result<Value, Error> {
|
||||
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::FromStr;
|
||||
|
||||
use super::Datetime;
|
||||
|
||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Uuid";
|
||||
|
||||
#[revisioned(revision = 1)]
|
||||
|
@ -78,6 +80,15 @@ impl Uuid {
|
|||
pub fn new_v7() -> Self {
|
||||
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
|
||||
pub fn to_raw(&self) -> String {
|
||||
self.0.to_string()
|
||||
|
|
|
@ -2953,6 +2953,39 @@ async fn function_rand_ulid() -> Result<(), Error> {
|
|||
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]
|
||||
async fn function_rand_uuid() -> Result<(), Error> {
|
||||
let sql = r#"
|
||||
|
@ -2966,6 +2999,39 @@ async fn function_rand_uuid() -> Result<(), Error> {
|
|||
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]
|
||||
async fn function_rand_uuid_v4() -> Result<(), Error> {
|
||||
let sql = r#"
|
||||
|
@ -2992,6 +3058,39 @@ async fn function_rand_uuid_v7() -> Result<(), Error> {
|
|||
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
|
||||
// --------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue