Return error when selecting from non-existent table in strict mode

Closes #13
This commit is contained in:
Tobie Morgan Hitchcock 2022-08-08 22:41:33 +01:00
parent bac8aa31a3
commit af45b33fa0
4 changed files with 63 additions and 5 deletions

View file

@ -30,6 +30,8 @@ impl Iterable {
chn.send((None, val)).await?;
}
Iterable::Thing(v) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -42,6 +44,8 @@ impl Iterable {
chn.send((Some(v), val)).await?;
}
Iterable::Mergeable(v, o) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -56,6 +60,8 @@ impl Iterable {
chn.send((Some(v), val)).await?;
}
Iterable::Relatable(f, v, w) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -70,6 +76,8 @@ impl Iterable {
chn.send((Some(v), val)).await?;
}
Iterable::Table(v) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
// Prepare the start and end keys
let beg = thing::prefix(opt.ns(), opt.db(), &v);
let end = thing::suffix(opt.ns(), opt.db(), &v);

View file

@ -30,6 +30,8 @@ impl Iterable {
ite.process(ctx, opt, txn, stm, None, val).await;
}
Iterable::Thing(v) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -42,6 +44,8 @@ impl Iterable {
ite.process(ctx, opt, txn, stm, Some(v), val).await;
}
Iterable::Mergeable(v, o) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -56,6 +60,8 @@ impl Iterable {
ite.process(ctx, opt, txn, stm, Some(v), val).await;
}
Iterable::Relatable(f, v, w) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let val = txn.clone().lock().await.get(key).await?;
@ -70,6 +76,8 @@ impl Iterable {
ite.process(ctx, opt, txn, stm, Some(v), val).await;
}
Iterable::Table(v) => {
// Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
// Prepare the start and end keys
let beg = thing::prefix(opt.ns(), opt.db(), &v);
let end = thing::suffix(opt.ns(), opt.db(), &v);

View file

@ -1134,6 +1134,26 @@ impl Transaction {
Ok(v) => Ok(v),
}
}
/// Retrieve and cache a specific table definition.
pub async fn check_ns_db_tb(
&mut self,
ns: &str,
db: &str,
tb: &str,
strict: bool,
) -> Result<(), Error> {
match strict {
// Strict mode is disabled
false => Ok(()),
// Strict mode is enabled
true => {
self.get_and_cache_ns(ns).await?;
self.get_and_cache_db(ns, db).await?;
self.get_and_cache_tb(ns, db, tb).await?;
Ok(())
}
}
}
/// Writes the full database contents as binary SQL.
pub async fn export(&mut self, ns: &str, db: &str, chn: Sender<Vec<u8>>) -> Result<(), Error> {
// Output OPTIONS

View file

@ -13,11 +13,15 @@ async fn strict_mode_no_namespace() -> Result<(), Error> {
DEFINE TABLE test;
DEFINE FIELD extra ON test VALUE true;
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
assert_eq!(res.len(), 4);
assert_eq!(res.len(), 5);
//
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::NsNotFound)));
//
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::NsNotFound)));
@ -42,11 +46,12 @@ async fn strict_mode_no_database() -> Result<(), Error> {
DEFINE TABLE test;
DEFINE FIELD extra ON test VALUE true;
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
assert_eq!(res.len(), 4);
assert_eq!(res.len(), 5);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
@ -60,6 +65,9 @@ async fn strict_mode_no_database() -> Result<(), Error> {
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::DbNotFound)));
//
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::DbNotFound)));
//
Ok(())
}
@ -71,11 +79,12 @@ async fn strict_mode_no_table() -> Result<(), Error> {
-- DEFINE TABLE test;
DEFINE FIELD extra ON test VALUE true;
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
assert_eq!(res.len(), 4);
assert_eq!(res.len(), 5);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
@ -89,6 +98,9 @@ async fn strict_mode_no_table() -> Result<(), Error> {
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::TbNotFound)));
//
let tmp = res.remove(0).result;
assert!(matches!(tmp.err(), Some(Error::TbNotFound)));
//
Ok(())
}
@ -100,11 +112,12 @@ async fn strict_mode_all_ok() -> Result<(), Error> {
DEFINE TABLE test;
DEFINE FIELD extra ON test VALUE true;
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
assert_eq!(res.len(), 5);
assert_eq!(res.len(), 6);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
@ -122,6 +135,10 @@ async fn strict_mode_all_ok() -> Result<(), Error> {
let val = Value::parse("[{ id: test:tester, extra: true }]");
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("[{ id: test:tester, extra: true }]");
assert_eq!(tmp, val);
//
Ok(())
}
@ -130,6 +147,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
let sql = "
DEFINE FIELD extra ON test VALUE true;
CREATE test:tester;
SELECT * FROM test;
INFO FOR KV;
INFO FOR NS;
INFO FOR DB;
@ -138,7 +156,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
assert_eq!(res.len(), 6);
assert_eq!(res.len(), 7);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
@ -148,6 +166,10 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("[{ id: test:tester, extra: true }]");
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"{
ns: { test: 'DEFINE NAMESPACE test' },