Delay Record ID generation when using functions (#2469)
This commit is contained in:
parent
1fd6d991ae
commit
f01da5f577
6 changed files with 86 additions and 12 deletions
|
@ -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"]
|
||||||
|
|
|
@ -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)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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((
|
||||||
|
|
|
@ -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(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = "
|
||||||
|
|
Loading…
Reference in a new issue