Delay Record ID generation when using functions (#2469)

This commit is contained in:
Tobie Morgan Hitchcock 2023-08-20 04:27:20 +01:00 committed by GitHub
parent 1fd6d991ae
commit f01da5f577
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 12 deletions

View file

@ -17,7 +17,7 @@ resolver = "2"
[features] [features]
# Public features # Public features
default = ["protocol-ws", "rustls"] default = ["protocol-ws", "rustls", "kv-mem"]
protocol-http = ["dep:reqwest", "dep:tokio-util"] protocol-http = ["dep:reqwest", "dep:tokio-util"]
protocol-ws = ["dep:tokio-tungstenite", "tokio/time"] protocol-ws = ["dep:tokio-tungstenite", "tokio/time"]
kv-mem = ["dep:echodb", "tokio/time"] kv-mem = ["dep:echodb", "tokio/time"]

View file

@ -11,6 +11,7 @@ mod tls;
use crate::api::err::Error; use crate::api::err::Error;
use crate::sql::constant::ConstantValue; use crate::sql::constant::ConstantValue;
use crate::sql::id::Gen;
use crate::sql::to_value; use crate::sql::to_value;
use crate::sql::Thing; use crate::sql::Thing;
use crate::sql::Value; use crate::sql::Value;
@ -325,6 +326,11 @@ fn into_json(value: Value, simplify: bool) -> JsonValue {
sql::Id::String(s) => Id::String(s), sql::Id::String(s) => Id::String(s),
sql::Id::Array(arr) => Id::Array((arr, simplify).into()), sql::Id::Array(arr) => Id::Array((arr, simplify).into()),
sql::Id::Object(obj) => Id::Object((obj, simplify).into()), sql::Id::Object(obj) => Id::Object((obj, simplify).into()),
sql::Id::Generate(v) => match v {
Gen::Rand => Id::from((sql::Id::rand(), simplify)),
Gen::Ulid => Id::from((sql::Id::ulid(), simplify)),
Gen::Uuid => Id::from((sql::Id::uuid(), simplify)),
},
} }
} }
} }

View file

@ -22,6 +22,14 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use ulid::Ulid; use ulid::Ulid;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
#[revisioned(revision = 1)]
pub enum Gen {
Rand,
Ulid,
Uuid,
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 1)]
pub enum Id { pub enum Id {
@ -29,6 +37,7 @@ pub enum Id {
String(String), String(String),
Array(Array), Array(Array),
Object(Object), Object(Object),
Generate(Gen),
} }
impl From<i64> for Id { impl From<i64> for Id {
@ -149,8 +158,13 @@ impl Id {
match self { match self {
Self::Number(v) => v.to_string(), Self::Number(v) => v.to_string(),
Self::String(v) => v.to_string(), Self::String(v) => v.to_string(),
Self::Object(v) => v.to_string(),
Self::Array(v) => v.to_string(), Self::Array(v) => v.to_string(),
Self::Object(v) => v.to_string(),
Self::Generate(v) => match v {
Gen::Rand => "rand()".to_string(),
Gen::Ulid => "ulid()".to_string(),
Gen::Uuid => "uuid()".to_string(),
},
} }
} }
} }
@ -160,8 +174,13 @@ impl Display for Id {
match self { match self {
Self::Number(v) => Display::fmt(v, f), Self::Number(v) => Display::fmt(v, f),
Self::String(v) => Display::fmt(&escape_rid(v), f), Self::String(v) => Display::fmt(&escape_rid(v), f),
Self::Object(v) => Display::fmt(v, f),
Self::Array(v) => Display::fmt(v, f), Self::Array(v) => Display::fmt(v, f),
Self::Object(v) => Display::fmt(v, f),
Self::Generate(v) => match v {
Gen::Rand => Display::fmt("rand()", f),
Gen::Ulid => Display::fmt("ulid()", f),
Gen::Uuid => Display::fmt("uuid()", f),
},
} }
} }
} }
@ -178,13 +197,18 @@ impl Id {
match self { match self {
Id::Number(v) => Ok(Id::Number(*v)), Id::Number(v) => Ok(Id::Number(*v)),
Id::String(v) => Ok(Id::String(v.clone())), Id::String(v) => Ok(Id::String(v.clone())),
Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? {
Value::Array(v) => Ok(Id::Array(v)),
_ => unreachable!(),
},
Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? { Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? {
Value::Object(v) => Ok(Id::Object(v)), Value::Object(v) => Ok(Id::Object(v)),
_ => unreachable!(), _ => unreachable!(),
}, },
Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? { Id::Generate(v) => match v {
Value::Array(v) => Ok(Id::Array(v)), Gen::Rand => Ok(Self::rand()),
_ => unreachable!(), Gen::Ulid => Ok(Self::ulid()),
Gen::Uuid => Ok(Self::uuid()),
}, },
} }
} }

View file

@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::escape::escape_rid; use crate::sql::escape::escape_rid;
use crate::sql::id::{id, Id}; use crate::sql::id::{id, Gen, Id};
use crate::sql::ident::ident_raw; use crate::sql::ident::ident_raw;
use crate::sql::strand::Strand; use crate::sql::strand::Strand;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -135,9 +135,9 @@ fn thing_raw(i: &str) -> IResult<&str, Thing> {
let (i, t) = ident_raw(i)?; let (i, t) = ident_raw(i)?;
let (i, _) = char(':')(i)?; let (i, _) = char(':')(i)?;
let (i, v) = alt(( let (i, v) = alt((
map(tag("rand()"), |_| Id::rand()), map(tag("rand()"), |_| Id::Generate(Gen::Rand)),
map(tag("ulid()"), |_| Id::ulid()), map(tag("ulid()"), |_| Id::Generate(Gen::Ulid)),
map(tag("uuid()"), |_| Id::uuid()), map(tag("uuid()"), |_| Id::Generate(Gen::Uuid)),
id, id,
))(i)?; ))(i)?;
Ok(( Ok((

View file

@ -23,7 +23,7 @@ use crate::sql::fmt::{Fmt, Pretty};
use crate::sql::function::{self, function, Function}; use crate::sql::function::{self, function, Function};
use crate::sql::future::{future, Future}; use crate::sql::future::{future, Future};
use crate::sql::geometry::{geometry, Geometry}; use crate::sql::geometry::{geometry, Geometry};
use crate::sql::id::Id; use crate::sql::id::{Gen, Id};
use crate::sql::idiom::{self, Idiom}; use crate::sql::idiom::{self, Idiom};
use crate::sql::kind::Kind; use crate::sql::kind::Kind;
use crate::sql::model::{model, Model}; use crate::sql::model::{model, Model};
@ -531,8 +531,13 @@ impl From<Id> for Value {
match v { match v {
Id::Number(v) => v.into(), Id::Number(v) => v.into(),
Id::String(v) => v.into(), Id::String(v) => v.into(),
Id::Object(v) => v.into(),
Id::Array(v) => v.into(), Id::Array(v) => v.into(),
Id::Object(v) => v.into(),
Id::Generate(v) => match v {
Gen::Rand => Id::rand().into(),
Gen::Ulid => Id::ulid().into(),
Gen::Uuid => Id::uuid().into(),
},
} }
} }
} }

View file

@ -4,6 +4,7 @@ use surrealdb::dbs::Session;
use surrealdb::err::Error; use surrealdb::err::Error;
use surrealdb::iam::Role; use surrealdb::iam::Role;
use surrealdb::kvs::Datastore; use surrealdb::kvs::Datastore;
use surrealdb::sql::Part;
use surrealdb::sql::Thing; use surrealdb::sql::Thing;
use surrealdb::sql::Value; use surrealdb::sql::Value;
@ -136,6 +137,44 @@ async fn create_with_id() -> Result<(), Error> {
Ok(()) Ok(())
} }
#[tokio::test]
async fn create_with_custom_function() -> Result<(), Error> {
let sql = "
DEFINE FUNCTION fn::record::create($data: any) {
RETURN CREATE person:ulid() CONTENT { data: $data } RETURN AFTER;
};
RETURN fn::record::create({ test: true, name: 'Tobie' });
RETURN fn::record::create({ test: true, name: 'Jaime' });
";
let dbs = Datastore::new("memory").await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
//
let tmp = res.remove(0).result?.pick(&[Part::from("data")]);
let val = Value::parse(
"{
test: true,
name: 'Tobie'
}",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?.pick(&[Part::from("data")]);
let val = Value::parse(
"{
test: true,
name: 'Jaime'
}",
);
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test] #[tokio::test]
async fn create_or_insert_with_permissions() -> Result<(), Error> { async fn create_or_insert_with_permissions() -> Result<(), Error> {
let sql = " let sql = "