Implement IF EXISTS for additional REMOVE-statements (#3377)

Co-authored-by: Tobie Morgan Hitchcock <tobie@surrealdb.com>
Co-authored-by: Rushmore Mushambi <rushmore@surrealdb.com>
This commit is contained in:
Micha de Vries 2024-03-05 20:28:38 +01:00 committed by GitHub
parent 0e2f83ed9d
commit 50b4b07b38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1632 additions and 338 deletions

View file

@ -319,12 +319,26 @@ pub enum Error {
value: String,
},
/// The requested event does not exist
#[error("The event '{value}' does not exist")]
#[cfg(feature = "sql2")]
EvNotFound {
value: String,
},
/// The requested function does not exist
#[error("The function 'fn::{value}' does not exist")]
FcNotFound {
value: String,
},
/// The requested field does not exist
#[error("The field '{value}' does not exist")]
#[cfg(feature = "sql2")]
FdNotFound {
value: String,
},
/// The requested model does not exist
#[error("The model 'ml::{value}' does not exist")]
MlNotFound {

View file

@ -1908,6 +1908,36 @@ impl Transaction {
Ok(val.into())
}
/// Retrieve a specific function definition from a database.
#[cfg(feature = "sql2")]
pub async fn get_db_function(
&mut self,
ns: &str,
db: &str,
fc: &str,
) -> Result<DefineFunctionStatement, Error> {
let key = crate::key::database::fc::new(ns, db, fc);
let val = self.get(key).await?.ok_or(Error::FcNotFound {
value: fc.to_owned(),
})?;
Ok(val.into())
}
/// Retrieve a specific function definition from a database.
#[cfg(feature = "sql2")]
pub async fn get_db_param(
&mut self,
ns: &str,
db: &str,
pa: &str,
) -> Result<DefineParamStatement, Error> {
let key = crate::key::database::pa::new(ns, db, pa);
let val = self.get(key).await?.ok_or(Error::PaNotFound {
value: pa.to_owned(),
})?;
Ok(val.into())
}
/// Retrieve a specific scope definition.
pub async fn get_sc(
&mut self,
@ -1983,6 +2013,60 @@ impl Transaction {
Ok(val.into())
}
/// Retrieve an event for a table.
#[cfg(feature = "sql2")]
pub async fn get_tb_event(
&mut self,
ns: &str,
db: &str,
tb: &str,
ev: &str,
) -> Result<DefineEventStatement, Error> {
let key = crate::key::table::ev::new(ns, db, tb, ev);
let key_enc = crate::key::table::ev::Ev::encode(&key)?;
trace!("Getting ev ({:?}) {:?}", ev, crate::key::debug::sprint_key(&key_enc));
let val = self.get(key_enc).await?.ok_or(Error::EvNotFound {
value: ev.to_string(),
})?;
Ok(val.into())
}
/// Retrieve an event for a table.
#[cfg(feature = "sql2")]
pub async fn get_tb_field(
&mut self,
ns: &str,
db: &str,
tb: &str,
fd: &str,
) -> Result<DefineFieldStatement, Error> {
let key = crate::key::table::fd::new(ns, db, tb, fd);
let key_enc = crate::key::table::fd::Fd::encode(&key)?;
trace!("Getting fd ({:?}) {:?}", fd, crate::key::debug::sprint_key(&key_enc));
let val = self.get(key_enc).await?.ok_or(Error::FdNotFound {
value: fd.to_string(),
})?;
Ok(val.into())
}
/// Retrieve an event for a table.
#[cfg(feature = "sql2")]
pub async fn get_tb_index(
&mut self,
ns: &str,
db: &str,
tb: &str,
ix: &str,
) -> Result<DefineFieldStatement, Error> {
let key = crate::key::table::ix::new(ns, db, tb, ix);
let key_enc = crate::key::table::ix::Ix::encode(&key)?;
trace!("Getting ix ({:?}) {:?}", ix, crate::key::debug::sprint_key(&key_enc));
let val = self.get(key_enc).await?.ok_or(Error::IxNotFound {
value: ix.to_string(),
})?;
Ok(val.into())
}
/// Add a namespace with a default configuration, only if we are in dynamic mode.
pub async fn add_ns(
&mut self,

View file

@ -39,6 +39,6 @@ impl RemoveParamStatement {
impl Display for RemoveParamStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE PARAM {}", self.name)
write!(f, "REMOVE PARAM ${}", self.name)
}
}

View file

@ -10,9 +10,11 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveAnalyzerStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveAnalyzerStatement {
@ -22,23 +24,39 @@ impl RemoveAnalyzerStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let az = run.get_db_analyzer(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::az::new(opt.ns(), opt.db(), &az.name);
run.del(key).await?;
// TODO Check that the analyzer is not used in any schema
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::AzNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveAnalyzerStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE ANALYZER {}", self.name)
write!(f, "REMOVE ANALYZER")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {}", self.name)?;
Ok(())
}
}

View file

@ -10,9 +10,11 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveDatabaseStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveDatabaseStatement {
@ -23,25 +25,41 @@ impl RemoveDatabaseStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let db = run.get_db(opt.ns(), &self.name).await?;
// Delete the definition
let key = crate::key::namespace::db::new(opt.ns(), &self.name);
let key = crate::key::namespace::db::new(opt.ns(), &db.name);
run.del(key).await?;
// Delete the resource data
let key = crate::key::database::all::new(opt.ns(), &self.name);
let key = crate::key::database::all::new(opt.ns(), &db.name);
run.delp(key, u32::MAX).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::DbNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveDatabaseStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE DATABASE {}", self.name)
write!(f, "REMOVE DATABASE")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {}", self.name)?;
Ok(())
}
}

View file

@ -10,10 +10,12 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveEventStatement {
pub name: Ident,
pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveEventStatement {
@ -24,25 +26,41 @@ impl RemoveEventStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let ev = run.get_tb_event(opt.ns(), opt.db(), &self.what, &self.name).await?;
// Delete the definition
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name);
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &ev.what, &ev.name);
run.del(key).await?;
// Clear the cache
let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &self.what);
let key = crate::key::table::ev::prefix(opt.ns(), opt.db(), &ev.what);
run.clr(key).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::EvNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveEventStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE EVENT {} ON {}", self.name, self.what)
write!(f, "REMOVE EVENT")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {} ON {}", self.name, self.what)?;
Ok(())
}
}

View file

@ -9,11 +9,13 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveFieldStatement {
pub name: Idiom,
pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveFieldStatement {
@ -24,15 +26,19 @@ impl RemoveFieldStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let fd_name = self.name.to_string();
let fd = run.get_tb_field(opt.ns(), opt.db(), &self.what, &fd_name).await?;
// Delete the definition
let fd = self.name.to_string();
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd);
let fd_name = fd.name.to_string();
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd_name);
run.del(key).await?;
// Clear the cache
let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what);
@ -40,10 +46,23 @@ impl RemoveFieldStatement {
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::FdNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveFieldStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE FIELD {} ON {}", self.name, self.what)
write!(f, "REMOVE FIELD")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {} ON {}", self.name, self.what)?;
Ok(())
}
}

View file

@ -10,9 +10,11 @@ use std::fmt::{self, Display};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveFunctionStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveFunctionStatement {
@ -23,23 +25,39 @@ impl RemoveFunctionStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let fc = run.get_db_function(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &fc.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::FcNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveFunctionStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Bypass ident display since we don't want backticks arround the ident.
write!(f, "REMOVE FUNCTION fn::{}", self.name.0)
write!(f, "REMOVE FUNCTION")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " fn::{}", self.name.0)?;
Ok(())
}
}

View file

@ -9,11 +9,13 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveIndexStatement {
pub name: Ident,
pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveIndexStatement {
@ -24,6 +26,7 @@ impl RemoveIndexStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
// Claim transaction
@ -44,10 +47,23 @@ impl RemoveIndexStatement {
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::IxNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveIndexStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE INDEX {} ON {}", self.name, self.what)
write!(f, "REMOVE INDEX")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {} ON {}", self.name, self.what)?;
Ok(())
}
}

View file

@ -9,11 +9,13 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveModelStatement {
pub name: Ident,
pub version: String,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveModelStatement {
@ -24,6 +26,7 @@ impl RemoveModelStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?;
// Claim transaction
@ -38,11 +41,24 @@ impl RemoveModelStatement {
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::MlNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveModelStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Bypass ident display since we don't want backticks arround the ident.
write!(f, "REMOVE MODEL ml::{}<{}>", self.name.0, self.version)
write!(f, "REMOVE MODEL")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " ml::{}<{}>", self.name.0, self.version)?;
Ok(())
}
}

View file

@ -10,9 +10,11 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveNamespaceStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveNamespaceStatement {
@ -23,6 +25,7 @@ impl RemoveNamespaceStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?;
// Claim transaction
@ -30,19 +33,34 @@ impl RemoveNamespaceStatement {
ctx.get_index_stores().namespace_removed(opt, &mut run).await?;
// Clear the cache
run.clear_cache();
// Get the definition
let ns = run.get_ns(&self.name).await?;
// Delete the definition
let key = crate::key::root::ns::new(&self.name);
let key = crate::key::root::ns::new(&ns.name);
run.del(key).await?;
// Delete the resource data
let key = crate::key::namespace::all::new(&self.name);
let key = crate::key::namespace::all::new(&ns.name);
run.delp(key, u32::MAX).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::NsNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveNamespaceStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE NAMESPACE {}", self.name)
write!(f, "REMOVE NAMESPACE")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {}", self.name)?;
Ok(())
}
}

View file

@ -9,10 +9,12 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveParamStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveParamStatement {
@ -23,22 +25,38 @@ impl RemoveParamStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let pa = run.get_db_param(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &pa.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::PaNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveParamStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE PARAM {}", self.name)
write!(f, "REMOVE PARAM")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " ${}", self.name)?;
Ok(())
}
}

View file

@ -10,9 +10,11 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveScopeStatement {
pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveScopeStatement {
@ -23,25 +25,41 @@ impl RemoveScopeStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// 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();
// Get the definition
let sc = run.get_sc(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::sc::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::sc::new(opt.ns(), opt.db(), &sc.name);
run.del(key).await?;
// Remove the resource data
let key = crate::key::scope::all::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::scope::all::new(opt.ns(), opt.db(), &sc.name);
run.delp(key, u32::MAX).await?;
// Ok all good
Ok(Value::None)
}
.await
{
Err(Error::ScNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveScopeStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE SCOPE {}", self.name)
write!(f, "REMOVE SCOPE")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {}", self.name)?;
Ok(())
}
}

View file

@ -26,6 +26,7 @@ impl RemoveTableStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
// Claim transaction
@ -35,8 +36,7 @@ impl RemoveTableStatement {
// Clear the cache
run.clear_cache();
// Get the defined table
match run.get_tb(opt.ns(), opt.db(), &self.name).await {
Ok(tb) => {
let tb = run.get_tb(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);
run.del(key).await?;
@ -55,23 +55,23 @@ impl RemoveTableStatement {
// Ok all good
Ok(Value::None)
}
Err(err) => {
if matches!(err, Error::TbNotFound { .. }) && self.if_exists {
Ok(Value::None)
} else {
Err(err)
}
}
.await
{
Err(Error::TbNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
}
impl Display for RemoveTableStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE TABLE {}", self.name)?;
write!(f, "REMOVE TABLE")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {}", self.name)?;
Ok(())
}
}

View file

@ -10,10 +10,12 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
pub struct RemoveTokenStatement {
pub name: Ident,
pub base: Base,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveTokenStatement {
@ -24,6 +26,7 @@ impl RemoveTokenStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
@ -33,8 +36,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let tk = run.get_ns_token(opt.ns(), &self.name).await?;
// Delete the definition
let key = crate::key::namespace::tk::new(opt.ns(), &self.name);
let key = crate::key::namespace::tk::new(opt.ns(), &tk.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -44,8 +49,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let tk = run.get_db_token(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::tk::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::tk::new(opt.ns(), opt.db(), &tk.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -55,8 +62,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let tk = run.get_sc_token(opt.ns(), opt.db(), sc, &self.name).await?;
// Delete the definition
let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &self.name);
let key = crate::key::scope::tk::new(opt.ns(), opt.db(), sc, &tk.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -64,10 +73,32 @@ impl RemoveTokenStatement {
_ => Err(Error::InvalidLevel(self.base.to_string())),
}
}
.await
{
Err(e) if self.if_exists => match e {
Error::NtNotFound {
..
} => Ok(Value::None),
Error::DtNotFound {
..
} => Ok(Value::None),
Error::StNotFound {
..
} => Ok(Value::None),
e => Err(e),
},
v => v,
}
}
}
impl Display for RemoveTokenStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base)
write!(f, "REMOVE TOKEN")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {} ON {}", self.name, self.base)?;
Ok(())
}
}

View file

@ -9,11 +9,13 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)]
#[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveUserStatement {
pub name: Ident,
pub base: Base,
#[revision(start = 2)]
pub if_exists: bool,
}
impl RemoveUserStatement {
@ -24,6 +26,7 @@ impl RemoveUserStatement {
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match async {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
@ -33,8 +36,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let us = run.get_root_user(&self.name).await?;
// Process the statement
let key = crate::key::root::us::new(&self.name);
let key = crate::key::root::us::new(&us.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -44,8 +49,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let us = run.get_ns_user(opt.ns(), &self.name).await?;
// Delete the definition
let key = crate::key::namespace::us::new(opt.ns(), &self.name);
let key = crate::key::namespace::us::new(opt.ns(), &us.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -55,8 +62,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await;
// Clear the cache
run.clear_cache();
// Get the definition
let us = run.get_db_user(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition
let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);
let key = crate::key::database::us::new(opt.ns(), opt.db(), &us.name);
run.del(key).await?;
// Ok all good
Ok(Value::None)
@ -64,10 +73,32 @@ impl RemoveUserStatement {
_ => Err(Error::InvalidLevel(self.base.to_string())),
}
}
.await
{
Err(e) if self.if_exists => match e {
Error::UserRootNotFound {
..
} => Ok(Value::None),
Error::UserNsNotFound {
..
} => Ok(Value::None),
Error::UserDbNotFound {
..
} => Ok(Value::None),
e => Err(e),
},
v => v,
}
}
}
impl Display for RemoveUserStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE USER {} ON {}", self.name, self.base)
write!(f, "REMOVE USER")?;
if self.if_exists {
write!(f, " IF EXISTS")?
}
write!(f, " {} ON {}", self.name, self.base)?;
Ok(())
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveAnalyzerStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveAnalyzerStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveAnalyzerStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveDatabaseStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveDatabaseStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveDatabaseStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveDatabaseStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveDatabaseStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveDatabaseStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -37,6 +37,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveEventStatement {
name: Ident,
what: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveEventStatement {
@ -54,6 +55,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveEventStatement {
"what" => {
self.what = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveEventStatement::{key}`"
@ -67,6 +71,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveEventStatement {
Ok(RemoveEventStatement {
name: self.name,
what: self.what,
if_exists: self.if_exists,
})
}
}

View file

@ -38,6 +38,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveFieldStatement {
name: Idiom,
what: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveFieldStatement {
@ -55,6 +56,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveFieldStatement {
"what" => {
self.what = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveFieldStatement::{key}`"
@ -68,6 +72,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveFieldStatement {
Ok(RemoveFieldStatement {
name: self.name,
what: self.what,
if_exists: self.if_exists,
})
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveFunctionStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveFunctionStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveFunctionStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveFunctionStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveFunctionStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveFunctionStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -37,6 +37,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveIndexStatement {
name: Ident,
what: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveIndexStatement {
@ -54,6 +55,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveIndexStatement {
"what" => {
self.what = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveIndexStatement::{key}`"
@ -67,6 +71,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveIndexStatement {
Ok(RemoveIndexStatement {
name: self.name,
what: self.what,
if_exists: self.if_exists,
})
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveNamespaceStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveNamespaceStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveNamespaceStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveNamespaceStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveNamespaceStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveNamespaceStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveParamStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveParamStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveParamStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveParamStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveParamStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveParamStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -36,6 +36,7 @@ impl ser::Serializer for Serializer {
#[derive(Default)]
pub struct SerializeRemoveScopeStatement {
name: Ident,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveScopeStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveScopeStatement {
"name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveScopeStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveScopeStatement {
fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveScopeStatement {
name: self.name,
if_exists: self.if_exists,
})
}
}

View file

@ -38,6 +38,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveTokenStatement {
name: Ident,
base: Base,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveTokenStatement {
@ -55,6 +56,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveTokenStatement {
"base" => {
self.base = value.serialize(ser::base::Serializer.wrap())?;
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveTokenStatement::{key}`"
@ -68,6 +72,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveTokenStatement {
Ok(RemoveTokenStatement {
name: self.name,
base: self.base,
if_exists: self.if_exists,
})
}
}

View file

@ -38,6 +38,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveUserStatement {
name: Ident,
base: Base,
if_exists: bool,
}
impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
@ -55,6 +56,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
"base" => {
self.base = value.serialize(ser::base::Serializer.wrap())?;
}
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => {
return Err(Error::custom(format!(
"unexpected field `RemoveUserStatement::{key}`"
@ -68,6 +72,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
Ok(RemoveUserStatement {
name: self.name,
base: self.base,
if_exists: self.if_exists,
})
}
}

View file

@ -41,30 +41,52 @@ pub fn remove(i: &str) -> IResult<&str, RemoveStatement> {
pub fn analyzer(i: &str) -> IResult<&str, RemoveAnalyzerStatement> {
let (i, _) = tag_no_case("ANALYZER")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveAnalyzerStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
let (i, _) = alt((tag_no_case("DB"), tag_no_case("DATABASE")))(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveDatabaseStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
let (i, _) = tag_no_case("EVENT")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?;
@ -77,12 +99,20 @@ pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
RemoveEventStatement {
name,
what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
let (i, _) = tag_no_case("FIELD")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(idiom::local)(i)?;
let (i, _) = shouldbespace(i)?;
@ -95,12 +125,20 @@ pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
RemoveFieldStatement {
name,
what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
let (i, _) = tag_no_case("FUNCTION")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, _) = tag("fn::")(i)?;
let (i, name) = ident_path(i)?;
@ -115,12 +153,20 @@ pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
i,
RemoveFunctionStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
let (i, _) = tag_no_case("INDEX")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?;
@ -133,24 +179,40 @@ pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
RemoveIndexStatement {
name,
what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
let (i, _) = alt((tag_no_case("NS"), tag_no_case("NAMESPACE")))(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveNamespaceStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
let (i, _) = tag_no_case("PARAM")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, _) = cut(char('$'))(i)?;
let (i, name) = cut(ident)(i)?;
@ -158,32 +220,42 @@ pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
i,
RemoveParamStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
let (i, _) = tag_no_case("SCOPE")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveScopeStatement {
name,
},
))
}
pub fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
let (i, _) = tag_no_case("TABLE")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveScopeStatement {
name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
let (i, _) = tag_no_case("TABLE")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
Ok((
i,
RemoveTableStatement {
@ -196,6 +268,12 @@ pub fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
let (i, _) = tag_no_case("TOKEN")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?;
@ -207,12 +285,20 @@ pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
RemoveTokenStatement {
name,
base,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
let (i, _) = tag_no_case("USER")(i)?;
#[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple((
shouldbespace,
tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?;
let (i, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?;
@ -224,6 +310,8 @@ pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
RemoveUserStatement {
name,
base,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
},
))
}
@ -238,9 +326,149 @@ mod tests {
fn check_remove_serialize() {
let stm = RemoveStatement::Namespace(RemoveNamespaceStatement {
name: Ident::from("test"),
#[cfg(feature = "sql2")]
if_exists: false,
});
let enc: Vec<u8> = stm.try_into().unwrap();
#[cfg(not(feature = "sql2"))]
assert_eq!(9, enc.len());
#[cfg(feature = "sql2")]
assert_eq!(10, enc.len());
}
/// REMOVE ANALYZER tests
#[test]
fn remove_analyzer() {
let sql = "REMOVE ANALYZER test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE ANALYZER test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_analyzer_if_exists() {
let sql = "REMOVE ANALYZER IF EXISTS test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE ANALYZER IF EXISTS test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_analyzer_if() {
let sql = "REMOVE ANALYZER IF test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE DATABASE tests
#[test]
fn remove_database() {
let sql = "REMOVE DATABASE test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE DATABASE test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_database_if_exists() {
let sql = "REMOVE DATABASE IF EXISTS test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE DATABASE IF EXISTS test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_database_if() {
let sql = "REMOVE DATABASE IF test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE EVENT tests
#[test]
fn remove_event() {
let sql = "REMOVE EVENT test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE EVENT test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_event_if_exists() {
let sql = "REMOVE EVENT IF EXISTS test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE EVENT IF EXISTS test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_event_if() {
let sql = "REMOVE EVENT IF test ON test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE FIELD tests
#[test]
fn remove_field() {
let sql = "REMOVE FIELD test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE FIELD test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_field_if_exists() {
let sql = "REMOVE FIELD IF EXISTS test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE FIELD IF EXISTS test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_field_if() {
let sql = "REMOVE FIELD IF test ON test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE FUNCTION tests
#[test]
fn remove_function() {
let sql = "REMOVE FUNCTION fn::test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE FUNCTION fn::test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_function_if_exists() {
let sql = "REMOVE FUNCTION IF EXISTS fn::test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE FUNCTION IF EXISTS fn::test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_function_if() {
let sql = "REMOVE FUNCTION IF fn::test";
let res = remove(sql);
assert!(res.is_err());
}
#[test]
@ -251,6 +479,116 @@ mod tests {
assert_eq!("REMOVE FUNCTION fn::foo::bar::baz::bac", format!("{}", out))
}
/// REMOVE INDEX tests
#[test]
fn remove_index() {
let sql = "REMOVE INDEX test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE INDEX test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_index_if_exists() {
let sql = "REMOVE INDEX IF EXISTS test ON test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE INDEX IF EXISTS test ON test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_index_if() {
let sql = "REMOVE INDEX IF test ON test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE NAMESPACE tests
#[test]
fn remove_namespace() {
let sql = "REMOVE NAMESPACE test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE NAMESPACE test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_namespace_if_exists() {
let sql = "REMOVE NAMESPACE IF EXISTS test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE NAMESPACE IF EXISTS test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_namespace_if() {
let sql = "REMOVE NAMESPACE IF test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE PARAM tests
#[test]
fn remove_param() {
let sql = "REMOVE PARAM $test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE PARAM $test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_param_if_exists() {
let sql = "REMOVE PARAM IF EXISTS $test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE PARAM IF EXISTS $test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_param_if() {
let sql = "REMOVE PARAM IF $test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE SCOPE tests
#[test]
fn remove_scope() {
let sql = "REMOVE SCOPE test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE SCOPE test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_scope_if_exists() {
let sql = "REMOVE SCOPE IF EXISTS test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE SCOPE IF EXISTS test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_scope_if() {
let sql = "REMOVE SCOPE IF test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE TABLE tests
#[test]
fn remove_table() {
let sql = "REMOVE TABLE test";
@ -262,16 +600,70 @@ mod tests {
#[test]
#[cfg(feature = "sql2")]
fn remove_table_if_exists() {
let sql = "REMOVE TABLE test IF EXISTS";
let sql = "REMOVE TABLE IF EXISTS test";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE TABLE test IF EXISTS", format!("{}", out))
assert_eq!("REMOVE TABLE IF EXISTS test", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_table_if() {
let sql = "REMOVE TABLE test IF";
let sql = "REMOVE TABLE IF test";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE TOKEN tests
#[test]
fn remove_token() {
let sql = "REMOVE TOKEN test ON NAMESPACE";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE TOKEN test ON NAMESPACE", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_token_if_exists() {
let sql = "REMOVE TOKEN IF EXISTS test ON NAMESPACE";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE TOKEN IF EXISTS test ON NAMESPACE", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_token_if() {
let sql = "REMOVE TOKEN IF test ON NAMESPACE";
let res = remove(sql);
assert!(res.is_err());
}
/// REMOVE USER tests
#[test]
fn remove_user() {
let sql = "REMOVE USER test ON ROOT";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE USER test ON ROOT", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_user_if_exists() {
let sql = "REMOVE USER IF EXISTS test ON ROOT";
let res = remove(sql);
let out = res.unwrap().1;
assert_eq!("REMOVE USER IF EXISTS test ON ROOT", format!("{}", out))
}
#[test]
#[cfg(feature = "sql2")]
fn remove_user_if() {
let sql = "REMOVE USER IF test ON ROOT";
let res = remove(sql);
assert!(res.is_err());
}

View file

@ -21,50 +21,6 @@ impl Parser<'_> {
pub fn parse_remove_stmt(&mut self) -> ParseResult<RemoveStatement> {
let res = match self.next().kind {
t!("NAMESPACE") => {
let name = self.next_token_value()?;
RemoveStatement::Namespace(RemoveNamespaceStatement {
name,
})
}
t!("DATABASE") => {
let name = self.next_token_value()?;
RemoveStatement::Database(RemoveDatabaseStatement {
name,
})
}
t!("FUNCTION") => {
let name = self.parse_custom_function_name()?;
let next = self.peek();
if self.eat(t!("(")) {
self.expect_closing_delimiter(t!(")"), next.span)?;
}
RemoveStatement::Function(RemoveFunctionStatement {
name,
})
}
t!("TOKEN") => {
let name = self.next_token_value()?;
expected!(self, t!("ON"));
let base = self.parse_base(true)?;
RemoveStatement::Token(crate::sql::statements::RemoveTokenStatement {
name,
base,
})
}
t!("SCOPE") => {
let name = self.next_token_value()?;
RemoveStatement::Scope(RemoveScopeStatement {
name,
})
}
t!("PARAM") => {
let name = self.next_token_value::<Param>()?;
RemoveStatement::Param(RemoveParamStatement {
name: name.0,
})
}
t!("TABLE") => {
let name = self.next_token_value()?;
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
@ -72,6 +28,110 @@ impl Parser<'_> {
} else {
false
};
let name = self.next_token_value()?;
RemoveStatement::Namespace(RemoveNamespaceStatement {
name,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("DATABASE") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
RemoveStatement::Database(RemoveDatabaseStatement {
name,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("FUNCTION") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.parse_custom_function_name()?;
let next = self.peek();
if self.eat(t!("(")) {
self.expect_closing_delimiter(t!(")"), next.span)?;
}
RemoveStatement::Function(RemoveFunctionStatement {
name,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("TOKEN") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
expected!(self, t!("ON"));
let base = self.parse_base(true)?;
RemoveStatement::Token(crate::sql::statements::RemoveTokenStatement {
name,
base,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("SCOPE") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
RemoveStatement::Scope(RemoveScopeStatement {
name,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("PARAM") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value::<Param>()?;
RemoveStatement::Param(RemoveParamStatement {
name: name.0,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("TABLE") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
RemoveStatement::Table(crate::sql::statements::RemoveTableStatement {
name,
@ -80,48 +140,98 @@ impl Parser<'_> {
})
}
t!("EVENT") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
expected!(self, t!("ON"));
self.eat(t!("TABLE"));
let table = self.next_token_value()?;
RemoveStatement::Event(RemoveEventStatement {
name,
what: table,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("FIELD") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let idiom = self.parse_local_idiom()?;
expected!(self, t!("ON"));
self.eat(t!("TABLE"));
let table = self.next_token_value()?;
RemoveStatement::Field(RemoveFieldStatement {
name: idiom,
what: table,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("INDEX") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
expected!(self, t!("ON"));
self.eat(t!("TABLE"));
let what = self.next_token_value()?;
RemoveStatement::Index(RemoveIndexStatement {
name,
what,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("ANALYZER") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
RemoveStatement::Analyzer(RemoveAnalyzerStatement {
name,
#[cfg(feature = "sql2")]
if_exists,
})
}
t!("USER") => {
#[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS"));
true
} else {
false
};
let name = self.next_token_value()?;
expected!(self, t!("ON"));
let base = self.parse_base(false)?;
RemoveStatement::User(RemoveUserStatement {
name,
base,
#[cfg(feature = "sql2")]
if_exists,
})
}
x => unexpected!(self, x, "a remove statement keyword"),

View file

@ -1057,7 +1057,9 @@ fn parse_remove() {
assert_eq!(
res,
Statement::Remove(RemoveStatement::Namespace(RemoveNamespaceStatement {
name: Ident("ns".to_owned())
name: Ident("ns".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1065,7 +1067,9 @@ fn parse_remove() {
assert_eq!(
res,
Statement::Remove(RemoveStatement::Database(RemoveDatabaseStatement {
name: Ident("database".to_owned())
name: Ident("database".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1073,14 +1077,18 @@ fn parse_remove() {
assert_eq!(
res,
Statement::Remove(RemoveStatement::Function(RemoveFunctionStatement {
name: Ident("foo::bar".to_owned())
name: Ident("foo::bar".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
let res = test_parse!(parse_stmt, r#"REMOVE FUNCTION fn::foo::bar();"#).unwrap();
assert_eq!(
res,
Statement::Remove(RemoveStatement::Function(RemoveFunctionStatement {
name: Ident("foo::bar".to_owned())
name: Ident("foo::bar".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1089,7 +1097,9 @@ fn parse_remove() {
res,
Statement::Remove(RemoveStatement::Token(RemoveTokenStatement {
name: Ident("foo".to_owned()),
base: Base::Sc(Ident("bar".to_owned()))
base: Base::Sc(Ident("bar".to_owned())),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1098,6 +1108,8 @@ fn parse_remove() {
res,
Statement::Remove(RemoveStatement::Scope(RemoveScopeStatement {
name: Ident("foo".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1106,6 +1118,8 @@ fn parse_remove() {
res,
Statement::Remove(RemoveStatement::Param(RemoveParamStatement {
name: Ident("foo".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1125,6 +1139,8 @@ fn parse_remove() {
Statement::Remove(RemoveStatement::Event(RemoveEventStatement {
name: Ident("foo".to_owned()),
what: Ident("bar".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1138,6 +1154,8 @@ fn parse_remove() {
Part::Index(Number::Int(10))
]),
what: Ident("bar".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1147,6 +1165,8 @@ fn parse_remove() {
Statement::Remove(RemoveStatement::Index(RemoveIndexStatement {
name: Ident("foo".to_owned()),
what: Ident("bar".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1155,6 +1175,8 @@ fn parse_remove() {
res,
Statement::Remove(RemoveStatement::Analyzer(RemoveAnalyzerStatement {
name: Ident("foo".to_owned()),
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
@ -1164,6 +1186,8 @@ fn parse_remove() {
Statement::Remove(RemoveStatement::User(RemoveUserStatement {
name: Ident("foo".to_owned()),
base: Base::Db,
#[cfg(feature = "sql2")]
if_exists: false,
}))
);
}

View file

@ -589,6 +589,7 @@ fn statements() -> Vec<Statement> {
}),
Statement::Remove(RemoveStatement::Function(RemoveFunctionStatement {
name: Ident("foo::bar".to_owned()),
if_exists: false,
})),
Statement::Remove(RemoveStatement::Field(RemoveFieldStatement {
name: Idiom(vec![
@ -597,6 +598,7 @@ fn statements() -> Vec<Statement> {
Part::Index(Number::Int(10)),
]),
what: Ident("bar".to_owned()),
if_exists: false,
})),
Statement::Update(UpdateStatement {
only: true,

View file

@ -149,9 +149,383 @@ async fn should_error_when_remove_and_table_does_not_exist() -> Result<(), Error
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_if_exists() -> Result<(), Error> {
async fn should_not_error_when_remove_table_if_exists() -> Result<(), Error> {
let sql = "
REMOVE TABLE foo IF EXISTS;
REMOVE TABLE IF EXISTS foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_analyzer_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE ANALYZER foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::AzNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_analyzer_if_exists() -> Result<(), Error> {
let sql = "
REMOVE ANALYZER IF EXISTS foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_database_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE DATABASE foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::DbNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_database_if_exists() -> Result<(), Error> {
let sql = "
REMOVE DATABASE IF EXISTS foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_event_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE EVENT foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::EvNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_event_if_exists() -> Result<(), Error> {
let sql = "
REMOVE EVENT IF EXISTS foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_field_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE FIELD foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::FdNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_field_if_exists() -> Result<(), Error> {
let sql = "
REMOVE FIELD IF EXISTS foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_function_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE FUNCTION fn::foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::FcNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_function_if_exists() -> Result<(), Error> {
let sql = "
REMOVE FUNCTION IF EXISTS fn::foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_index_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE INDEX foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::IxNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_index_if_exists() -> Result<(), Error> {
let sql = "
REMOVE INDEX IF EXISTS foo ON bar;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_namespace_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE NAMESPACE foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::NsNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_namespace_if_exists() -> Result<(), Error> {
let sql = "
REMOVE NAMESPACE IF EXISTS foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_param_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE PARAM $foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::PaNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_param_if_exists() -> Result<(), Error> {
let sql = "
REMOVE PARAM IF EXISTS $foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_scope_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE SCOPE foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::ScNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_scope_if_exists() -> Result<(), Error> {
let sql = "
REMOVE SCOPE IF EXISTS foo;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_token_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE TOKEN foo ON NAMESPACE;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::NtNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_token_if_exists() -> Result<(), Error> {
let sql = "
REMOVE TOKEN IF EXISTS foo ON NAMESPACE;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result?;
assert_eq!(tmp, Value::None);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_error_when_remove_and_user_does_not_exist() -> Result<(), Error> {
let sql = "
REMOVE USER foo ON ROOT;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
//
let tmp = res.remove(0).result.unwrap_err();
assert!(matches!(tmp, Error::UserRootNotFound { .. }),);
Ok(())
}
#[tokio::test]
#[cfg(feature = "sql2")]
async fn should_not_error_when_remove_user_if_exists() -> Result<(), Error> {
let sql = "
REMOVE USER IF EXISTS foo ON ROOT;
";
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");