Improve DEFINE
and REMOVE
statements code (#2455)
This commit is contained in:
parent
c514c39e9d
commit
44dabfa9d2
46 changed files with 3373 additions and 2803 deletions
|
@ -11,6 +11,7 @@ use_small_heuristics = "Off"
|
|||
# -----------------------------------
|
||||
|
||||
#blank_lines_lower_bound = 1
|
||||
#group_imports = "One"
|
||||
#indent_style = "Block"
|
||||
#match_arm_blocks = true
|
||||
#reorder_impl_items = true
|
||||
|
|
|
@ -916,8 +916,8 @@ where
|
|||
/// ```no_run
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() -> surrealdb::Result<()> {
|
||||
/// # let db = surrealdb::engine::any::connect("mem://").unwrap();
|
||||
/// db.tick_at(123).await.unwrap();
|
||||
/// # let db = surrealdb::engine::any::connect("mem://").await?;
|
||||
/// db.tick(123).await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::dbs::Session;
|
||||
use crate::err::Error;
|
||||
use crate::error;
|
||||
use crate::iam::token::Claims;
|
||||
use crate::iam::Auth;
|
||||
use crate::iam::{Actor, Level, Role};
|
||||
|
@ -454,21 +453,6 @@ async fn verify_ns_creds(
|
|||
|
||||
let user_res = match tx.get_ns_user(ns, user).await {
|
||||
Ok(u) => Ok(u),
|
||||
// TODO(sgirones): Remove this fallback once we remove LOGIN from the system completely. We are backwards compatible with LOGIN for now.
|
||||
// If the USER resource is not found in the namespace, try to find the LOGIN resource
|
||||
Err(error::Db::UserNsNotFound {
|
||||
ns: _,
|
||||
value: _,
|
||||
}) => match tx.get_nl(ns, user).await {
|
||||
Ok(u) => Ok(DefineUserStatement {
|
||||
base: u.base,
|
||||
name: u.name,
|
||||
hash: u.hash,
|
||||
code: u.code,
|
||||
roles: vec![Role::Editor.into()],
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}?;
|
||||
|
||||
|
@ -488,22 +472,6 @@ async fn verify_db_creds(
|
|||
|
||||
let user_res = match tx.get_db_user(ns, db, user).await {
|
||||
Ok(u) => Ok(u),
|
||||
// TODO(sgirones): Remove this fallback once we remove LOGIN from the system completely. We are backwards compatible with LOGIN for now.
|
||||
// If the USER resource is not found in the database, try to find the LOGIN resource
|
||||
Err(error::Db::UserDbNotFound {
|
||||
ns: _,
|
||||
db: _,
|
||||
value: _,
|
||||
}) => match tx.get_dl(ns, db, user).await {
|
||||
Ok(u) => Ok(DefineUserStatement {
|
||||
base: u.base,
|
||||
name: u.name,
|
||||
hash: u.hash,
|
||||
code: u.code,
|
||||
roles: vec![Role::Editor.into()],
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}?;
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ use crate::sql::statements::DefineEventStatement;
|
|||
use crate::sql::statements::DefineFieldStatement;
|
||||
use crate::sql::statements::DefineFunctionStatement;
|
||||
use crate::sql::statements::DefineIndexStatement;
|
||||
use crate::sql::statements::DefineLoginStatement;
|
||||
use crate::sql::statements::DefineNamespaceStatement;
|
||||
use crate::sql::statements::DefineParamStatement;
|
||||
use crate::sql::statements::DefineScopeStatement;
|
||||
use crate::sql::statements::DefineTableStatement;
|
||||
use crate::sql::statements::DefineTokenStatement;
|
||||
use crate::sql::statements::DefineUserStatement;
|
||||
use crate::sql::statements::LiveStatement;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
@ -25,17 +25,17 @@ pub enum Entry {
|
|||
// Multi definitions
|
||||
Azs(Arc<[DefineAnalyzerStatement]>),
|
||||
Dbs(Arc<[DefineDatabaseStatement]>),
|
||||
Dls(Arc<[DefineLoginStatement]>),
|
||||
Dts(Arc<[DefineTokenStatement]>),
|
||||
Dus(Arc<[DefineUserStatement]>),
|
||||
Evs(Arc<[DefineEventStatement]>),
|
||||
Fcs(Arc<[DefineFunctionStatement]>),
|
||||
Fds(Arc<[DefineFieldStatement]>),
|
||||
Fts(Arc<[DefineTableStatement]>),
|
||||
Ixs(Arc<[DefineIndexStatement]>),
|
||||
Lvs(Arc<[LiveStatement]>),
|
||||
Nls(Arc<[DefineLoginStatement]>),
|
||||
Nss(Arc<[DefineNamespaceStatement]>),
|
||||
Nts(Arc<[DefineTokenStatement]>),
|
||||
Nus(Arc<[DefineUserStatement]>),
|
||||
Pas(Arc<[DefineParamStatement]>),
|
||||
Scs(Arc<[DefineScopeStatement]>),
|
||||
Seq(U32),
|
||||
|
@ -59,4 +59,8 @@ impl Cache {
|
|||
pub fn del(&mut self, key: &Key) -> Option<Entry> {
|
||||
self.0.remove(key)
|
||||
}
|
||||
/// Clears a cache completely
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ async fn table_definitions_can_be_scanned() {
|
|||
view: None,
|
||||
permissions: Default::default(),
|
||||
changefeed: None,
|
||||
comment: None,
|
||||
};
|
||||
tx.set(&key, &value).await.unwrap();
|
||||
|
||||
|
@ -57,6 +58,7 @@ async fn table_definitions_can_be_deleted() {
|
|||
view: None,
|
||||
permissions: Default::default(),
|
||||
changefeed: None,
|
||||
comment: None,
|
||||
};
|
||||
tx.set(&key, &value).await.unwrap();
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ use crate::sql;
|
|||
use crate::sql::paths::EDGE;
|
||||
use crate::sql::paths::IN;
|
||||
use crate::sql::paths::OUT;
|
||||
use crate::sql::statements::DefineUserStatement;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::Strand;
|
||||
use crate::sql::Value;
|
||||
|
@ -30,12 +29,12 @@ use sql::statements::DefineEventStatement;
|
|||
use sql::statements::DefineFieldStatement;
|
||||
use sql::statements::DefineFunctionStatement;
|
||||
use sql::statements::DefineIndexStatement;
|
||||
use sql::statements::DefineLoginStatement;
|
||||
use sql::statements::DefineNamespaceStatement;
|
||||
use sql::statements::DefineParamStatement;
|
||||
use sql::statements::DefineScopeStatement;
|
||||
use sql::statements::DefineTableStatement;
|
||||
use sql::statements::DefineTokenStatement;
|
||||
use sql::statements::DefineUserStatement;
|
||||
use sql::statements::LiveStatement;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
@ -1205,32 +1204,23 @@ impl Transaction {
|
|||
})
|
||||
}
|
||||
|
||||
/// Retrieve all namespace login definitions for a specific namespace.
|
||||
pub async fn all_nl(&mut self, ns: &str) -> Result<Arc<[DefineLoginStatement]>, Error> {
|
||||
let key = crate::key::namespace::lg::prefix(ns);
|
||||
/// Retrieve all namespace user definitions for a specific namespace.
|
||||
pub async fn all_ns_users(&mut self, ns: &str) -> Result<Arc<[DefineUserStatement]>, Error> {
|
||||
let key = crate::key::namespace::us::prefix(ns);
|
||||
Ok(if let Some(e) = self.cache.get(&key) {
|
||||
if let Entry::Nls(v) = e {
|
||||
if let Entry::Nus(v) = e {
|
||||
v
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else {
|
||||
let beg = crate::key::namespace::lg::prefix(ns);
|
||||
let end = crate::key::namespace::lg::suffix(ns);
|
||||
let val = self.getr(beg..end, u32::MAX).await?;
|
||||
let val = val.convert().into();
|
||||
self.cache.set(key, Entry::Nls(Arc::clone(&val)));
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve all namespace user definitions for a specific namespace.
|
||||
pub async fn all_ns_users(&mut self, ns: &str) -> Result<Arc<[DefineUserStatement]>, Error> {
|
||||
let beg = crate::key::namespace::us::prefix(ns);
|
||||
let end = crate::key::namespace::us::suffix(ns);
|
||||
let val = self.getr(beg..end, u32::MAX).await?;
|
||||
let val = val.convert().into();
|
||||
Ok(val)
|
||||
self.cache.set(key, Entry::Nus(Arc::clone(&val)));
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve all namespace token definitions for a specific namespace.
|
||||
|
@ -1271,40 +1261,27 @@ impl Transaction {
|
|||
})
|
||||
}
|
||||
|
||||
/// Retrieve all database login definitions for a specific database.
|
||||
pub async fn all_dl(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
db: &str,
|
||||
) -> Result<Arc<[DefineLoginStatement]>, Error> {
|
||||
let key = crate::key::database::lg::prefix(ns, db);
|
||||
Ok(if let Some(e) = self.cache.get(&key) {
|
||||
if let Entry::Dls(v) = e {
|
||||
v
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else {
|
||||
let beg = crate::key::database::lg::prefix(ns, db);
|
||||
let end = crate::key::database::lg::suffix(ns, db);
|
||||
let val = self.getr(beg..end, u32::MAX).await?;
|
||||
let val = val.convert().into();
|
||||
self.cache.set(key, Entry::Dls(Arc::clone(&val)));
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve all database user definitions for a specific database.
|
||||
pub async fn all_db_users(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
db: &str,
|
||||
) -> Result<Arc<[DefineUserStatement]>, Error> {
|
||||
let key = crate::key::database::us::prefix(ns, db);
|
||||
Ok(if let Some(e) = self.cache.get(&key) {
|
||||
if let Entry::Dus(v) = e {
|
||||
v
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else {
|
||||
let beg = crate::key::database::us::prefix(ns, db);
|
||||
let end = crate::key::database::us::suffix(ns, db);
|
||||
let val = self.getr(beg..end, u32::MAX).await?;
|
||||
let val = val.convert().into();
|
||||
Ok(val)
|
||||
self.cache.set(key, Entry::Dus(Arc::clone(&val)));
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve all database token definitions for a specific database.
|
||||
|
@ -1631,15 +1608,6 @@ impl Transaction {
|
|||
Ok(val.into())
|
||||
}
|
||||
|
||||
/// Retrieve a specific namespace login definition.
|
||||
pub async fn get_nl(&mut self, ns: &str, nl: &str) -> Result<DefineLoginStatement, Error> {
|
||||
let key = crate::key::namespace::lg::new(ns, nl);
|
||||
let val = self.get(key).await?.ok_or(Error::NlNotFound {
|
||||
value: nl.to_owned(),
|
||||
})?;
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
/// Retrieve a specific namespace token definition.
|
||||
pub async fn get_nt(&mut self, ns: &str, nt: &str) -> Result<DefineTokenStatement, Error> {
|
||||
let key = crate::key::namespace::tk::new(ns, nt);
|
||||
|
@ -1658,20 +1626,6 @@ impl Transaction {
|
|||
Ok(val.into())
|
||||
}
|
||||
|
||||
/// Retrieve a specific database login definition.
|
||||
pub async fn get_dl(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
db: &str,
|
||||
dl: &str,
|
||||
) -> Result<DefineLoginStatement, Error> {
|
||||
let key = crate::key::database::lg::new(ns, db, dl);
|
||||
let val = self.get(key).await?.ok_or(Error::DlNotFound {
|
||||
value: dl.to_owned(),
|
||||
})?;
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
/// Retrieve a specific database token definition.
|
||||
pub async fn get_dt(
|
||||
&mut self,
|
||||
|
@ -1868,7 +1822,7 @@ impl Transaction {
|
|||
let key = crate::key::root::ns::new(ns);
|
||||
let val = DefineNamespaceStatement {
|
||||
name: ns.to_owned().into(),
|
||||
id: None,
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(val)
|
||||
|
@ -1897,8 +1851,7 @@ impl Transaction {
|
|||
let key = crate::key::namespace::db::new(ns, db);
|
||||
let val = DefineDatabaseStatement {
|
||||
name: db.to_owned().into(),
|
||||
changefeed: None,
|
||||
id: None,
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(val)
|
||||
|
@ -1928,7 +1881,7 @@ impl Transaction {
|
|||
let key = crate::key::database::sc::new(ns, db, sc);
|
||||
let val = DefineScopeStatement {
|
||||
name: sc.to_owned().into(),
|
||||
..DefineScopeStatement::default()
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(val)
|
||||
|
@ -1959,8 +1912,7 @@ impl Transaction {
|
|||
let val = DefineTableStatement {
|
||||
name: tb.to_owned().into(),
|
||||
permissions: Permissions::none(),
|
||||
changefeed: None,
|
||||
..DefineTableStatement::default()
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(val)
|
||||
|
@ -2057,7 +2009,7 @@ impl Transaction {
|
|||
let key = crate::key::root::ns::new(ns);
|
||||
let val = DefineNamespaceStatement {
|
||||
name: ns.to_owned().into(),
|
||||
id: None,
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(Arc::new(val))
|
||||
|
@ -2086,8 +2038,7 @@ impl Transaction {
|
|||
let key = crate::key::namespace::db::new(ns, db);
|
||||
let val = DefineDatabaseStatement {
|
||||
name: db.to_owned().into(),
|
||||
changefeed: None,
|
||||
id: None,
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(Arc::new(val))
|
||||
|
@ -2118,8 +2069,7 @@ impl Transaction {
|
|||
let val = DefineTableStatement {
|
||||
name: tb.to_owned().into(),
|
||||
permissions: Permissions::none(),
|
||||
changefeed: None,
|
||||
..DefineTableStatement::default()
|
||||
..Default::default()
|
||||
};
|
||||
self.put(key, &val).await?;
|
||||
Ok(Arc::new(val))
|
||||
|
@ -2183,16 +2133,16 @@ impl Transaction {
|
|||
chn.send(bytes!("")).await?;
|
||||
}
|
||||
}
|
||||
// Output LOGINS
|
||||
// Output USERS
|
||||
{
|
||||
let dls = self.all_dl(ns, db).await?;
|
||||
if !dls.is_empty() {
|
||||
let dus = self.all_db_users(ns, db).await?;
|
||||
if !dus.is_empty() {
|
||||
chn.send(bytes!("-- ------------------------------")).await?;
|
||||
chn.send(bytes!("-- LOGINS")).await?;
|
||||
chn.send(bytes!("-- USERS")).await?;
|
||||
chn.send(bytes!("-- ------------------------------")).await?;
|
||||
chn.send(bytes!("")).await?;
|
||||
for dl in dls.iter() {
|
||||
chn.send(bytes!(format!("{dl};"))).await?;
|
||||
for us in dus.iter() {
|
||||
chn.send(bytes!(format!("{us};"))).await?;
|
||||
}
|
||||
chn.send(bytes!("")).await?;
|
||||
}
|
||||
|
@ -2385,6 +2335,13 @@ impl Transaction {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// change will record the change in the changefeed if enabled.
|
||||
// To actually persist the record changes into the underlying kvs,
|
||||
// you must call the `complete_changes` function and then commit the transaction.
|
||||
pub(crate) fn clear_cache(&mut self) {
|
||||
self.cache.clear()
|
||||
}
|
||||
|
||||
// change will record the change in the changefeed if enabled.
|
||||
// To actually persist the record changes into the underlying kvs,
|
||||
// you must call the `complete_changes` function and then commit the transaction.
|
||||
|
@ -2800,6 +2757,9 @@ mod tests {
|
|||
let key2 = crate::key::namespace::us::new("ns", "user2");
|
||||
let _ = txn.set(key1, data.to_owned()).await.unwrap();
|
||||
let _ = txn.set(key2, data.to_owned()).await.unwrap();
|
||||
|
||||
txn.cache.clear();
|
||||
|
||||
let res = txn.all_ns_users("ns").await.unwrap();
|
||||
|
||||
assert_eq!(res.len(), 2);
|
||||
|
@ -2808,7 +2768,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_db_users() {
|
||||
async fn test_all_db_users() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut txn = ds.transaction(true, false).await.unwrap();
|
||||
|
||||
|
@ -2827,6 +2787,9 @@ mod tests {
|
|||
let key2 = crate::key::database::us::new("ns", "db", "user2");
|
||||
let _ = txn.set(key1, data.to_owned()).await.unwrap();
|
||||
let _ = txn.set(key2, data.to_owned()).await.unwrap();
|
||||
|
||||
txn.cache.clear();
|
||||
|
||||
let res = txn.all_db_users("ns", "db").await.unwrap();
|
||||
|
||||
assert_eq!(res.len(), 2);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::{closeparentheses, commas, openparentheses};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::language::{language, Language};
|
||||
|
@ -83,7 +82,5 @@ fn filter(i: &str) -> IResult<&str, Filter> {
|
|||
}
|
||||
|
||||
pub(super) fn filters(i: &str) -> IResult<&str, Vec<Filter>> {
|
||||
let (i, _) = tag_no_case("FILTERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
separated_list1(commas, filter)(i)
|
||||
}
|
||||
|
|
|
@ -11,10 +11,11 @@ use revision::revisioned;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum Index {
|
||||
/// (Basic) non unique
|
||||
#[default]
|
||||
Idx,
|
||||
/// Unique index
|
||||
Uniq,
|
||||
|
@ -27,12 +28,6 @@ pub enum Index {
|
|||
},
|
||||
}
|
||||
|
||||
impl Default for Index {
|
||||
fn default() -> Self {
|
||||
Self::Idx
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Index {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -55,12 +50,7 @@ impl fmt::Display for Index {
|
|||
}
|
||||
|
||||
pub fn index(i: &str) -> IResult<&str, Index> {
|
||||
alt((unique, search, non_unique))(i)
|
||||
}
|
||||
|
||||
pub fn non_unique(i: &str) -> IResult<&str, Index> {
|
||||
let (i, _) = tag("")(i)?;
|
||||
Ok((i, Index::Idx))
|
||||
alt((unique, search))(i)
|
||||
}
|
||||
|
||||
pub fn unique(i: &str) -> IResult<&str, Index> {
|
||||
|
|
|
@ -107,6 +107,7 @@ pub use self::id::Id;
|
|||
pub use self::ident::Ident;
|
||||
pub use self::idiom::Idiom;
|
||||
pub use self::idiom::Idioms;
|
||||
pub use self::index::Index;
|
||||
pub use self::kind::Kind;
|
||||
pub use self::limit::Limit;
|
||||
pub use self::model::Model;
|
||||
|
@ -124,6 +125,7 @@ pub use self::permission::Permissions;
|
|||
pub use self::query::Query;
|
||||
pub use self::range::Range;
|
||||
pub use self::regex::Regex;
|
||||
pub use self::scoring::Scoring;
|
||||
pub use self::script::Script;
|
||||
pub use self::split::Split;
|
||||
pub use self::split::Splits;
|
||||
|
|
File diff suppressed because it is too large
Load diff
139
lib/src/sql/statements/define/analyzer.rs
Normal file
139
lib/src/sql/statements/define/analyzer.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::filter::{filters, Filter};
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::tokenizer::{tokenizers, Tokenizer};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineAnalyzerStatement {
|
||||
pub name: Ident,
|
||||
pub tokenizers: Option<Vec<Tokenizer>>,
|
||||
pub filters: Option<Vec<Filter>>,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineAnalyzerStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Release the transaction
|
||||
drop(run); // Do we really need this?
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineAnalyzerStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE ANALYZER {}", self.name)?;
|
||||
if let Some(v) = &self.tokenizers {
|
||||
let tokens: Vec<String> = v.iter().map(|f| f.to_string()).collect();
|
||||
write!(f, " TOKENIZERS {}", tokens.join(","))?;
|
||||
}
|
||||
if let Some(v) = &self.filters {
|
||||
let tokens: Vec<String> = v.iter().map(|f| f.to_string()).collect();
|
||||
write!(f, " FILTERS {}", tokens.join(","))?;
|
||||
}
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyzer(i: &str) -> IResult<&str, DefineAnalyzerStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ANALYZER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(analyzer_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineAnalyzerStatement {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineAnalyzerOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
DefineAnalyzerOption::Filters(v) => {
|
||||
res.filters = Some(v);
|
||||
}
|
||||
DefineAnalyzerOption::Tokenizers(v) => {
|
||||
res.tokenizers = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineAnalyzerOption {
|
||||
Comment(Strand),
|
||||
Filters(Vec<Filter>),
|
||||
Tokenizers(Vec<Tokenizer>),
|
||||
}
|
||||
|
||||
fn analyzer_opts(i: &str) -> IResult<&str, DefineAnalyzerOption> {
|
||||
alt((analyzer_comment, analyzer_filters, analyzer_tokenizers))(i)
|
||||
}
|
||||
|
||||
fn analyzer_comment(i: &str) -> IResult<&str, DefineAnalyzerOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineAnalyzerOption::Comment(v)))
|
||||
}
|
||||
|
||||
fn analyzer_filters(i: &str) -> IResult<&str, DefineAnalyzerOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FILTERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = filters(i)?;
|
||||
Ok((i, DefineAnalyzerOption::Filters(v)))
|
||||
}
|
||||
|
||||
fn analyzer_tokenizers(i: &str) -> IResult<&str, DefineAnalyzerOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TOKENIZERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = tokenizers(i)?;
|
||||
Ok((i, DefineAnalyzerOption::Tokenizers(v)))
|
||||
}
|
145
lib/src/sql/statements/define/database.rs
Normal file
145
lib/src/sql/statements/define/database.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::changefeed::{changefeed, ChangeFeed};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineDatabaseStatement {
|
||||
pub id: Option<u32>,
|
||||
pub name: Ident,
|
||||
pub comment: Option<Strand>,
|
||||
pub changefeed: Option<ChangeFeed>,
|
||||
}
|
||||
|
||||
impl DefineDatabaseStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::namespace::db::new(opt.ns(), &self.name);
|
||||
let ns = run.add_ns(opt.ns(), opt.strict).await?;
|
||||
// Set the id
|
||||
if self.id.is_none() && ns.id.is_some() {
|
||||
let mut db = self.clone();
|
||||
db.id = Some(run.get_next_db_id(ns.id.unwrap()).await?);
|
||||
// Store the db
|
||||
run.set(key, db).await?;
|
||||
} else {
|
||||
// Store the db
|
||||
run.set(key, self).await?;
|
||||
}
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineDatabaseStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE DATABASE {}", self.name)?;
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.changefeed {
|
||||
write!(f, " {v}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn database(i: &str) -> IResult<&str, DefineDatabaseStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("DB"), tag_no_case("DATABASE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(database_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineDatabaseStatement {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineDatabaseOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
DefineDatabaseOption::ChangeFeed(v) => {
|
||||
res.changefeed = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineDatabaseOption {
|
||||
Comment(Strand),
|
||||
ChangeFeed(ChangeFeed),
|
||||
}
|
||||
|
||||
fn database_opts(i: &str) -> IResult<&str, DefineDatabaseOption> {
|
||||
alt((database_comment, database_changefeed))(i)
|
||||
}
|
||||
|
||||
fn database_comment(i: &str) -> IResult<&str, DefineDatabaseOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineDatabaseOption::Comment(v)))
|
||||
}
|
||||
|
||||
fn database_changefeed(i: &str) -> IResult<&str, DefineDatabaseOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = changefeed(i)?;
|
||||
Ok((i, DefineDatabaseOption::ChangeFeed(v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn define_database_with_changefeed() {
|
||||
let sql = "DEFINE DATABASE mydatabase CHANGEFEED 1h";
|
||||
let res = database(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(sql, format!("{}", out));
|
||||
|
||||
let serialized: Vec<u8> = (&out).try_into().unwrap();
|
||||
let deserialized = DefineDatabaseStatement::try_from(&serialized).unwrap();
|
||||
assert_eq!(out, deserialized);
|
||||
}
|
||||
}
|
145
lib/src/sql/statements/define/event.rs
Normal file
145
lib/src/sql/statements/define/event.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{value, values, Value, Values};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::many0;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineEventStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
pub when: Value,
|
||||
pub then: Values,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineEventStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineEventStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DEFINE EVENT {} ON {} WHEN {} THEN {}",
|
||||
self.name, self.what, self.when, self.then
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(i: &str) -> IResult<&str, DefineEventStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("EVENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
let (i, opts) = many0(event_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineEventStatement {
|
||||
name,
|
||||
what,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineEventOption::When(v) => {
|
||||
res.when = v;
|
||||
}
|
||||
DefineEventOption::Then(v) => {
|
||||
res.then = v;
|
||||
}
|
||||
DefineEventOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check necessary options
|
||||
if res.then.is_empty() {
|
||||
// TODO throw error
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineEventOption {
|
||||
When(Value),
|
||||
Then(Values),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn event_opts(i: &str) -> IResult<&str, DefineEventOption> {
|
||||
alt((event_when, event_then, event_comment))(i)
|
||||
}
|
||||
|
||||
fn event_when(i: &str) -> IResult<&str, DefineEventOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("WHEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineEventOption::When(v)))
|
||||
}
|
||||
|
||||
fn event_then(i: &str) -> IResult<&str, DefineEventOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("THEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = values(i)?;
|
||||
Ok((i, DefineEventOption::Then(v)))
|
||||
}
|
||||
|
||||
fn event_comment(i: &str) -> IResult<&str, DefineEventOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineEventOption::Comment(v)))
|
||||
}
|
214
lib/src/sql/statements/define/field.rs
Normal file
214
lib/src/sql/statements/define/field.rs
Normal file
|
@ -0,0 +1,214 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::kind::{kind, Kind};
|
||||
use crate::sql::permission::{permissions, Permissions};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{value, Value};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::many0;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineFieldStatement {
|
||||
pub name: Idiom,
|
||||
pub what: Ident,
|
||||
pub flex: bool,
|
||||
pub kind: Option<Kind>,
|
||||
pub value: Option<Value>,
|
||||
pub assert: Option<Value>,
|
||||
pub default: Option<Value>,
|
||||
pub permissions: Permissions,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineFieldStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let fd = self.name.to_string();
|
||||
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineFieldStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE FIELD {} ON {}", self.name, self.what)?;
|
||||
if self.flex {
|
||||
write!(f, " FLEXIBLE")?
|
||||
}
|
||||
if let Some(ref v) = self.kind {
|
||||
write!(f, " TYPE {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.value {
|
||||
write!(f, " VALUE {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.assert {
|
||||
write!(f, " ASSERT {v}")?
|
||||
}
|
||||
if !self.permissions.is_full() {
|
||||
write!(f, " {}", self.permissions)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(i: &str) -> IResult<&str, DefineFieldStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FIELD")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = idiom::local(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
let (i, opts) = many0(field_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineFieldStatement {
|
||||
name,
|
||||
what,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineFieldOption::Flex => {
|
||||
res.flex = true;
|
||||
}
|
||||
DefineFieldOption::Kind(v) => {
|
||||
res.kind = Some(v);
|
||||
}
|
||||
DefineFieldOption::Value(v) => {
|
||||
res.value = Some(v);
|
||||
}
|
||||
DefineFieldOption::Assert(v) => {
|
||||
res.assert = Some(v);
|
||||
}
|
||||
DefineFieldOption::Default(v) => {
|
||||
res.default = Some(v);
|
||||
}
|
||||
DefineFieldOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
DefineFieldOption::Permissions(v) => {
|
||||
res.permissions = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineFieldOption {
|
||||
Flex,
|
||||
Kind(Kind),
|
||||
Value(Value),
|
||||
Assert(Value),
|
||||
Default(Value),
|
||||
Comment(Strand),
|
||||
Permissions(Permissions),
|
||||
}
|
||||
|
||||
fn field_opts(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
alt((
|
||||
field_flex,
|
||||
field_kind,
|
||||
field_value,
|
||||
field_assert,
|
||||
field_default,
|
||||
field_comment,
|
||||
field_permissions,
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn field_flex(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("FLEXIBLE"), tag_no_case("FLEXI"), tag_no_case("FLEX")))(i)?;
|
||||
Ok((i, DefineFieldOption::Flex))
|
||||
}
|
||||
|
||||
fn field_kind(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TYPE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = kind(i)?;
|
||||
Ok((i, DefineFieldOption::Kind(v)))
|
||||
}
|
||||
|
||||
fn field_value(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("VALUE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineFieldOption::Value(v)))
|
||||
}
|
||||
|
||||
fn field_assert(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ASSERT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineFieldOption::Assert(v)))
|
||||
}
|
||||
|
||||
fn field_default(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("DEFAULT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineFieldOption::Default(v)))
|
||||
}
|
||||
|
||||
fn field_comment(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineFieldOption::Comment(v)))
|
||||
}
|
||||
|
||||
fn field_permissions(i: &str) -> IResult<&str, DefineFieldOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = permissions(i)?;
|
||||
Ok((i, DefineFieldOption::Permissions(v)))
|
||||
}
|
137
lib/src/sql/statements/define/function.rs
Normal file
137
lib/src/sql/statements/define/function.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::block::{block, Block};
|
||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::kind::{kind, Kind};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::character::complete::char;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::separated_list0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineFunctionStatement {
|
||||
pub name: Ident,
|
||||
pub args: Vec<(Ident, Kind)>,
|
||||
pub block: Block,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineFunctionStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DefineFunctionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE FUNCTION fn::{}(", self.name)?;
|
||||
for (i, (name, kind)) in self.args.iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
write!(f, "${name}: {kind}")?;
|
||||
}
|
||||
f.write_str(") ")?;
|
||||
Display::fmt(&self.block, f)?;
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function(i: &str) -> IResult<&str, DefineFunctionStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FUNCTION")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag("fn::")(i)?;
|
||||
let (i, name) = ident::multi(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, args) = separated_list0(commas, |i| {
|
||||
let (i, _) = char('$')(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(':')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, kind) = kind(i)?;
|
||||
Ok((i, (name, kind)))
|
||||
})(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, block) = block(i)?;
|
||||
let (i, opts) = many0(function_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineFunctionStatement {
|
||||
name,
|
||||
args,
|
||||
block,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineFunctionOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineFunctionOption {
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn function_opts(i: &str) -> IResult<&str, DefineFunctionOption> {
|
||||
function_comment(i)
|
||||
}
|
||||
|
||||
fn function_comment(i: &str) -> IResult<&str, DefineFunctionOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineFunctionOption::Comment(v)))
|
||||
}
|
264
lib/src/sql/statements/define/index.rs
Normal file
264
lib/src/sql/statements/define/index.rs
Normal file
|
@ -0,0 +1,264 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::Idioms;
|
||||
use crate::sql::index;
|
||||
use crate::sql::index::Index;
|
||||
use crate::sql::statements::UpdateStatement;
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{Value, Values};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::many0;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineIndexStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
pub cols: Idioms,
|
||||
pub index: Index,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Remove the index data
|
||||
let key = crate::key::index::all::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ix::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Release the transaction
|
||||
drop(run);
|
||||
// Force queries to run
|
||||
let opt = &opt.new_with_force(true);
|
||||
// Don't process field queries
|
||||
let opt = &opt.new_with_fields(false);
|
||||
// Don't process event queries
|
||||
let opt = &opt.new_with_events(false);
|
||||
// Don't process table queries
|
||||
let opt = &opt.new_with_tables(false);
|
||||
// Update the index data
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::Table(self.what.clone().into())]),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt, txn, doc).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineIndexStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE INDEX {} ON {} FIELDS {}", self.name, self.what, self.cols)?;
|
||||
if Index::Idx != self.index {
|
||||
write!(f, " {}", self.index)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(i: &str) -> IResult<&str, DefineIndexStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("INDEX")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
let (i, opts) = many0(index_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineIndexStatement {
|
||||
name,
|
||||
what,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineIndexOption::Index(v) => {
|
||||
res.index = v;
|
||||
}
|
||||
DefineIndexOption::Columns(v) => {
|
||||
res.cols = v;
|
||||
}
|
||||
DefineIndexOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check necessary options
|
||||
if res.cols.is_empty() {
|
||||
// TODO throw error
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineIndexOption {
|
||||
Index(Index),
|
||||
Columns(Idioms),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn index_opts(i: &str) -> IResult<&str, DefineIndexOption> {
|
||||
alt((index_kind, index_columns, index_comment))(i)
|
||||
}
|
||||
|
||||
fn index_kind(i: &str) -> IResult<&str, DefineIndexOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = index::index(i)?;
|
||||
Ok((i, DefineIndexOption::Index(v)))
|
||||
}
|
||||
|
||||
fn index_columns(i: &str) -> IResult<&str, DefineIndexOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("COLUMNS"), tag_no_case("FIELDS")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = idiom::locals(i)?;
|
||||
Ok((i, DefineIndexOption::Columns(v)))
|
||||
}
|
||||
|
||||
fn index_comment(i: &str) -> IResult<&str, DefineIndexOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineIndexOption::Comment(v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::sql::Ident;
|
||||
use crate::sql::Idiom;
|
||||
use crate::sql::Idioms;
|
||||
use crate::sql::Index;
|
||||
use crate::sql::Part;
|
||||
use crate::sql::Scoring;
|
||||
|
||||
#[test]
|
||||
fn check_create_non_unique_index() {
|
||||
let sql = "DEFINE INDEX my_index ON TABLE my_table COLUMNS my_col";
|
||||
let (_, idx) = index(sql).unwrap();
|
||||
assert_eq!(
|
||||
idx,
|
||||
DefineIndexStatement {
|
||||
name: Ident("my_index".to_string()),
|
||||
what: Ident("my_table".to_string()),
|
||||
cols: Idioms(vec![Idiom(vec![Part::Field(Ident("my_col".to_string()))])]),
|
||||
index: Index::Idx,
|
||||
comment: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(idx.to_string(), "DEFINE INDEX my_index ON my_table FIELDS my_col");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_create_unique_index() {
|
||||
let sql = "DEFINE INDEX my_index ON TABLE my_table COLUMNS my_col UNIQUE";
|
||||
let (_, idx) = index(sql).unwrap();
|
||||
assert_eq!(
|
||||
idx,
|
||||
DefineIndexStatement {
|
||||
name: Ident("my_index".to_string()),
|
||||
what: Ident("my_table".to_string()),
|
||||
cols: Idioms(vec![Idiom(vec![Part::Field(Ident("my_col".to_string()))])]),
|
||||
index: Index::Uniq,
|
||||
comment: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(idx.to_string(), "DEFINE INDEX my_index ON my_table FIELDS my_col UNIQUE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_create_search_index_with_highlights() {
|
||||
let sql = "DEFINE INDEX my_index ON TABLE my_table COLUMNS my_col SEARCH ANALYZER my_analyzer BM25(1.2,0.75) ORDER 1000 HIGHLIGHTS";
|
||||
let (_, idx) = index(sql).unwrap();
|
||||
assert_eq!(
|
||||
idx,
|
||||
DefineIndexStatement {
|
||||
name: Ident("my_index".to_string()),
|
||||
what: Ident("my_table".to_string()),
|
||||
cols: Idioms(vec![Idiom(vec![Part::Field(Ident("my_col".to_string()))])]),
|
||||
index: Index::Search {
|
||||
az: Ident("my_analyzer".to_string()),
|
||||
hl: true,
|
||||
sc: Scoring::Bm {
|
||||
k1: 1.2,
|
||||
b: 0.75,
|
||||
},
|
||||
order: 1000
|
||||
},
|
||||
comment: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(idx.to_string(), "DEFINE INDEX my_index ON my_table FIELDS my_col SEARCH ANALYZER my_analyzer BM25(1.2,0.75) ORDER 1000 HIGHLIGHTS");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_create_search_index() {
|
||||
let sql =
|
||||
"DEFINE INDEX my_index ON TABLE my_table COLUMNS my_col SEARCH ANALYZER my_analyzer VS";
|
||||
let (_, idx) = index(sql).unwrap();
|
||||
assert_eq!(
|
||||
idx,
|
||||
DefineIndexStatement {
|
||||
name: Ident("my_index".to_string()),
|
||||
what: Ident("my_table".to_string()),
|
||||
cols: Idioms(vec![Idiom(vec![Part::Field(Ident("my_col".to_string()))])]),
|
||||
index: Index::Search {
|
||||
az: Ident("my_analyzer".to_string()),
|
||||
hl: false,
|
||||
sc: Scoring::Vs,
|
||||
order: 100
|
||||
},
|
||||
comment: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
idx.to_string(),
|
||||
"DEFINE INDEX my_index ON my_table FIELDS my_col SEARCH ANALYZER my_analyzer VS ORDER 100"
|
||||
);
|
||||
}
|
||||
}
|
135
lib/src/sql/statements/define/mod.rs
Normal file
135
lib/src/sql/statements/define/mod.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
mod analyzer;
|
||||
mod database;
|
||||
mod event;
|
||||
mod field;
|
||||
mod function;
|
||||
mod index;
|
||||
mod namespace;
|
||||
mod param;
|
||||
mod scope;
|
||||
mod table;
|
||||
mod token;
|
||||
mod user;
|
||||
|
||||
pub use analyzer::{analyzer, DefineAnalyzerStatement};
|
||||
pub use database::{database, DefineDatabaseStatement};
|
||||
pub use event::{event, DefineEventStatement};
|
||||
pub use field::{field, DefineFieldStatement};
|
||||
pub use function::{function, DefineFunctionStatement};
|
||||
pub use index::{index, DefineIndexStatement};
|
||||
pub use namespace::{namespace, DefineNamespaceStatement};
|
||||
pub use param::{param, DefineParamStatement};
|
||||
pub use scope::{scope, DefineScopeStatement};
|
||||
pub use table::{table, DefineTableStatement};
|
||||
pub use token::{token, DefineTokenStatement};
|
||||
pub use user::{user, DefineUserStatement};
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum DefineStatement {
|
||||
Namespace(DefineNamespaceStatement),
|
||||
Database(DefineDatabaseStatement),
|
||||
Function(DefineFunctionStatement),
|
||||
Analyzer(DefineAnalyzerStatement),
|
||||
Token(DefineTokenStatement),
|
||||
Scope(DefineScopeStatement),
|
||||
Param(DefineParamStatement),
|
||||
Table(DefineTableStatement),
|
||||
Event(DefineEventStatement),
|
||||
Field(DefineFieldStatement),
|
||||
Index(DefineIndexStatement),
|
||||
User(DefineUserStatement),
|
||||
}
|
||||
|
||||
impl DefineStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::User(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Namespace(v) => Display::fmt(v, f),
|
||||
Self::Database(v) => Display::fmt(v, f),
|
||||
Self::Function(v) => Display::fmt(v, f),
|
||||
Self::User(v) => Display::fmt(v, f),
|
||||
Self::Token(v) => Display::fmt(v, f),
|
||||
Self::Scope(v) => Display::fmt(v, f),
|
||||
Self::Param(v) => Display::fmt(v, f),
|
||||
Self::Table(v) => Display::fmt(v, f),
|
||||
Self::Event(v) => Display::fmt(v, f),
|
||||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define(i: &str) -> IResult<&str, DefineStatement> {
|
||||
alt((
|
||||
map(namespace, DefineStatement::Namespace),
|
||||
map(database, DefineStatement::Database),
|
||||
map(function, DefineStatement::Function),
|
||||
map(user, DefineStatement::User),
|
||||
map(token, DefineStatement::Token),
|
||||
map(scope, DefineStatement::Scope),
|
||||
map(param, DefineStatement::Param),
|
||||
map(table, DefineStatement::Table),
|
||||
map(event, DefineStatement::Event),
|
||||
map(field, DefineStatement::Field),
|
||||
map(index, DefineStatement::Index),
|
||||
map(analyzer, DefineStatement::Analyzer),
|
||||
))(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::sql::Ident;
|
||||
|
||||
#[test]
|
||||
fn check_define_serialize() {
|
||||
let stm = DefineStatement::Namespace(DefineNamespaceStatement {
|
||||
name: Ident::from("test"),
|
||||
..Default::default()
|
||||
});
|
||||
let enc: Vec<u8> = stm.try_into().unwrap();
|
||||
assert_eq!(11, enc.len());
|
||||
}
|
||||
}
|
108
lib/src/sql/statements/define/namespace.rs
Normal file
108
lib/src/sql/statements/define/namespace.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineNamespaceStatement {
|
||||
pub id: Option<u32>,
|
||||
pub name: Ident,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineNamespaceStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?;
|
||||
// Process the statement
|
||||
let key = crate::key::root::ns::new(&self.name);
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Set the id
|
||||
if self.id.is_none() {
|
||||
let mut ns = self.clone();
|
||||
ns.id = Some(run.get_next_ns_id().await?);
|
||||
run.set(key, ns).await?;
|
||||
} else {
|
||||
run.set(key, self).await?;
|
||||
}
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineNamespaceStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE NAMESPACE {}", self.name)?;
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn namespace(i: &str) -> IResult<&str, DefineNamespaceStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("NS"), tag_no_case("NAMESPACE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(namespace_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineNamespaceStatement {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineNamespaceOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineNamespaceOption {
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn namespace_opts(i: &str) -> IResult<&str, DefineNamespaceOption> {
|
||||
namespace_comment(i)
|
||||
}
|
||||
|
||||
fn namespace_comment(i: &str) -> IResult<&str, DefineNamespaceOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineNamespaceOption::Comment(v)))
|
||||
}
|
117
lib/src/sql/statements/define/param.rs
Normal file
117
lib/src/sql/statements/define/param.rs
Normal file
|
@ -0,0 +1,117 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{value, Value};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::character::complete::char;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineParamStatement {
|
||||
pub name: Ident,
|
||||
pub value: Value,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineParamStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineParamStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE PARAM ${} VALUE {}", self.name, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn param(i: &str) -> IResult<&str, DefineParamStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("PARAM")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = char('$')(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(param_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineParamStatement {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineParamOption::Value(v) => {
|
||||
res.value = v;
|
||||
}
|
||||
DefineParamOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check necessary options
|
||||
if res.value.is_none() {
|
||||
// TODO throw error
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineParamOption {
|
||||
Value(Value),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn param_opts(i: &str) -> IResult<&str, DefineParamOption> {
|
||||
alt((param_value, param_comment))(i)
|
||||
}
|
||||
|
||||
fn param_value(i: &str) -> IResult<&str, DefineParamOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("VALUE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineParamOption::Value(v)))
|
||||
}
|
||||
|
||||
fn param_comment(i: &str) -> IResult<&str, DefineParamOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineParamOption::Comment(v)))
|
||||
}
|
156
lib/src/sql/statements/define/scope.rs
Normal file
156
lib/src/sql/statements/define/scope.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::duration::{duration, Duration};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{value, Value};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
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>,
|
||||
}
|
||||
|
||||
impl DefineScopeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineScopeStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE SCOPE {}", self.name)?;
|
||||
if let Some(ref v) = self.session {
|
||||
write!(f, " SESSION {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.signup {
|
||||
write!(f, " SIGNUP {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.signin {
|
||||
write!(f, " SIGNIN {v}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope(i: &str) -> IResult<&str, DefineScopeStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SCOPE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(scope_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineScopeStatement {
|
||||
name,
|
||||
code: rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(128)
|
||||
.map(char::from)
|
||||
.collect::<String>(),
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineScopeOption::Session(v) => {
|
||||
res.session = Some(v);
|
||||
}
|
||||
DefineScopeOption::Signup(v) => {
|
||||
res.signup = Some(v);
|
||||
}
|
||||
DefineScopeOption::Signin(v) => {
|
||||
res.signin = Some(v);
|
||||
}
|
||||
DefineScopeOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineScopeOption {
|
||||
Session(Duration),
|
||||
Signup(Value),
|
||||
Signin(Value),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn scope_opts(i: &str) -> IResult<&str, DefineScopeOption> {
|
||||
alt((scope_session, scope_signup, scope_signin, scope_comment))(i)
|
||||
}
|
||||
|
||||
fn scope_session(i: &str) -> IResult<&str, DefineScopeOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SESSION")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = duration(i)?;
|
||||
Ok((i, DefineScopeOption::Session(v)))
|
||||
}
|
||||
|
||||
fn scope_signup(i: &str) -> IResult<&str, DefineScopeOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SIGNUP")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineScopeOption::Signup(v)))
|
||||
}
|
||||
|
||||
fn scope_signin(i: &str) -> IResult<&str, DefineScopeOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SIGNIN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, DefineScopeOption::Signin(v)))
|
||||
}
|
||||
|
||||
fn scope_comment(i: &str) -> IResult<&str, DefineScopeOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineScopeOption::Comment(v)))
|
||||
}
|
260
lib/src/sql/statements/define/table.rs
Normal file
260
lib/src/sql/statements/define/table.rs
Normal file
|
@ -0,0 +1,260 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::changefeed::{changefeed, ChangeFeed};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::is_pretty;
|
||||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::permission::{permissions, Permissions};
|
||||
use crate::sql::statements::UpdateStatement;
|
||||
use crate::sql::strand::{strand, Strand};
|
||||
use crate::sql::value::{Value, Values};
|
||||
use crate::sql::view::{view, View};
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineTableStatement {
|
||||
pub id: Option<u32>,
|
||||
pub name: Ident,
|
||||
pub drop: bool,
|
||||
pub full: bool,
|
||||
pub view: Option<View>,
|
||||
pub permissions: Permissions,
|
||||
pub changefeed: Option<ChangeFeed>,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineTableStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);
|
||||
let ns = run.add_ns(opt.ns(), opt.strict).await?;
|
||||
let db = run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
if self.id.is_none() && ns.id.is_some() && db.id.is_some() {
|
||||
let mut tb = self.clone();
|
||||
tb.id = Some(run.get_next_tb_id(ns.id.unwrap(), db.id.unwrap()).await?);
|
||||
run.set(key, tb).await?;
|
||||
} else {
|
||||
run.set(key, self).await?;
|
||||
}
|
||||
// Check if table is a view
|
||||
if let Some(view) = &self.view {
|
||||
// Remove the table data
|
||||
let key = crate::key::table::all::new(opt.ns(), opt.db(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Process each foreign table
|
||||
for v in view.what.0.iter() {
|
||||
// Save the view config
|
||||
let key = crate::key::table::ft::new(opt.ns(), opt.db(), v, &self.name);
|
||||
run.set(key, self).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ft::prefix(opt.ns(), opt.db(), v);
|
||||
run.clr(key).await?;
|
||||
}
|
||||
// Release the transaction
|
||||
drop(run);
|
||||
// Force queries to run
|
||||
let opt = &opt.new_with_force(true);
|
||||
// Don't process field queries
|
||||
let opt = &opt.new_with_fields(false);
|
||||
// Don't process event queries
|
||||
let opt = &opt.new_with_events(false);
|
||||
// Don't process index queries
|
||||
let opt = &opt.new_with_indexes(false);
|
||||
// Process each foreign table
|
||||
for v in view.what.0.iter() {
|
||||
// Process the view data
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::Table(v.clone())]),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt, txn, doc).await?;
|
||||
}
|
||||
}
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineTableStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE TABLE {}", self.name)?;
|
||||
if self.drop {
|
||||
f.write_str(" DROP")?;
|
||||
}
|
||||
f.write_str(if self.full {
|
||||
" SCHEMAFULL"
|
||||
} else {
|
||||
" SCHEMALESS"
|
||||
})?;
|
||||
if let Some(ref v) = self.view {
|
||||
write!(f, " {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.changefeed {
|
||||
write!(f, " {v}")?;
|
||||
}
|
||||
if !self.permissions.is_full() {
|
||||
let _indent = if is_pretty() {
|
||||
Some(pretty_indent())
|
||||
} else {
|
||||
f.write_char(' ')?;
|
||||
None
|
||||
};
|
||||
write!(f, "{}", self.permissions)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn table(i: &str) -> IResult<&str, DefineTableStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TABLE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, opts) = many0(table_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineTableStatement {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineTableOption::Drop => {
|
||||
res.drop = true;
|
||||
}
|
||||
DefineTableOption::Schemafull => {
|
||||
res.full = true;
|
||||
}
|
||||
DefineTableOption::Schemaless => {
|
||||
res.full = false;
|
||||
}
|
||||
DefineTableOption::View(v) => {
|
||||
res.view = Some(v);
|
||||
}
|
||||
DefineTableOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
DefineTableOption::ChangeFeed(v) => {
|
||||
res.changefeed = Some(v);
|
||||
}
|
||||
DefineTableOption::Permissions(v) => {
|
||||
res.permissions = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineTableOption {
|
||||
Drop,
|
||||
View(View),
|
||||
Schemaless,
|
||||
Schemafull,
|
||||
Comment(Strand),
|
||||
Permissions(Permissions),
|
||||
ChangeFeed(ChangeFeed),
|
||||
}
|
||||
|
||||
fn table_opts(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
alt((
|
||||
table_drop,
|
||||
table_view,
|
||||
table_comment,
|
||||
table_schemaless,
|
||||
table_schemafull,
|
||||
table_permissions,
|
||||
table_changefeed,
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn table_drop(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("DROP")(i)?;
|
||||
Ok((i, DefineTableOption::Drop))
|
||||
}
|
||||
|
||||
fn table_changefeed(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = changefeed(i)?;
|
||||
Ok((i, DefineTableOption::ChangeFeed(v)))
|
||||
}
|
||||
|
||||
fn table_view(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = view(i)?;
|
||||
Ok((i, DefineTableOption::View(v)))
|
||||
}
|
||||
|
||||
fn table_schemaless(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SCHEMALESS")(i)?;
|
||||
Ok((i, DefineTableOption::Schemaless))
|
||||
}
|
||||
|
||||
fn table_schemafull(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("SCHEMAFULL"), tag_no_case("SCHEMAFUL")))(i)?;
|
||||
Ok((i, DefineTableOption::Schemafull))
|
||||
}
|
||||
|
||||
fn table_comment(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineTableOption::Comment(v)))
|
||||
}
|
||||
|
||||
fn table_permissions(i: &str) -> IResult<&str, DefineTableOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = permissions(i)?;
|
||||
Ok((i, DefineTableOption::Permissions(v)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn define_table_with_changefeed() {
|
||||
let sql = "DEFINE TABLE mytable SCHEMALESS CHANGEFEED 1h";
|
||||
let res = table(sql);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(sql, format!("{}", out));
|
||||
|
||||
let serialized: Vec<u8> = (&out).try_into().unwrap();
|
||||
let deserialized = DefineTableStatement::try_from(&serialized).unwrap();
|
||||
assert_eq!(out, deserialized);
|
||||
}
|
||||
}
|
179
lib/src/sql/statements/define/token.rs
Normal file
179
lib/src/sql/statements/define/token.rs
Normal file
|
@ -0,0 +1,179 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::sql::algorithm::{algorithm, Algorithm};
|
||||
use crate::sql::base::{base_or_scope, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::quote_str;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, strand_raw, Strand};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineTokenStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
pub kind: Algorithm,
|
||||
pub code: String,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl DefineTokenStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match &self.base {
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::namespace::tk::new(opt.ns(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Sc(sc) => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.add_sc(opt.ns(), opt.db(), sc, opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
// Other levels are not supported
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineTokenStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DEFINE TOKEN {} ON {} TYPE {} VALUE {}",
|
||||
self.name,
|
||||
self.base,
|
||||
self.kind,
|
||||
quote_str(&self.code)
|
||||
)?;
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token(i: &str) -> IResult<&str, DefineTokenStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TOKEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base_or_scope(i)?;
|
||||
let (i, opts) = many0(token_opts)(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineTokenStatement {
|
||||
name,
|
||||
base,
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineTokenOption::Type(v) => {
|
||||
res.kind = v;
|
||||
}
|
||||
DefineTokenOption::Value(v) => {
|
||||
res.code = v;
|
||||
}
|
||||
DefineTokenOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check necessary options
|
||||
if res.code.is_empty() {
|
||||
// TODO throw error
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineTokenOption {
|
||||
Type(Algorithm),
|
||||
Value(String),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn token_opts(i: &str) -> IResult<&str, DefineTokenOption> {
|
||||
alt((token_type, token_value, token_comment))(i)
|
||||
}
|
||||
|
||||
fn token_type(i: &str) -> IResult<&str, DefineTokenOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TYPE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = algorithm(i)?;
|
||||
Ok((i, DefineTokenOption::Type(v)))
|
||||
}
|
||||
|
||||
fn token_value(i: &str) -> IResult<&str, DefineTokenOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("VALUE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand_raw(i)?;
|
||||
Ok((i, DefineTokenOption::Value(v)))
|
||||
}
|
||||
|
||||
fn token_comment(i: &str) -> IResult<&str, DefineTokenOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineTokenOption::Comment(v)))
|
||||
}
|
230
lib/src/sql/statements/define/user.rs
Normal file
230
lib/src/sql/statements/define/user.rs
Normal file
|
@ -0,0 +1,230 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::Action;
|
||||
use crate::iam::ResourceKind;
|
||||
use crate::iam::Role;
|
||||
use crate::sql::base::{base, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::Error as SqlError;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::quote_str;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::strand::{strand, strand_raw, Strand};
|
||||
use crate::sql::value::Value;
|
||||
use argon2::password_hash::{PasswordHasher, SaltString};
|
||||
use argon2::Argon2;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::separated_list0;
|
||||
use nom::Err::Failure;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct DefineUserStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
pub hash: String,
|
||||
pub code: String,
|
||||
pub roles: Vec<Ident>,
|
||||
pub comment: Option<Strand>,
|
||||
}
|
||||
|
||||
impl From<(Base, &str, &str)> for DefineUserStatement {
|
||||
fn from((base, user, pass): (Base, &str, &str)) -> Self {
|
||||
DefineUserStatement {
|
||||
base,
|
||||
name: user.into(),
|
||||
hash: Argon2::default()
|
||||
.hash_password(pass.as_ref(), &SaltString::generate(&mut OsRng))
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
code: rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(128)
|
||||
.map(char::from)
|
||||
.collect::<String>(),
|
||||
roles: vec!["owner".into()],
|
||||
comment: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefineUserStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match self.base {
|
||||
Base::Root => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::root::us::new(&self.name);
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::namespace::us::new(opt.ns(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);
|
||||
run.add_ns(opt.ns(), opt.strict).await?;
|
||||
run.add_db(opt.ns(), opt.db(), opt.strict).await?;
|
||||
run.set(key, self).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
// Other levels are not supported
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DefineUserStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DEFINE USER {} ON {} PASSHASH {} ROLES {}",
|
||||
self.name,
|
||||
self.base,
|
||||
quote_str(&self.hash),
|
||||
Fmt::comma_separated(
|
||||
&self.roles.iter().map(|r| r.to_string().to_uppercase()).collect::<Vec<String>>()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user(i: &str) -> IResult<&str, DefineUserStatement> {
|
||||
let (i, _) = tag_no_case("DEFINE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("USER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base(i)?;
|
||||
let (i, opts) = user_opts(i)?;
|
||||
// Create the base statement
|
||||
let mut res = DefineUserStatement {
|
||||
name,
|
||||
base,
|
||||
roles: vec!["Viewer".into()], // New users get the viewer role by default
|
||||
code: rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(128)
|
||||
.map(char::from)
|
||||
.collect::<String>(),
|
||||
..Default::default()
|
||||
};
|
||||
// Assign any defined options
|
||||
for opt in opts {
|
||||
match opt {
|
||||
DefineUserOption::Password(v) => {
|
||||
res.hash = Argon2::default()
|
||||
.hash_password(v.as_ref(), &SaltString::generate(&mut OsRng))
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
DefineUserOption::Passhash(v) => {
|
||||
res.hash = v;
|
||||
}
|
||||
DefineUserOption::Roles(v) => {
|
||||
res.roles = v;
|
||||
}
|
||||
DefineUserOption::Comment(v) => {
|
||||
res.comment = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the statement
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
enum DefineUserOption {
|
||||
Password(String),
|
||||
Passhash(String),
|
||||
Roles(Vec<Ident>),
|
||||
Comment(Strand),
|
||||
}
|
||||
|
||||
fn user_opts(i: &str) -> IResult<&str, Vec<DefineUserOption>> {
|
||||
many0(alt((alt((user_pass, user_hash)), user_roles, user_comment)))(i)
|
||||
}
|
||||
|
||||
fn user_pass(i: &str) -> IResult<&str, DefineUserOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("PASSWORD")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand_raw(i)?;
|
||||
Ok((i, DefineUserOption::Password(v)))
|
||||
}
|
||||
|
||||
fn user_hash(i: &str) -> IResult<&str, DefineUserOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("PASSHASH")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand_raw(i)?;
|
||||
Ok((i, DefineUserOption::Passhash(v)))
|
||||
}
|
||||
|
||||
fn user_comment(i: &str) -> IResult<&str, DefineUserOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("COMMENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = strand(i)?;
|
||||
Ok((i, DefineUserOption::Comment(v)))
|
||||
}
|
||||
|
||||
fn user_roles(i: &str) -> IResult<&str, DefineUserOption> {
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ROLES")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, roles) = separated_list0(commas, |i| {
|
||||
let (i, v) = ident(i)?;
|
||||
// Verify the role is valid
|
||||
Role::try_from(v.as_str()).map_err(|_| Failure(SqlError::Role(i, v.to_string())))?;
|
||||
|
||||
Ok((i, v))
|
||||
})(i)?;
|
||||
|
||||
Ok((i, DefineUserOption::Roles(roles)))
|
||||
}
|
|
@ -77,12 +77,6 @@ impl InfoStatement {
|
|||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("databases".to_owned(), tmp.into());
|
||||
// Process the logins
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_nl(opt.ns()).await?.iter() {
|
||||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("logins".to_owned(), tmp.into());
|
||||
// Process the users
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_ns_users(opt.ns()).await?.iter() {
|
||||
|
@ -105,12 +99,6 @@ impl InfoStatement {
|
|||
let mut run = txn.lock().await;
|
||||
// Create the result set
|
||||
let mut res = Object::default();
|
||||
// Process the logins
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_dl(opt.ns(), opt.db()).await?.iter() {
|
||||
tmp.insert(v.name.to_string(), v.to_string().into());
|
||||
}
|
||||
res.insert("logins".to_owned(), tmp.into());
|
||||
// Process the users
|
||||
let mut tmp = Object::default();
|
||||
for v in run.all_db_users(opt.ns(), opt.db()).await?.iter() {
|
||||
|
|
|
@ -53,7 +53,6 @@ pub use self::define::DefineEventStatement;
|
|||
pub use self::define::DefineFieldStatement;
|
||||
pub use self::define::DefineFunctionStatement;
|
||||
pub use self::define::DefineIndexStatement;
|
||||
pub use self::define::DefineLoginStatement;
|
||||
pub use self::define::DefineNamespaceStatement;
|
||||
pub use self::define::DefineParamStatement;
|
||||
pub use self::define::DefineScopeStatement;
|
||||
|
@ -67,7 +66,6 @@ pub use self::remove::RemoveEventStatement;
|
|||
pub use self::remove::RemoveFieldStatement;
|
||||
pub use self::remove::RemoveFunctionStatement;
|
||||
pub use self::remove::RemoveIndexStatement;
|
||||
pub use self::remove::RemoveLoginStatement;
|
||||
pub use self::remove::RemoveNamespaceStatement;
|
||||
pub use self::remove::RemoveParamStatement;
|
||||
pub use self::remove::RemoveScopeStatement;
|
||||
|
|
|
@ -1,908 +0,0 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::{base, base_or_scope, Base};
|
||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::{map, opt};
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum RemoveStatement {
|
||||
Namespace(RemoveNamespaceStatement),
|
||||
Database(RemoveDatabaseStatement),
|
||||
Function(RemoveFunctionStatement),
|
||||
Analyzer(RemoveAnalyzerStatement),
|
||||
Login(RemoveLoginStatement),
|
||||
Token(RemoveTokenStatement),
|
||||
Scope(RemoveScopeStatement),
|
||||
Param(RemoveParamStatement),
|
||||
Table(RemoveTableStatement),
|
||||
Event(RemoveEventStatement),
|
||||
Field(RemoveFieldStatement),
|
||||
Index(RemoveIndexStatement),
|
||||
User(RemoveUserStatement),
|
||||
}
|
||||
|
||||
impl RemoveStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Login(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::User(ref v) => v.compute(ctx, opt, txn).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Namespace(v) => Display::fmt(v, f),
|
||||
Self::Database(v) => Display::fmt(v, f),
|
||||
Self::Function(v) => Display::fmt(v, f),
|
||||
Self::Login(v) => Display::fmt(v, f),
|
||||
Self::Token(v) => Display::fmt(v, f),
|
||||
Self::Scope(v) => Display::fmt(v, f),
|
||||
Self::Param(v) => Display::fmt(v, f),
|
||||
Self::Table(v) => Display::fmt(v, f),
|
||||
Self::Event(v) => Display::fmt(v, f),
|
||||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
Self::User(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
|
||||
alt((
|
||||
map(namespace, RemoveStatement::Namespace),
|
||||
map(database, RemoveStatement::Database),
|
||||
map(function, RemoveStatement::Function),
|
||||
map(login, RemoveStatement::Login),
|
||||
map(token, RemoveStatement::Token),
|
||||
map(scope, RemoveStatement::Scope),
|
||||
map(param, RemoveStatement::Param),
|
||||
map(table, RemoveStatement::Table),
|
||||
map(event, RemoveStatement::Event),
|
||||
map(field, RemoveStatement::Field),
|
||||
map(index, RemoveStatement::Index),
|
||||
map(analyzer, RemoveStatement::Analyzer),
|
||||
map(user, RemoveStatement::User),
|
||||
))(i)
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveNamespaceStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveNamespaceStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::root::ns::new(&self.name);
|
||||
run.del(key).await?;
|
||||
// Delete the resource data
|
||||
let key = crate::key::namespace::all::new(&self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveNamespaceStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE NAMESPACE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("NS"), tag_no_case("NAMESPACE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveNamespaceStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveDatabaseStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveDatabaseStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::db::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Delete the resource data
|
||||
let key = crate::key::database::all::new(opt.ns(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveDatabaseStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE DATABASE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("DB"), tag_no_case("DATABASE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveDatabaseStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveFunctionStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveFunctionStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveFunctionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE FUNCTION fn::{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FUNCTION")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag("fn::")(i)?;
|
||||
let (i, name) = ident::plain(i)?;
|
||||
let (i, _) = opt(|i| {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
Ok((i, ()))
|
||||
})(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveFunctionStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveAnalyzerStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveAnalyzerStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// TODO Check that the analyzer is not used in any schema
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveAnalyzerStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE ANALYZER {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzer(i: &str) -> IResult<&str, RemoveAnalyzerStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ANALYZER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveAnalyzerStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveLoginStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
}
|
||||
|
||||
impl RemoveLoginStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match self.base {
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::lg::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::lg::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveLoginStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE LOGIN {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
||||
fn login(i: &str) -> IResult<&str, RemoveLoginStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("LOGIN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveLoginStatement {
|
||||
name,
|
||||
base,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveTokenStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
}
|
||||
|
||||
impl RemoveTokenStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match &self.base {
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::tk::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Sc(sc) => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveTokenStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
||||
fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TOKEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base_or_scope(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveTokenStatement {
|
||||
name,
|
||||
base,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveScopeStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveScopeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the resource data
|
||||
let key = crate::key::scope::all::new(opt.ns(), opt.db(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveScopeStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE SCOPE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SCOPE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveScopeStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveParamStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveParamStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveParamStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE PARAM {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("PARAM")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = char('$')(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveParamStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveTableStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveTableStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the resource data
|
||||
let key = crate::key::table::all::new(opt.ns(), opt.db(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveTableStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TABLE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TABLE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveTableStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveEventStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveEventStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.del(key).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveEventStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE EVENT {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("EVENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveEventStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveFieldStatement {
|
||||
pub name: Idiom,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveFieldStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let fd = self.name.to_string();
|
||||
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd);
|
||||
run.del(key).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveFieldStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE FIELD {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FIELD")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = idiom::local(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveFieldStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveIndexStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the index data
|
||||
let key = crate::key::index::all::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ix::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveIndexStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE INDEX {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("INDEX")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveIndexStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveUserStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
}
|
||||
|
||||
impl RemoveUserStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match self.base {
|
||||
Base::Root => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
let key = crate::key::root::us::new(&self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::us::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveUserStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE USER {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
||||
fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("USER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveUserStatement {
|
||||
name,
|
||||
base,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_remove_serialize() {
|
||||
let stm = RemoveStatement::Namespace(RemoveNamespaceStatement {
|
||||
name: Ident::from("test"),
|
||||
});
|
||||
let enc: Vec<u8> = stm.try_into().unwrap();
|
||||
assert_eq!(9, enc.len());
|
||||
}
|
||||
}
|
63
lib/src/sql/statements/remove/analyzer.rs
Normal file
63
lib/src/sql/statements/remove/analyzer.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveAnalyzerStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveAnalyzerStatement {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// TODO Check that the analyzer is not used in any schema
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveAnalyzerStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE ANALYZER {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyzer(i: &str) -> IResult<&str, RemoveAnalyzerStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ANALYZER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveAnalyzerStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
67
lib/src/sql/statements/remove/database.rs
Normal file
67
lib/src/sql/statements/remove/database.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveDatabaseStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveDatabaseStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::db::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Delete the resource data
|
||||
let key = crate::key::database::all::new(opt.ns(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveDatabaseStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE DATABASE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("DB"), tag_no_case("DATABASE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveDatabaseStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
75
lib/src/sql/statements/remove/event.rs
Normal file
75
lib/src/sql/statements/remove/event.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveEventStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveEventStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.del(key).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveEventStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE EVENT {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("EVENT")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveEventStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
78
lib/src/sql/statements/remove/field.rs
Normal file
78
lib/src/sql/statements/remove/field.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveFieldStatement {
|
||||
pub name: Idiom,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveFieldStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let fd = self.name.to_string();
|
||||
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd);
|
||||
run.del(key).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveFieldStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE FIELD {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FIELD")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = idiom::local(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveFieldStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
75
lib/src/sql/statements/remove/function.rs
Normal file
75
lib/src/sql/statements/remove/function.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident;
|
||||
use crate::sql::ident::Ident;
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::opt;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveFunctionStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveFunctionStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveFunctionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE FUNCTION fn::{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("FUNCTION")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag("fn::")(i)?;
|
||||
let (i, name) = ident::plain(i)?;
|
||||
let (i, _) = opt(|i| {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char('(')(i)?;
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, _) = char(')')(i)?;
|
||||
Ok((i, ()))
|
||||
})(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveFunctionStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
78
lib/src/sql/statements/remove/index.rs
Normal file
78
lib/src/sql/statements/remove/index.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::tuple;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveIndexStatement {
|
||||
pub name: Ident,
|
||||
pub what: Ident,
|
||||
}
|
||||
|
||||
impl RemoveIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the index data
|
||||
let key = crate::key::index::all::new(opt.ns(), opt.db(), &self.what, &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Clear the cache
|
||||
let key = crate::key::table::ix::prefix(opt.ns(), opt.db(), &self.what);
|
||||
run.clr(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveIndexStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE INDEX {} ON {}", self.name, self.what)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("INDEX")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = opt(tuple((shouldbespace, tag_no_case("TABLE"))))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, what) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveIndexStatement {
|
||||
name,
|
||||
what,
|
||||
},
|
||||
))
|
||||
}
|
135
lib/src/sql/statements/remove/mod.rs
Normal file
135
lib/src/sql/statements/remove/mod.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
mod analyzer;
|
||||
mod database;
|
||||
mod event;
|
||||
mod field;
|
||||
mod function;
|
||||
mod index;
|
||||
mod namespace;
|
||||
mod param;
|
||||
mod scope;
|
||||
mod table;
|
||||
mod token;
|
||||
mod user;
|
||||
|
||||
pub use analyzer::{analyzer, RemoveAnalyzerStatement};
|
||||
pub use database::{database, RemoveDatabaseStatement};
|
||||
pub use event::{event, RemoveEventStatement};
|
||||
pub use field::{field, RemoveFieldStatement};
|
||||
pub use function::{function, RemoveFunctionStatement};
|
||||
pub use index::{index, RemoveIndexStatement};
|
||||
pub use namespace::{namespace, RemoveNamespaceStatement};
|
||||
pub use param::{param, RemoveParamStatement};
|
||||
pub use scope::{scope, RemoveScopeStatement};
|
||||
pub use table::{table, RemoveTableStatement};
|
||||
pub use token::{token, RemoveTokenStatement};
|
||||
pub use user::{user, RemoveUserStatement};
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub enum RemoveStatement {
|
||||
Namespace(RemoveNamespaceStatement),
|
||||
Database(RemoveDatabaseStatement),
|
||||
Function(RemoveFunctionStatement),
|
||||
Analyzer(RemoveAnalyzerStatement),
|
||||
Token(RemoveTokenStatement),
|
||||
Scope(RemoveScopeStatement),
|
||||
Param(RemoveParamStatement),
|
||||
Table(RemoveTableStatement),
|
||||
Event(RemoveEventStatement),
|
||||
Field(RemoveFieldStatement),
|
||||
Index(RemoveIndexStatement),
|
||||
User(RemoveUserStatement),
|
||||
}
|
||||
|
||||
impl RemoveStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::User(ref v) => v.compute(ctx, opt, txn).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Namespace(v) => Display::fmt(v, f),
|
||||
Self::Database(v) => Display::fmt(v, f),
|
||||
Self::Function(v) => Display::fmt(v, f),
|
||||
Self::Token(v) => Display::fmt(v, f),
|
||||
Self::Scope(v) => Display::fmt(v, f),
|
||||
Self::Param(v) => Display::fmt(v, f),
|
||||
Self::Table(v) => Display::fmt(v, f),
|
||||
Self::Event(v) => Display::fmt(v, f),
|
||||
Self::Field(v) => Display::fmt(v, f),
|
||||
Self::Index(v) => Display::fmt(v, f),
|
||||
Self::Analyzer(v) => Display::fmt(v, f),
|
||||
Self::User(v) => Display::fmt(v, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
|
||||
alt((
|
||||
map(namespace, RemoveStatement::Namespace),
|
||||
map(database, RemoveStatement::Database),
|
||||
map(function, RemoveStatement::Function),
|
||||
map(token, RemoveStatement::Token),
|
||||
map(scope, RemoveStatement::Scope),
|
||||
map(param, RemoveStatement::Param),
|
||||
map(table, RemoveStatement::Table),
|
||||
map(event, RemoveStatement::Event),
|
||||
map(field, RemoveStatement::Field),
|
||||
map(index, RemoveStatement::Index),
|
||||
map(analyzer, RemoveStatement::Analyzer),
|
||||
map(user, RemoveStatement::User),
|
||||
))(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::sql::Ident;
|
||||
|
||||
#[test]
|
||||
fn check_remove_serialize() {
|
||||
let stm = RemoveStatement::Namespace(RemoveNamespaceStatement {
|
||||
name: Ident::from("test"),
|
||||
..Default::default()
|
||||
});
|
||||
let enc: Vec<u8> = stm.try_into().unwrap();
|
||||
assert_eq!(9, enc.len());
|
||||
}
|
||||
}
|
67
lib/src/sql/statements/remove/namespace.rs
Normal file
67
lib/src/sql/statements/remove/namespace.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveNamespaceStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveNamespaceStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::root::ns::new(&self.name);
|
||||
run.del(key).await?;
|
||||
// Delete the resource data
|
||||
let key = crate::key::namespace::all::new(&self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveNamespaceStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE NAMESPACE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = alt((tag_no_case("NS"), tag_no_case("NAMESPACE")))(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveNamespaceStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
65
lib/src/sql/statements/remove/param.rs
Normal file
65
lib/src/sql/statements/remove/param.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::character::complete::char;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveParamStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveParamStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveParamStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE PARAM {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("PARAM")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = char('$')(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveParamStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
66
lib/src/sql/statements/remove/scope.rs
Normal file
66
lib/src/sql/statements/remove/scope.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveScopeStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveScopeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the resource data
|
||||
let key = crate::key::scope::all::new(opt.ns(), opt.db(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveScopeStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE SCOPE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("SCOPE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveScopeStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
66
lib/src/sql/statements/remove/table.rs
Normal file
66
lib/src/sql/statements/remove/table.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::Base;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveTableStatement {
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
impl RemoveTableStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Remove the resource data
|
||||
let key = crate::key::table::all::new(opt.ns(), opt.db(), &self.name);
|
||||
run.delp(key, u32::MAX).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveTableStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TABLE {}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TABLE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveTableStatement {
|
||||
name,
|
||||
},
|
||||
))
|
||||
}
|
97
lib/src/sql/statements/remove/token.rs
Normal file
97
lib/src/sql/statements/remove/token.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::{base_or_scope, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveTokenStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
}
|
||||
|
||||
impl RemoveTokenStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match &self.base {
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::tk::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Sc(sc) => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveTokenStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("TOKEN")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base_or_scope(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveTokenStatement {
|
||||
name,
|
||||
base,
|
||||
},
|
||||
))
|
||||
}
|
97
lib/src/sql/statements/remove/user.rs
Normal file
97
lib/src/sql/statements/remove/user.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::base::{base, Base};
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::value::Value;
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use revision::revisioned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
#[revisioned(revision = 1)]
|
||||
pub struct RemoveUserStatement {
|
||||
pub name: Ident,
|
||||
pub base: Base,
|
||||
}
|
||||
|
||||
impl RemoveUserStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
|
||||
|
||||
match self.base {
|
||||
Base::Root => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Process the statement
|
||||
let key = crate::key::root::us::new(&self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Ns => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::namespace::us::new(opt.ns(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
Base::Db => {
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Clear the cache
|
||||
run.clear_cache();
|
||||
// Delete the definition
|
||||
let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);
|
||||
run.del(key).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
_ => Err(Error::InvalidLevel(self.base.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RemoveUserStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "REMOVE USER {} ON {}", self.name, self.base)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
|
||||
let (i, _) = tag_no_case("REMOVE")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("USER")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, name) = ident(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, _) = tag_no_case("ON")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, base) = base(i)?;
|
||||
Ok((
|
||||
i,
|
||||
RemoveUserStatement {
|
||||
name,
|
||||
base,
|
||||
},
|
||||
))
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use nom::branch::alt;
|
||||
|
@ -41,8 +40,5 @@ fn tokenizer(i: &str) -> IResult<&str, Tokenizer> {
|
|||
}
|
||||
|
||||
pub(super) fn tokenizers(i: &str) -> IResult<&str, Vec<Tokenizer>> {
|
||||
let (i, _) = tag_no_case("TOKENIZERS")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, t) = separated_list1(commas, tokenizer)(i)?;
|
||||
Ok((i, t))
|
||||
separated_list1(commas, tokenizer)(i)
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ pub enum Value {
|
|||
Edges(Box<Edges>),
|
||||
Future(Box<Future>),
|
||||
Constant(Constant),
|
||||
// Closure(Box<Closure>),
|
||||
Function(Box<Function>),
|
||||
Subquery(Box<Subquery>),
|
||||
Expression(Box<Expression>),
|
||||
|
|
|
@ -57,7 +57,6 @@ async fn define_statement_database() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
databases: { test: 'DEFINE DATABASE test' },
|
||||
logins: {},
|
||||
tokens: {},
|
||||
users: {},
|
||||
}",
|
||||
|
@ -87,7 +86,6 @@ async fn define_statement_function() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: { test: 'DEFINE FUNCTION fn::test($first: string, $last: string) { RETURN $first + $last; }' },
|
||||
params: {},
|
||||
|
@ -121,7 +119,6 @@ async fn define_statement_table_drop() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -153,7 +150,6 @@ async fn define_statement_table_schemaless() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -189,7 +185,6 @@ async fn define_statement_table_schemafull() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -221,7 +216,6 @@ async fn define_statement_table_schemaful() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -1075,7 +1069,6 @@ async fn define_statement_analyzer() -> Result<(), Error> {
|
|||
autocomplete: 'DEFINE ANALYZER autocomplete FILTERS LOWERCASE,EDGENGRAM(2,10)',
|
||||
english: 'DEFINE ANALYZER english TOKENIZERS BLANK,CLASS FILTERS LOWERCASE,SNOWBALL(ENGLISH)',
|
||||
},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -1352,10 +1345,8 @@ async fn permissions_checks_define_db() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec![
|
||||
"{ databases: { DB: 'DEFINE DATABASE DB' }, logins: { }, tokens: { }, users: { } }",
|
||||
],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { DB: 'DEFINE DATABASE DB' }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1396,8 +1387,8 @@ async fn permissions_checks_define_function() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { greet: \"DEFINE FUNCTION fn::greet() { RETURN 'Hello'; }\" }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { greet: \"DEFINE FUNCTION fn::greet() { RETURN 'Hello'; }\" }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1438,8 +1429,8 @@ async fn permissions_checks_define_analyzer() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { analyzer: 'DEFINE ANALYZER analyzer TOKENIZERS BLANK' }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { analyzer: 'DEFINE ANALYZER analyzer TOKENIZERS BLANK' }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1480,8 +1471,8 @@ async fn permissions_checks_define_token_ns() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { token: \"DEFINE TOKEN token ON NAMESPACE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ databases: { }, tokens: { token: \"DEFINE TOKEN token ON NAMESPACE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1522,8 +1513,8 @@ async fn permissions_checks_define_token_db() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { token: \"DEFINE TOKEN token ON DATABASE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { token: \"DEFINE TOKEN token ON DATABASE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1606,8 +1597,8 @@ async fn permissions_checks_define_user_ns() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ databases: { }, tokens: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1648,8 +1639,8 @@ async fn permissions_checks_define_user_db() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1690,8 +1681,8 @@ async fn permissions_checks_define_scope() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { account: 'DEFINE SCOPE account SESSION 1h' }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { account: 'DEFINE SCOPE account SESSION 1h' }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1732,8 +1723,8 @@ async fn permissions_checks_define_param() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { param: \"DEFINE PARAM $param VALUE 'foo'\" }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { }, params: { param: \"DEFINE PARAM $param VALUE 'foo'\" }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -1771,8 +1762,8 @@ async fn permissions_checks_define_table() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { TB: 'DEFINE TABLE TB SCHEMALESS' }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { TB: 'DEFINE TABLE TB SCHEMALESS' }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"]
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
|
|
@ -55,7 +55,7 @@ async fn info_for_ns() {
|
|||
assert!(out.is_ok(), "Unexpected error: {:?}", out);
|
||||
|
||||
let output_regex = Regex::new(
|
||||
r"\{ databases: \{ DB: .* \}, logins: \{ \}, tokens: \{ token: .* \}, users: \{ user: .* \} \}",
|
||||
r"\{ databases: \{ DB: .* \}, tokens: \{ token: .* \}, users: \{ user: .* \} \}",
|
||||
)
|
||||
.unwrap();
|
||||
let out_str = out.unwrap().to_string();
|
||||
|
@ -88,7 +88,7 @@ async fn info_for_db() {
|
|||
let out = res.pop().unwrap().output();
|
||||
assert!(out.is_ok(), "Unexpected error: {:?}", out);
|
||||
|
||||
let output_regex = Regex::new(r"\{ analyzers: \{ analyzer: .* \}, functions: \{ greet: .* \}, logins: \{ \}, params: \{ param: .* \}, scopes: \{ account: .* \}, tables: \{ TB: .* \}, tokens: \{ token: .* \}, users: \{ user: .* \} \}").unwrap();
|
||||
let output_regex = Regex::new(r"\{ analyzers: \{ analyzer: .* \}, functions: \{ greet: .* \}, params: \{ param: .* \}, scopes: \{ account: .* \}, tables: \{ TB: .* \}, tokens: \{ token: .* \}, users: \{ user: .* \} \}").unwrap();
|
||||
let out_str = out.unwrap().to_string();
|
||||
assert!(
|
||||
output_regex.is_match(&out_str),
|
||||
|
@ -276,8 +276,8 @@ async fn permissions_checks_info_ns() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -315,8 +315,8 @@ async fn permissions_checks_info_db() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
|
|
@ -26,7 +26,6 @@ async fn define_global_param() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: { test: 'DEFINE PARAM $test VALUE 12345' },
|
||||
|
|
|
@ -37,7 +37,6 @@ async fn remove_statement_table() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -72,7 +71,6 @@ async fn remove_statement_analyzer() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
@ -181,10 +179,8 @@ async fn permissions_checks_remove_db() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec![
|
||||
"{ databases: { DB: 'DEFINE DATABASE DB' }, logins: { }, tokens: { }, users: { } }",
|
||||
],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { DB: 'DEFINE DATABASE DB' }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -225,8 +221,8 @@ async fn permissions_checks_remove_function() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { greet: \"DEFINE FUNCTION fn::greet() { RETURN 'Hello'; }\" }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { greet: \"DEFINE FUNCTION fn::greet() { RETURN 'Hello'; }\" }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -267,8 +263,8 @@ async fn permissions_checks_remove_analyzer() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { analyzer: 'DEFINE ANALYZER analyzer TOKENIZERS BLANK' }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { analyzer: 'DEFINE ANALYZER analyzer TOKENIZERS BLANK' }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -309,8 +305,8 @@ async fn permissions_checks_remove_ns_token() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { token: \"DEFINE TOKEN token ON NAMESPACE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { token: \"DEFINE TOKEN token ON NAMESPACE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -351,8 +347,8 @@ async fn permissions_checks_remove_db_token() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { token: \"DEFINE TOKEN token ON DATABASE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { token: \"DEFINE TOKEN token ON DATABASE TYPE HS512 VALUE 'secret'\" }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -435,8 +431,8 @@ async fn permissions_checks_remove_ns_user() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, logins: { }, tokens: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ databases: { }, tokens: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -477,8 +473,8 @@ async fn permissions_checks_remove_db_user() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -519,8 +515,8 @@ async fn permissions_checks_remove_scope() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { account: 'DEFINE SCOPE account SESSION 1h' }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { account: 'DEFINE SCOPE account SESSION 1h' }, tables: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -561,8 +557,8 @@ async fn permissions_checks_remove_param() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { param: \"DEFINE PARAM $param VALUE 'foo'\" }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { param: \"DEFINE PARAM $param VALUE 'foo'\" }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -603,8 +599,8 @@ async fn permissions_checks_remove_table() {
|
|||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, logins: { }, params: { }, scopes: { }, tables: { TB: 'DEFINE TABLE TB SCHEMALESS' }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { }, tokens: { }, users: { } }"],
|
||||
vec!["{ analyzers: { }, functions: { }, params: { }, scopes: { }, tables: { TB: 'DEFINE TABLE TB SCHEMALESS' }, tokens: { }, users: { } }"],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
|
|
@ -242,7 +242,6 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
databases: { test: 'DEFINE DATABASE test' },
|
||||
logins: {},
|
||||
tokens: {},
|
||||
users: {},
|
||||
}",
|
||||
|
@ -253,7 +252,6 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
|||
let val = Value::parse(
|
||||
"{
|
||||
analyzers: {},
|
||||
logins: {},
|
||||
tokens: {},
|
||||
functions: {},
|
||||
params: {},
|
||||
|
|
Loading…
Reference in a new issue