Revision Value::Range, Id::Uuid, DefineStatement::Scope and DefineStatement::Token (#4586)

Co-authored-by: Emmanuel Keller <emmanuel.keller@surrealdb.com>
This commit is contained in:
Micha de Vries 2024-08-26 12:57:18 +02:00 committed by GitHub
parent f4e3d4f4e2
commit 5165a34a27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 159 additions and 7 deletions

View file

@ -28,13 +28,14 @@ pub enum Gen {
Uuid,
}
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Key, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub enum Id {
Number(i64),
String(String),
#[revision(start = 2)]
Uuid(Uuid),
Array(Array),
Object(Object),

View file

@ -1,3 +1,4 @@
use super::Id;
use crate::cnf::GENERATION_ALLOCATION_LIMIT;
use crate::ctx::Context;
use crate::dbs::Options;
@ -13,8 +14,6 @@ use std::fmt;
use std::ops::Bound;
use std::str::FromStr;
use super::Id;
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Range";
#[revisioned(revision = 1)]
@ -211,3 +210,16 @@ fn to_i64(v: Value) -> Result<i64, Error> {
}),
}
}
// Structs needed for revision convertion from old ranges
#[revisioned(revision = 1)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
#[serde(rename = "$surrealdb::private::sql::Range")]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct OldRange {
pub tb: String,
pub beg: Bound<Id>,
pub end: Bound<Id>,
}

View file

@ -0,0 +1,4 @@
// This folder houses DEFINE statements which have been deprecated.
// The old structs are needed for revision conversion.
pub mod scope;
pub mod token;

View file

@ -0,0 +1,19 @@
use crate::sql::{Duration, Ident, Strand, Value};
use derive::Store;
use revision::revisioned;
use serde::{Deserialize, Serialize};
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct DefineScopeStatement {
pub name: Ident,
pub code: String,
pub session: Option<Duration>,
pub signup: Option<Value>,
pub signin: Option<Value>,
pub comment: Option<Strand>,
#[revision(start = 2)]
pub if_not_exists: bool,
}

View file

@ -0,0 +1,18 @@
use crate::sql::{Algorithm, Base, Ident, Strand};
use derive::Store;
use revision::revisioned;
use serde::{Deserialize, Serialize};
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct DefineTokenStatement {
pub name: Ident,
pub base: Base,
pub kind: Algorithm,
pub code: String,
pub comment: Option<Strand>,
#[revision(start = 2)]
pub if_not_exists: bool,
}

View file

@ -1,6 +1,7 @@
mod access;
mod analyzer;
mod database;
mod deprecated;
mod event;
mod field;
mod function;
@ -24,18 +25,24 @@ pub use param::DefineParamStatement;
pub use table::DefineTableStatement;
pub use user::DefineUserStatement;
use crate::ctx::Context;
use deprecated::scope::DefineScopeStatement;
use deprecated::token::DefineTokenStatement;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::access::AccessDuration;
use crate::sql::access_type::{JwtAccessIssue, JwtAccessVerify, JwtAccessVerifyKey};
use crate::sql::value::Value;
use crate::sql::{Algorithm, Base, JwtAccess, RecordAccess};
use crate::{ctx::Context, sql::AccessType};
use derive::Store;
use reblessive::tree::Stk;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display};
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
@ -44,6 +51,18 @@ pub enum DefineStatement {
Database(DefineDatabaseStatement),
Function(DefineFunctionStatement),
Analyzer(DefineAnalyzerStatement),
#[revision(
end = 2,
convert_fn = "convert_token_to_access",
fields_name = "DefineTokenStatementFields"
)]
Token(DefineTokenStatement),
#[revision(
end = 2,
convert_fn = "convert_scope_to_access",
fields_name = "DefineScopeStatementFields"
)]
Scope(DefineScopeStatement),
Param(DefineParamStatement),
Table(DefineTableStatement),
Event(DefineEventStatement),
@ -51,9 +70,69 @@ pub enum DefineStatement {
Index(DefineIndexStatement),
User(DefineUserStatement),
Model(DefineModelStatement),
#[revision(start = 2)]
Access(DefineAccessStatement),
}
// Revision implementations
impl DefineStatement {
fn convert_token_to_access(
fields: DefineTokenStatementFields,
_revision: u16,
) -> Result<Self, revision::Error> {
Ok(DefineStatement::Access(DefineAccessStatement {
name: fields.0.name,
base: fields.0.base,
comment: fields.0.comment,
if_not_exists: fields.0.if_not_exists,
kind: AccessType::Jwt(JwtAccess {
issue: None,
verify: JwtAccessVerify::Key(JwtAccessVerifyKey {
alg: fields.0.kind,
key: fields.0.code,
}),
}),
// unused fields
authenticate: None,
duration: AccessDuration::default(),
overwrite: false,
}))
}
fn convert_scope_to_access(
fields: DefineScopeStatementFields,
_revision: u16,
) -> Result<Self, revision::Error> {
Ok(DefineStatement::Access(DefineAccessStatement {
name: fields.0.name,
base: Base::Db,
comment: fields.0.comment,
if_not_exists: fields.0.if_not_exists,
kind: AccessType::Record(RecordAccess {
signup: fields.0.signup,
signin: fields.0.signin,
jwt: JwtAccess {
issue: Some(JwtAccessIssue {
alg: Algorithm::Hs512,
key: fields.0.code.clone(),
}),
verify: JwtAccessVerify::Key(JwtAccessVerifyKey {
alg: Algorithm::Hs512,
key: fields.0.code,
}),
},
}),
// unused fields
authenticate: None,
duration: AccessDuration {
session: fields.0.session,
..AccessDuration::default()
},
overwrite: false,
}))
}
}
impl DefineStatement {
/// Check if we require a writeable transaction
pub(crate) fn writeable(&self) -> bool {

View file

@ -7,6 +7,7 @@ use crate::err::Error;
use crate::fnc::util::string::fuzzy::Fuzzy;
use crate::sql::id::range::IdRange;
use crate::sql::kind::Literal;
use crate::sql::range::OldRange;
use crate::sql::statements::info::InfoStructure;
use crate::sql::Closure;
use crate::sql::{
@ -82,7 +83,7 @@ impl From<&Tables> for Values {
}
}
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[serde(rename = "$surrealdb::private::sql::Value")]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
@ -123,6 +124,9 @@ pub enum Value {
Regex(Regex),
Cast(Box<Cast>),
Block(Box<Block>),
#[revision(end = 2, convert_fn = "convert_old_range", fields_name = "OldValueRangeFields")]
Range(OldRange),
#[revision(start = 2)]
Range(Box<Range>),
Edges(Box<Edges>),
Future(Box<Future>),
@ -136,6 +140,21 @@ pub enum Value {
// Add new variants here
}
impl Value {
fn convert_old_range(
fields: OldValueRangeFields,
_revision: u16,
) -> Result<Self, revision::Error> {
Ok(Value::Thing(Thing {
tb: fields.0.tb,
id: Id::Range(Box::new(IdRange {
beg: fields.0.beg,
end: fields.0.end,
})),
}))
}
}
impl Eq for Value {}
impl Ord for Value {

View file

@ -1119,7 +1119,7 @@ async fn define_statement_search_index() -> Result<(), Error> {
check_path(&tmp, &["doc_ids", "keys_count"], |v| assert_eq!(v, Value::from(2)));
check_path(&tmp, &["doc_ids", "max_depth"], |v| assert_eq!(v, Value::from(1)));
check_path(&tmp, &["doc_ids", "nodes_count"], |v| assert_eq!(v, Value::from(1)));
check_path(&tmp, &["doc_ids", "total_size"], |v| assert_eq!(v, Value::from(63)));
check_path(&tmp, &["doc_ids", "total_size"], |v| assert_eq!(v, Value::from(62)));
check_path(&tmp, &["doc_lengths", "keys_count"], |v| assert_eq!(v, Value::from(2)));
check_path(&tmp, &["doc_lengths", "max_depth"], |v| assert_eq!(v, Value::from(1)));