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, 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 /// The requested function does not exist
#[error("The function 'fn::{value}' does not exist")] #[error("The function 'fn::{value}' does not exist")]
FcNotFound { FcNotFound {
value: String, 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 /// The requested model does not exist
#[error("The model 'ml::{value}' does not exist")] #[error("The model 'ml::{value}' does not exist")]
MlNotFound { MlNotFound {

View file

@ -1908,6 +1908,36 @@ impl Transaction {
Ok(val.into()) 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. /// Retrieve a specific scope definition.
pub async fn get_sc( pub async fn get_sc(
&mut self, &mut self,
@ -1983,6 +2013,60 @@ impl Transaction {
Ok(val.into()) 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. /// Add a namespace with a default configuration, only if we are in dynamic mode.
pub async fn add_ns( pub async fn add_ns(
&mut self, &mut self,

View file

@ -39,6 +39,6 @@ impl RemoveParamStatement {
impl Display for RemoveParamStatement { impl Display for RemoveParamStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveAnalyzerStatement { pub struct RemoveAnalyzerStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveAnalyzerStatement { impl RemoveAnalyzerStatement {
@ -22,23 +24,39 @@ impl RemoveAnalyzerStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Analyzer, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let az = run.get_db_analyzer(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// TODO Check that the analyzer is not used in any schema // TODO Check that the analyzer is not used in any schema
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::AzNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveAnalyzerStatement { impl Display for RemoveAnalyzerStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveDatabaseStatement { pub struct RemoveDatabaseStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveDatabaseStatement { impl RemoveDatabaseStatement {
@ -23,25 +25,41 @@ impl RemoveDatabaseStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?; opt.is_allowed(Action::Edit, ResourceKind::Database, &Base::Ns)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let db = run.get_db(opt.ns(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Delete the resource data // 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?; run.delp(key, u32::MAX).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::DbNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveDatabaseStatement { impl Display for RemoveDatabaseStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveEventStatement { pub struct RemoveEventStatement {
pub name: Ident, pub name: Ident,
pub what: Ident, pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveEventStatement { impl RemoveEventStatement {
@ -24,25 +26,41 @@ impl RemoveEventStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Event, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_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 // 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?; run.del(key).await?;
// Clear the cache // 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?; run.clr(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::EvNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveEventStatement { impl Display for RemoveEventStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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}; use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveFieldStatement { pub struct RemoveFieldStatement {
pub name: Idiom, pub name: Idiom,
pub what: Ident, pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveFieldStatement { impl RemoveFieldStatement {
@ -24,15 +26,19 @@ impl RemoveFieldStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_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 // Delete the definition
let fd = self.name.to_string(); let fd_name = fd.name.to_string();
let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd); let key = crate::key::table::fd::new(opt.ns(), opt.db(), &self.what, &fd_name);
run.del(key).await?; run.del(key).await?;
// Clear the cache // Clear the cache
let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what); let key = crate::key::table::fd::prefix(opt.ns(), opt.db(), &self.what);
@ -40,10 +46,23 @@ impl RemoveFieldStatement {
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::FdNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveFieldStatement { impl Display for RemoveFieldStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveFunctionStatement { pub struct RemoveFunctionStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveFunctionStatement { impl RemoveFunctionStatement {
@ -23,23 +25,39 @@ impl RemoveFunctionStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let fc = run.get_db_function(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::FcNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveFunctionStatement { impl Display for RemoveFunctionStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Bypass ident display since we don't want backticks arround the ident. // 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}; use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveIndexStatement { pub struct RemoveIndexStatement {
pub name: Ident, pub name: Ident,
pub what: Ident, pub what: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveIndexStatement { impl RemoveIndexStatement {
@ -24,6 +26,7 @@ impl RemoveIndexStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Index, &Base::Db)?;
// Claim transaction // Claim transaction
@ -44,10 +47,23 @@ impl RemoveIndexStatement {
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::IxNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveIndexStatement { impl Display for RemoveIndexStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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}; use std::fmt::{self, Display};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveModelStatement { pub struct RemoveModelStatement {
pub name: Ident, pub name: Ident,
pub version: String, pub version: String,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveModelStatement { impl RemoveModelStatement {
@ -24,6 +26,7 @@ impl RemoveModelStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?;
// Claim transaction // Claim transaction
@ -38,11 +41,24 @@ impl RemoveModelStatement {
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::MlNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveModelStatement { impl Display for RemoveModelStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Bypass ident display since we don't want backticks arround the ident. // 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveNamespaceStatement { pub struct RemoveNamespaceStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveNamespaceStatement { impl RemoveNamespaceStatement {
@ -23,6 +25,7 @@ impl RemoveNamespaceStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?; opt.is_allowed(Action::Edit, ResourceKind::Namespace, &Base::Root)?;
// Claim transaction // Claim transaction
@ -30,19 +33,34 @@ impl RemoveNamespaceStatement {
ctx.get_index_stores().namespace_removed(opt, &mut run).await?; ctx.get_index_stores().namespace_removed(opt, &mut run).await?;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let ns = run.get_ns(&self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Delete the resource data // 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?; run.delp(key, u32::MAX).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::NsNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveNamespaceStatement { impl Display for RemoveNamespaceStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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}; use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveParamStatement { pub struct RemoveParamStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveParamStatement { impl RemoveParamStatement {
@ -23,22 +25,38 @@ impl RemoveParamStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let pa = run.get_db_param(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::PaNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveParamStatement { impl Display for RemoveParamStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveScopeStatement { pub struct RemoveScopeStatement {
pub name: Ident, pub name: Ident,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveScopeStatement { impl RemoveScopeStatement {
@ -23,25 +25,41 @@ impl RemoveScopeStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Scope, &Base::Db)?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let sc = run.get_sc(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Remove the resource data // 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?; run.delp(key, u32::MAX).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
.await
{
Err(Error::ScNotFound {
..
}) if self.if_exists => Ok(Value::None),
v => v,
}
}
} }
impl Display for RemoveScopeStatement { impl Display for RemoveScopeStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?; opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
// Claim transaction // Claim transaction
@ -35,8 +36,7 @@ impl RemoveTableStatement {
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the defined table // Get the defined table
match run.get_tb(opt.ns(), opt.db(), &self.name).await { let tb = run.get_tb(opt.ns(), opt.db(), &self.name).await?;
Ok(tb) => {
// Delete the definition // Delete the definition
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name); let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);
run.del(key).await?; run.del(key).await?;
@ -55,23 +55,23 @@ impl RemoveTableStatement {
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
Err(err) => { .await
if matches!(err, Error::TbNotFound { .. }) && self.if_exists { {
Ok(Value::None) Err(Error::TbNotFound {
} else { ..
Err(err) }) if self.if_exists => Ok(Value::None),
} v => v,
}
} }
} }
} }
impl Display for RemoveTableStatement { impl Display for RemoveTableStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "REMOVE TABLE {}", self.name)?; write!(f, "REMOVE TABLE")?;
if self.if_exists { if self.if_exists {
write!(f, " IF EXISTS")? write!(f, " IF EXISTS")?
} }
write!(f, " {}", self.name)?;
Ok(()) Ok(())
} }
} }

View file

@ -10,10 +10,12 @@ use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
pub struct RemoveTokenStatement { pub struct RemoveTokenStatement {
pub name: Ident, pub name: Ident,
pub base: Base, pub base: Base,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveTokenStatement { impl RemoveTokenStatement {
@ -24,6 +26,7 @@ impl RemoveTokenStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
@ -33,8 +36,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let tk = run.get_ns_token(opt.ns(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -44,8 +49,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let tk = run.get_db_token(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -55,8 +62,10 @@ impl RemoveTokenStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let tk = run.get_sc_token(opt.ns(), opt.db(), sc, &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -64,10 +73,32 @@ impl RemoveTokenStatement {
_ => Err(Error::InvalidLevel(self.base.to_string())), _ => 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 { impl Display for RemoveTokenStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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}; use std::fmt::{self, Display, Formatter};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 1)] #[revisioned(revision = 2)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RemoveUserStatement { pub struct RemoveUserStatement {
pub name: Ident, pub name: Ident,
pub base: Base, pub base: Base,
#[revision(start = 2)]
pub if_exists: bool,
} }
impl RemoveUserStatement { impl RemoveUserStatement {
@ -24,6 +26,7 @@ impl RemoveUserStatement {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match async {
// Allowed to run? // Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?; opt.is_allowed(Action::Edit, ResourceKind::Actor, &self.base)?;
@ -33,8 +36,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let us = run.get_root_user(&self.name).await?;
// Process the statement // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -44,8 +49,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let us = run.get_ns_user(opt.ns(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -55,8 +62,10 @@ impl RemoveUserStatement {
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Clear the cache // Clear the cache
run.clear_cache(); run.clear_cache();
// Get the definition
let us = run.get_db_user(opt.ns(), opt.db(), &self.name).await?;
// Delete the definition // 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?; run.del(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
@ -64,10 +73,32 @@ impl RemoveUserStatement {
_ => Err(Error::InvalidLevel(self.base.to_string())), _ => 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 { impl Display for RemoveUserStatement {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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)] #[derive(Default)]
pub struct SerializeRemoveAnalyzerStatement { pub struct SerializeRemoveAnalyzerStatement {
name: Ident, name: Ident,
if_exists: bool,
} }
impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement { impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
@ -50,6 +51,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
"name" => { "name" => {
self.name = Ident(value.serialize(ser::string::Serializer.wrap())?); self.name = Ident(value.serialize(ser::string::Serializer.wrap())?);
} }
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?
}
key => { key => {
return Err(Error::custom(format!( return Err(Error::custom(format!(
"unexpected field `RemoveAnalyzerStatement::{key}`" "unexpected field `RemoveAnalyzerStatement::{key}`"
@ -62,6 +66,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveAnalyzerStatement {
fn end(self) -> Result<Self::Ok, Error> { fn end(self) -> Result<Self::Ok, Error> {
Ok(RemoveAnalyzerStatement { Ok(RemoveAnalyzerStatement {
name: self.name, name: self.name,
if_exists: self.if_exists,
}) })
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -38,6 +38,7 @@ impl ser::Serializer for Serializer {
pub struct SerializeRemoveUserStatement { pub struct SerializeRemoveUserStatement {
name: Ident, name: Ident,
base: Base, base: Base,
if_exists: bool,
} }
impl serde::ser::SerializeStruct for SerializeRemoveUserStatement { impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
@ -55,6 +56,9 @@ impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
"base" => { "base" => {
self.base = value.serialize(ser::base::Serializer.wrap())?; self.base = value.serialize(ser::base::Serializer.wrap())?;
} }
"if_exists" => {
self.if_exists = value.serialize(ser::primitive::bool::Serializer.wrap())?;
}
key => { key => {
return Err(Error::custom(format!( return Err(Error::custom(format!(
"unexpected field `RemoveUserStatement::{key}`" "unexpected field `RemoveUserStatement::{key}`"
@ -68,6 +72,7 @@ impl serde::ser::SerializeStruct for SerializeRemoveUserStatement {
Ok(RemoveUserStatement { Ok(RemoveUserStatement {
name: self.name, name: self.name,
base: self.base, 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> { pub fn analyzer(i: &str) -> IResult<&str, RemoveAnalyzerStatement> {
let (i, _) = tag_no_case("ANALYZER")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
Ok(( Ok((
i, i,
RemoveAnalyzerStatement { RemoveAnalyzerStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> { pub fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
let (i, _) = alt((tag_no_case("DB"), tag_no_case("DATABASE")))(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
Ok(( Ok((
i, i,
RemoveDatabaseStatement { RemoveDatabaseStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> { pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
let (i, _) = tag_no_case("EVENT")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
@ -77,12 +99,20 @@ pub fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
RemoveEventStatement { RemoveEventStatement {
name, name,
what, what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> { pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
let (i, _) = tag_no_case("FIELD")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(idiom::local)(i)?; let (i, name) = cut(idiom::local)(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
@ -95,12 +125,20 @@ pub fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
RemoveFieldStatement { RemoveFieldStatement {
name, name,
what, what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> { pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
let (i, _) = tag_no_case("FUNCTION")(i)?; 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, _) = shouldbespace(i)?;
let (i, _) = tag("fn::")(i)?; let (i, _) = tag("fn::")(i)?;
let (i, name) = ident_path(i)?; let (i, name) = ident_path(i)?;
@ -115,12 +153,20 @@ pub fn function(i: &str) -> IResult<&str, RemoveFunctionStatement> {
i, i,
RemoveFunctionStatement { RemoveFunctionStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> { pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
let (i, _) = tag_no_case("INDEX")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
@ -133,24 +179,40 @@ pub fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
RemoveIndexStatement { RemoveIndexStatement {
name, name,
what, what,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> { pub fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
let (i, _) = alt((tag_no_case("NS"), tag_no_case("NAMESPACE")))(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
Ok(( Ok((
i, i,
RemoveNamespaceStatement { RemoveNamespaceStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> { pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
let (i, _) = tag_no_case("PARAM")(i)?; 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, _) = shouldbespace(i)?;
let (i, _) = cut(char('$'))(i)?; let (i, _) = cut(char('$'))(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
@ -158,32 +220,42 @@ pub fn param(i: &str) -> IResult<&str, RemoveParamStatement> {
i, i,
RemoveParamStatement { RemoveParamStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> { pub fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
let (i, _) = tag_no_case("SCOPE")(i)?; 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")] #[cfg(feature = "sql2")]
let (i, if_exists) = opt(tuple(( let (i, if_exists) = opt(tuple((
shouldbespace, shouldbespace,
tag_no_case("IF"), tag_no_case("IF"),
cut(tuple((shouldbespace, tag_no_case("EXISTS")))), cut(tuple((shouldbespace, tag_no_case("EXISTS")))),
)))(i)?; )))(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(( Ok((
i, i,
RemoveTableStatement { RemoveTableStatement {
@ -196,6 +268,12 @@ pub fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> { pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
let (i, _) = tag_no_case("TOKEN")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
@ -207,12 +285,20 @@ pub fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
RemoveTokenStatement { RemoveTokenStatement {
name, name,
base, base,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> { pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
let (i, _) = tag_no_case("USER")(i)?; 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, _) = shouldbespace(i)?;
let (i, name) = cut(ident)(i)?; let (i, name) = cut(ident)(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
@ -224,6 +310,8 @@ pub fn user(i: &str) -> IResult<&str, RemoveUserStatement> {
RemoveUserStatement { RemoveUserStatement {
name, name,
base, base,
#[cfg(feature = "sql2")]
if_exists: if_exists.is_some(),
}, },
)) ))
} }
@ -238,9 +326,149 @@ mod tests {
fn check_remove_serialize() { fn check_remove_serialize() {
let stm = RemoveStatement::Namespace(RemoveNamespaceStatement { let stm = RemoveStatement::Namespace(RemoveNamespaceStatement {
name: Ident::from("test"), name: Ident::from("test"),
#[cfg(feature = "sql2")]
if_exists: false,
}); });
let enc: Vec<u8> = stm.try_into().unwrap(); let enc: Vec<u8> = stm.try_into().unwrap();
#[cfg(not(feature = "sql2"))]
assert_eq!(9, enc.len()); 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] #[test]
@ -251,6 +479,116 @@ mod tests {
assert_eq!("REMOVE FUNCTION fn::foo::bar::baz::bac", format!("{}", out)) 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] #[test]
fn remove_table() { fn remove_table() {
let sql = "REMOVE TABLE test"; let sql = "REMOVE TABLE test";
@ -262,16 +600,70 @@ mod tests {
#[test] #[test]
#[cfg(feature = "sql2")] #[cfg(feature = "sql2")]
fn remove_table_if_exists() { fn remove_table_if_exists() {
let sql = "REMOVE TABLE test IF EXISTS"; let sql = "REMOVE TABLE IF EXISTS test";
let res = remove(sql); let res = remove(sql);
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!("REMOVE TABLE test IF EXISTS", format!("{}", out)) assert_eq!("REMOVE TABLE IF EXISTS test", format!("{}", out))
} }
#[test] #[test]
#[cfg(feature = "sql2")] #[cfg(feature = "sql2")]
fn remove_table_if() { 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); let res = remove(sql);
assert!(res.is_err()); assert!(res.is_err());
} }

View file

@ -21,50 +21,6 @@ impl Parser<'_> {
pub fn parse_remove_stmt(&mut self) -> ParseResult<RemoveStatement> { pub fn parse_remove_stmt(&mut self) -> ParseResult<RemoveStatement> {
let res = match self.next().kind { let res = match self.next().kind {
t!("NAMESPACE") => { 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")] #[cfg(feature = "sql2")]
let if_exists = if self.eat(t!("IF")) { let if_exists = if self.eat(t!("IF")) {
expected!(self, t!("EXISTS")); expected!(self, t!("EXISTS"));
@ -72,6 +28,110 @@ impl Parser<'_> {
} else { } else {
false 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 { RemoveStatement::Table(crate::sql::statements::RemoveTableStatement {
name, name,
@ -80,48 +140,98 @@ impl Parser<'_> {
}) })
} }
t!("EVENT") => { 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()?; let name = self.next_token_value()?;
expected!(self, t!("ON")); expected!(self, t!("ON"));
self.eat(t!("TABLE")); self.eat(t!("TABLE"));
let table = self.next_token_value()?; let table = self.next_token_value()?;
RemoveStatement::Event(RemoveEventStatement { RemoveStatement::Event(RemoveEventStatement {
name, name,
what: table, what: table,
#[cfg(feature = "sql2")]
if_exists,
}) })
} }
t!("FIELD") => { 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()?; let idiom = self.parse_local_idiom()?;
expected!(self, t!("ON")); expected!(self, t!("ON"));
self.eat(t!("TABLE")); self.eat(t!("TABLE"));
let table = self.next_token_value()?; let table = self.next_token_value()?;
RemoveStatement::Field(RemoveFieldStatement { RemoveStatement::Field(RemoveFieldStatement {
name: idiom, name: idiom,
what: table, what: table,
#[cfg(feature = "sql2")]
if_exists,
}) })
} }
t!("INDEX") => { 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()?; let name = self.next_token_value()?;
expected!(self, t!("ON")); expected!(self, t!("ON"));
self.eat(t!("TABLE")); self.eat(t!("TABLE"));
let what = self.next_token_value()?; let what = self.next_token_value()?;
RemoveStatement::Index(RemoveIndexStatement { RemoveStatement::Index(RemoveIndexStatement {
name, name,
what, what,
#[cfg(feature = "sql2")]
if_exists,
}) })
} }
t!("ANALYZER") => { 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()?; let name = self.next_token_value()?;
RemoveStatement::Analyzer(RemoveAnalyzerStatement { RemoveStatement::Analyzer(RemoveAnalyzerStatement {
name, name,
#[cfg(feature = "sql2")]
if_exists,
}) })
} }
t!("USER") => { 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()?; let name = self.next_token_value()?;
expected!(self, t!("ON")); expected!(self, t!("ON"));
let base = self.parse_base(false)?; let base = self.parse_base(false)?;
RemoveStatement::User(RemoveUserStatement { RemoveStatement::User(RemoveUserStatement {
name, name,
base, base,
#[cfg(feature = "sql2")]
if_exists,
}) })
} }
x => unexpected!(self, x, "a remove statement keyword"), x => unexpected!(self, x, "a remove statement keyword"),

View file

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

View file

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

View file

@ -149,9 +149,383 @@ async fn should_error_when_remove_and_table_does_not_exist() -> Result<(), Error
#[tokio::test] #[tokio::test]
#[cfg(feature = "sql2")] #[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 = " 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 dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test"); let ses = Session::owner().with_ns("test").with_db("test");