Return error when selecting from non-existent table in strict mode
Closes #13
This commit is contained in:
parent
bac8aa31a3
commit
af45b33fa0
4 changed files with 63 additions and 5 deletions
|
@ -30,6 +30,8 @@ impl Iterable {
|
||||||
chn.send((None, val)).await?;
|
chn.send((None, val)).await?;
|
||||||
}
|
}
|
||||||
Iterable::Thing(v) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
let val = txn.clone().lock().await.get(key).await?;
|
||||||
|
@ -42,6 +44,8 @@ impl Iterable {
|
||||||
chn.send((Some(v), val)).await?;
|
chn.send((Some(v), val)).await?;
|
||||||
}
|
}
|
||||||
Iterable::Mergeable(v, o) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
let val = txn.clone().lock().await.get(key).await?;
|
||||||
|
@ -56,6 +60,8 @@ impl Iterable {
|
||||||
chn.send((Some(v), val)).await?;
|
chn.send((Some(v), val)).await?;
|
||||||
}
|
}
|
||||||
Iterable::Relatable(f, v, w) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
let val = txn.clone().lock().await.get(key).await?;
|
||||||
|
@ -70,6 +76,8 @@ impl Iterable {
|
||||||
chn.send((Some(v), val)).await?;
|
chn.send((Some(v), val)).await?;
|
||||||
}
|
}
|
||||||
Iterable::Table(v) => {
|
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
|
// Prepare the start and end keys
|
||||||
let beg = thing::prefix(opt.ns(), opt.db(), &v);
|
let beg = thing::prefix(opt.ns(), opt.db(), &v);
|
||||||
let end = thing::suffix(opt.ns(), opt.db(), &v);
|
let end = thing::suffix(opt.ns(), opt.db(), &v);
|
||||||
|
|
|
@ -30,6 +30,8 @@ impl Iterable {
|
||||||
ite.process(ctx, opt, txn, stm, None, val).await;
|
ite.process(ctx, opt, txn, stm, None, val).await;
|
||||||
}
|
}
|
||||||
Iterable::Thing(v) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
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;
|
ite.process(ctx, opt, txn, stm, Some(v), val).await;
|
||||||
}
|
}
|
||||||
Iterable::Mergeable(v, o) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
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;
|
ite.process(ctx, opt, txn, stm, Some(v), val).await;
|
||||||
}
|
}
|
||||||
Iterable::Relatable(f, v, w) => {
|
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
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
|
||||||
let val = txn.clone().lock().await.get(key).await?;
|
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;
|
ite.process(ctx, opt, txn, stm, Some(v), val).await;
|
||||||
}
|
}
|
||||||
Iterable::Table(v) => {
|
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
|
// Prepare the start and end keys
|
||||||
let beg = thing::prefix(opt.ns(), opt.db(), &v);
|
let beg = thing::prefix(opt.ns(), opt.db(), &v);
|
||||||
let end = thing::suffix(opt.ns(), opt.db(), &v);
|
let end = thing::suffix(opt.ns(), opt.db(), &v);
|
||||||
|
|
|
@ -1134,6 +1134,26 @@ impl Transaction {
|
||||||
Ok(v) => Ok(v),
|
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.
|
/// Writes the full database contents as binary SQL.
|
||||||
pub async fn export(&mut self, ns: &str, db: &str, chn: Sender<Vec<u8>>) -> Result<(), Error> {
|
pub async fn export(&mut self, ns: &str, db: &str, chn: Sender<Vec<u8>>) -> Result<(), Error> {
|
||||||
// Output OPTIONS
|
// Output OPTIONS
|
||||||
|
|
|
@ -13,11 +13,15 @@ async fn strict_mode_no_namespace() -> Result<(), Error> {
|
||||||
DEFINE TABLE test;
|
DEFINE TABLE test;
|
||||||
DEFINE FIELD extra ON test VALUE true;
|
DEFINE FIELD extra ON test VALUE true;
|
||||||
CREATE test:tester;
|
CREATE test:tester;
|
||||||
|
SELECT * FROM test;
|
||||||
";
|
";
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
|
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;
|
let tmp = res.remove(0).result;
|
||||||
assert!(matches!(tmp.err(), Some(Error::NsNotFound)));
|
assert!(matches!(tmp.err(), Some(Error::NsNotFound)));
|
||||||
|
@ -42,11 +46,12 @@ async fn strict_mode_no_database() -> Result<(), Error> {
|
||||||
DEFINE TABLE test;
|
DEFINE TABLE test;
|
||||||
DEFINE FIELD extra ON test VALUE true;
|
DEFINE FIELD extra ON test VALUE true;
|
||||||
CREATE test:tester;
|
CREATE test:tester;
|
||||||
|
SELECT * FROM test;
|
||||||
";
|
";
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
|
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;
|
let tmp = res.remove(0).result;
|
||||||
assert!(tmp.is_ok());
|
assert!(tmp.is_ok());
|
||||||
|
@ -60,6 +65,9 @@ async fn strict_mode_no_database() -> Result<(), Error> {
|
||||||
let tmp = res.remove(0).result;
|
let tmp = res.remove(0).result;
|
||||||
assert!(matches!(tmp.err(), Some(Error::DbNotFound)));
|
assert!(matches!(tmp.err(), Some(Error::DbNotFound)));
|
||||||
//
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(matches!(tmp.err(), Some(Error::DbNotFound)));
|
||||||
|
//
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +79,12 @@ async fn strict_mode_no_table() -> Result<(), Error> {
|
||||||
-- DEFINE TABLE test;
|
-- DEFINE TABLE test;
|
||||||
DEFINE FIELD extra ON test VALUE true;
|
DEFINE FIELD extra ON test VALUE true;
|
||||||
CREATE test:tester;
|
CREATE test:tester;
|
||||||
|
SELECT * FROM test;
|
||||||
";
|
";
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
|
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;
|
let tmp = res.remove(0).result;
|
||||||
assert!(tmp.is_ok());
|
assert!(tmp.is_ok());
|
||||||
|
@ -89,6 +98,9 @@ async fn strict_mode_no_table() -> Result<(), Error> {
|
||||||
let tmp = res.remove(0).result;
|
let tmp = res.remove(0).result;
|
||||||
assert!(matches!(tmp.err(), Some(Error::TbNotFound)));
|
assert!(matches!(tmp.err(), Some(Error::TbNotFound)));
|
||||||
//
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(matches!(tmp.err(), Some(Error::TbNotFound)));
|
||||||
|
//
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +112,12 @@ async fn strict_mode_all_ok() -> Result<(), Error> {
|
||||||
DEFINE TABLE test;
|
DEFINE TABLE test;
|
||||||
DEFINE FIELD extra ON test VALUE true;
|
DEFINE FIELD extra ON test VALUE true;
|
||||||
CREATE test:tester;
|
CREATE test:tester;
|
||||||
|
SELECT * FROM test;
|
||||||
";
|
";
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None, true).await?;
|
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;
|
let tmp = res.remove(0).result;
|
||||||
assert!(tmp.is_ok());
|
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 }]");
|
let val = Value::parse("[{ id: test:tester, extra: true }]");
|
||||||
assert_eq!(tmp, val);
|
assert_eq!(tmp, val);
|
||||||
//
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse("[{ id: test:tester, extra: true }]");
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +147,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
||||||
let sql = "
|
let sql = "
|
||||||
DEFINE FIELD extra ON test VALUE true;
|
DEFINE FIELD extra ON test VALUE true;
|
||||||
CREATE test:tester;
|
CREATE test:tester;
|
||||||
|
SELECT * FROM test;
|
||||||
INFO FOR KV;
|
INFO FOR KV;
|
||||||
INFO FOR NS;
|
INFO FOR NS;
|
||||||
INFO FOR DB;
|
INFO FOR DB;
|
||||||
|
@ -138,7 +156,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
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;
|
let tmp = res.remove(0).result;
|
||||||
assert!(tmp.is_ok());
|
assert!(tmp.is_ok());
|
||||||
|
@ -148,6 +166,10 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
|
||||||
assert_eq!(tmp, val);
|
assert_eq!(tmp, val);
|
||||||
//
|
//
|
||||||
let tmp = res.remove(0).result?;
|
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(
|
let val = Value::parse(
|
||||||
"{
|
"{
|
||||||
ns: { test: 'DEFINE NAMESPACE test' },
|
ns: { test: 'DEFINE NAMESPACE test' },
|
||||||
|
|
Loading…
Reference in a new issue