diff --git a/lib/src/dbs/channel.rs b/lib/src/dbs/channel.rs index b3b35032..050223ff 100644 --- a/lib/src/dbs/channel.rs +++ b/lib/src/dbs/channel.rs @@ -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); diff --git a/lib/src/dbs/iterate.rs b/lib/src/dbs/iterate.rs index c1d66e58..e979b631 100644 --- a/lib/src/dbs/iterate.rs +++ b/lib/src/dbs/iterate.rs @@ -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); diff --git a/lib/src/kvs/tx.rs b/lib/src/kvs/tx.rs index 7b51069a..79766392 100644 --- a/lib/src/kvs/tx.rs +++ b/lib/src/kvs/tx.rs @@ -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>) -> Result<(), Error> { // Output OPTIONS diff --git a/lib/tests/strict.rs b/lib/tests/strict.rs index 73a0864b..c773e1fa 100644 --- a/lib/tests/strict.rs +++ b/lib/tests/strict.rs @@ -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' },