Implement INFO sql statements

This commit is contained in:
Tobie Morgan Hitchcock 2022-04-06 12:06:33 +01:00
parent cf20cd4396
commit 2e2756d9e8
2 changed files with 172 additions and 32 deletions

View file

@ -36,14 +36,14 @@ pub fn new(ns: &str, db: &str) -> Db {
} }
pub fn prefix(ns: &str) -> Vec<u8> { pub fn prefix(ns: &str) -> Vec<u8> {
let mut k = super::ns::new(ns).encode().unwrap(); let mut k = super::namespace::new(ns).encode().unwrap();
k.extend_from_slice(&[0x21, 0x64, 0x02, 0x00]); k.extend_from_slice(&[0x21, 0x64, 0x62, 0x00]);
k k
} }
pub fn suffix(ns: &str) -> Vec<u8> { pub fn suffix(ns: &str) -> Vec<u8> {
let mut k = super::ns::new(ns).encode().unwrap(); let mut k = super::namespace::new(ns).encode().unwrap();
k.extend_from_slice(&[0x21, 0x64, 0x02, 0xff]); k.extend_from_slice(&[0x21, 0x64, 0x62, 0xff]);
k k
} }

View file

@ -6,6 +6,7 @@ use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::ident::ident_raw; use crate::sql::ident::ident_raw;
use crate::sql::object::Object;
use crate::sql::value::Value; use crate::sql::value::Value;
use derive::Store; use derive::Store;
use nom::branch::alt; use nom::branch::alt;
@ -15,10 +16,11 @@ use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store)]
pub enum InfoStatement { pub enum InfoStatement {
Namespace, Kv,
Database, Ns,
Scope(String), Db,
Table(String), Sc(String),
Tb(String),
} }
impl InfoStatement { impl InfoStatement {
@ -26,28 +28,161 @@ impl InfoStatement {
&self, &self,
_ctx: &Runtime, _ctx: &Runtime,
opt: &Options, opt: &Options,
_txn: &Transaction, txn: &Transaction,
_doc: Option<&Value>, _doc: Option<&Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Allowed to run? // Allowed to run?
match self { match self {
InfoStatement::Namespace => opt.check(Level::Ns)?, InfoStatement::Kv => {
InfoStatement::Database => opt.check(Level::Db)?, // Allowed to run?
InfoStatement::Scope(_) => opt.check(Level::Db)?, opt.check(Level::Kv)?;
InfoStatement::Table(_) => opt.check(Level::Db)?, // Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Create the result set
let mut res = Object::default();
// Process the statement
let mut tmp = Object::default();
for v in run.all_ns().await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("ns", tmp.into());
// Ok all good
Value::from(res).ok()
}
InfoStatement::Ns => {
// Allowed to run?
opt.check(Level::Ns)?;
// Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Create the result set
let mut res = Object::default();
// Process the databases
let mut tmp = Object::default();
for v in run.all_db(opt.ns()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("db", tmp.into());
// Process the tokens
let mut tmp = Object::default();
for v in run.all_nt(opt.ns()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("nt", tmp.into());
// Process the logins
let mut tmp = Object::default();
for v in run.all_nl(opt.ns()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("nl", tmp.into());
// Ok all good
Value::from(res).ok()
}
InfoStatement::Db => {
// Allowed to run?
opt.check(Level::Db)?;
// Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Create the result set
let mut res = Object::default();
// Process the tables
let mut tmp = Object::default();
for v in run.all_tb(opt.ns(), opt.db()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("tb", tmp.into());
// Process the scopes
let mut tmp = Object::default();
for v in run.all_sc(opt.ns(), opt.db()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("sc", tmp.into());
// Process the tokens
let mut tmp = Object::default();
for v in run.all_nt(opt.ns()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("nt", tmp.into());
// Process the logins
let mut tmp = Object::default();
for v in run.all_nl(opt.ns()).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("nl", tmp.into());
// Ok all good
Value::from(res).ok()
}
InfoStatement::Sc(sc) => {
// Allowed to run?
opt.check(Level::Db)?;
// Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Create the result set
let mut res = Object::default();
// Process the tokens
let mut tmp = Object::default();
for v in run.all_st(opt.ns(), opt.db(), sc).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("st", tmp.into());
// Ok all good
Value::from(res).ok()
}
InfoStatement::Tb(tb) => {
// Allowed to run?
opt.check(Level::Db)?;
// Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Create the result set
let mut res = Object::default();
// Process the events
let mut tmp = Object::default();
for v in run.all_ev(opt.ns(), opt.db(), tb).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("ev", tmp.into());
// Process the fields
let mut tmp = Object::default();
for v in run.all_fd(opt.ns(), opt.db(), tb).await? {
tmp.insert(&v.name.to_string(), v.to_string().into());
}
res.insert("fd", tmp.into());
// Process the indexs
let mut tmp = Object::default();
for v in run.all_ix(opt.ns(), opt.db(), tb).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("ix", tmp.into());
// Process the tables
let mut tmp = Object::default();
for v in run.all_ft(opt.ns(), opt.db(), tb).await? {
tmp.insert(&v.name, v.to_string().into());
}
res.insert("ft", tmp.into());
// Ok all good
Value::from(res).ok()
}
} }
// Continue
todo!()
} }
} }
impl fmt::Display for InfoStatement { impl fmt::Display for InfoStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
InfoStatement::Namespace => write!(f, "INFO FOR NAMESPACE"), InfoStatement::Kv => write!(f, "INFO FOR KV"),
InfoStatement::Database => write!(f, "INFO FOR DATABASE"), InfoStatement::Ns => write!(f, "INFO FOR NAMESPACE"),
InfoStatement::Scope(ref s) => write!(f, "INFO FOR SCOPE {}", s), InfoStatement::Db => write!(f, "INFO FOR DATABASE"),
InfoStatement::Table(ref t) => write!(f, "INFO FOR TABLE {}", t), InfoStatement::Sc(ref s) => write!(f, "INFO FOR SCOPE {}", s),
InfoStatement::Tb(ref t) => write!(f, "INFO FOR TABLE {}", t),
} }
} }
} }
@ -57,31 +192,36 @@ pub fn info(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
let (i, _) = tag_no_case("FOR")(i)?; let (i, _) = tag_no_case("FOR")(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
alt((namespace, database, scope, table))(i) alt((kv, ns, db, sc, tb))(i)
} }
fn namespace(i: &str) -> IResult<&str, InfoStatement> { fn kv(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = tag_no_case("KV")(i)?;
Ok((i, InfoStatement::Kv))
}
fn ns(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = alt((tag_no_case("NAMESPACE"), tag_no_case("NS")))(i)?; let (i, _) = alt((tag_no_case("NAMESPACE"), tag_no_case("NS")))(i)?;
Ok((i, InfoStatement::Namespace)) Ok((i, InfoStatement::Ns))
} }
fn database(i: &str) -> IResult<&str, InfoStatement> { fn db(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = alt((tag_no_case("DATABASE"), tag_no_case("DB")))(i)?; let (i, _) = alt((tag_no_case("DATABASE"), tag_no_case("DB")))(i)?;
Ok((i, InfoStatement::Database)) Ok((i, InfoStatement::Db))
} }
fn scope(i: &str) -> IResult<&str, InfoStatement> { fn sc(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = alt((tag_no_case("SCOPE"), tag_no_case("SC")))(i)?; let (i, _) = alt((tag_no_case("SCOPE"), tag_no_case("SC")))(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
let (i, scope) = ident_raw(i)?; let (i, scope) = ident_raw(i)?;
Ok((i, InfoStatement::Scope(scope))) Ok((i, InfoStatement::Sc(scope)))
} }
fn table(i: &str) -> IResult<&str, InfoStatement> { fn tb(i: &str) -> IResult<&str, InfoStatement> {
let (i, _) = alt((tag_no_case("TABLE"), tag_no_case("TB")))(i)?; let (i, _) = alt((tag_no_case("TABLE"), tag_no_case("TB")))(i)?;
let (i, _) = shouldbespace(i)?; let (i, _) = shouldbespace(i)?;
let (i, table) = ident_raw(i)?; let (i, table) = ident_raw(i)?;
Ok((i, InfoStatement::Table(table))) Ok((i, InfoStatement::Tb(table)))
} }
#[cfg(test)] #[cfg(test)]
@ -95,7 +235,7 @@ mod tests {
let res = info(sql); let res = info(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!(out, InfoStatement::Namespace); assert_eq!(out, InfoStatement::Ns);
assert_eq!("INFO FOR NAMESPACE", format!("{}", out)); assert_eq!("INFO FOR NAMESPACE", format!("{}", out));
} }
@ -105,7 +245,7 @@ mod tests {
let res = info(sql); let res = info(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!(out, InfoStatement::Database); assert_eq!(out, InfoStatement::Db);
assert_eq!("INFO FOR DATABASE", format!("{}", out)); assert_eq!("INFO FOR DATABASE", format!("{}", out));
} }
@ -115,7 +255,7 @@ mod tests {
let res = info(sql); let res = info(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!(out, InfoStatement::Scope(String::from("test"))); assert_eq!(out, InfoStatement::Sc(String::from("test")));
assert_eq!("INFO FOR SCOPE test", format!("{}", out)); assert_eq!("INFO FOR SCOPE test", format!("{}", out));
} }
@ -125,7 +265,7 @@ mod tests {
let res = info(sql); let res = info(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!(out, InfoStatement::Table(String::from("test"))); assert_eq!(out, InfoStatement::Tb(String::from("test")));
assert_eq!("INFO FOR TABLE test", format!("{}", out)); assert_eq!("INFO FOR TABLE test", format!("{}", out));
} }
} }