diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a78e3d..b06191bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ All changes in this project will be noted in this file. - `auth restore ` - `auth restore ` - Shell now supports multiple `--eval` expressions +- Partial entity syntax: `:table` can be used for referring to the current table. For example + you can use `use :default` instead of `use default:default` ## Version 0.7.3 diff --git a/server/src/actions/macros.rs b/server/src/actions/macros.rs index 7c67b56e..d0d24335 100644 --- a/server/src/actions/macros.rs +++ b/server/src/actions/macros.rs @@ -88,7 +88,7 @@ macro_rules! get_tbl_ref { #[macro_export] macro_rules! handle_entity { ($con:expr, $ident:expr) => {{ - match crate::queryengine::parser::get_query_entity(&$ident) { + match crate::queryengine::parser::Entity::from_slice(&$ident) { Ok(e) => e, Err(e) => return conwrite!($con, e), } diff --git a/server/src/corestore/mod.rs b/server/src/corestore/mod.rs index b9970a6b..4109c14a 100644 --- a/server/src/corestore/mod.rs +++ b/server/src/corestore/mod.rs @@ -29,13 +29,13 @@ use crate::corestore::{ memstore::{DdlError, Keyspace, Memstore, ObjectID, DEFAULT}, table::{DescribeTable, Table}, }; +use crate::queryengine::parser::{Entity, OwnedEntity}; use crate::registry; use crate::storage; use crate::storage::v1::sengine::SnapshotEngine; use crate::util::Unwrappable; use crate::IoResult; use core::borrow::Borrow; -use core::fmt; use core::hash::Hash; pub use htable::Data; use std::sync::Arc; @@ -55,57 +55,6 @@ pub mod table; mod tests; pub(super) type KeyspaceResult = Result; -type OptionTuple = (Option, Option); -/// An owned entity group -pub type OwnedEntityGroup = OptionTuple; -/// A raw borrowed entity (not the struct, but in a tuple form) -type BorrowedEntityGroupRaw<'a> = OptionTuple<&'a [u8]>; - -#[derive(PartialEq)] -/// An entity group borrowed from a byte slice -pub struct BorrowedEntityGroup<'a> { - va: Option<&'a [u8]>, - vb: Option<&'a [u8]>, -} - -impl<'a> fmt::Debug for BorrowedEntityGroup<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn write_if_some(v: Option<&'_ [u8]>) -> String { - if let Some(v) = v { - format!("{:?}", String::from_utf8_lossy(&v)) - } else { - "None".to_owned() - } - } - f.debug_struct("BorrowedEntityGroup") - .field("va", &write_if_some(self.va)) - .field("vb", &write_if_some(self.vb)) - .finish() - } -} - -impl<'a> BorrowedEntityGroup<'a> { - pub unsafe fn into_owned(self) -> OwnedEntityGroup { - match self { - BorrowedEntityGroup { - va: Some(a), - vb: Some(b), - } => (Some(ObjectID::from_slice(a)), Some(ObjectID::from_slice(b))), - BorrowedEntityGroup { - va: Some(a), - vb: None, - } => (Some(ObjectID::from_slice(a)), None), - _ => impossible!(), - } - } -} - -impl<'a> From> for BorrowedEntityGroup<'a> { - fn from(oth: BorrowedEntityGroupRaw<'a>) -> Self { - let (va, vb) = oth; - Self { va, vb } - } -} #[derive(Debug, Clone)] struct ConnectionEntityState { @@ -180,23 +129,17 @@ impl Corestore { /// /// If the table is non-existent or the default keyspace was unset, then /// false is returned. Else true is returned - pub fn swap_entity(&mut self, entity: BorrowedEntityGroup) -> KeyspaceResult<()> { + pub fn swap_entity(&mut self, entity: Entity<'_>) -> KeyspaceResult<()> { match entity { // Switch to the provided keyspace - BorrowedEntityGroup { - va: Some(ks), - vb: None, - } => match self.store.get_keyspace_atomic_ref(ks) { + Entity::Single(ks) => match self.store.get_keyspace_atomic_ref(ks) { Some(ksref) => self .estate .set_ks(ksref, unsafe { ObjectID::from_slice(ks) }), None => return Err(DdlError::ObjectNotFound), }, // Switch to the provided table in the given keyspace - BorrowedEntityGroup { - va: Some(ks), - vb: Some(tbl), - } => match self.store.get_keyspace_atomic_ref(ks) { + Entity::Full(ks, tbl) => match self.store.get_keyspace_atomic_ref(ks) { Some(kspace) => match kspace.get_table_atomic_ref(tbl) { Some(tblref) => unsafe { self.estate.set_table( @@ -210,7 +153,15 @@ impl Corestore { }, None => return Err(DdlError::ObjectNotFound), }, - _ => unsafe { impossible!() }, + Entity::Partial(tbl) => match &self.estate.ks { + Some((_, ks)) => match ks.get_table_atomic_ref(tbl) { + Some(tblref) => { + self.estate.table = Some((unsafe { ObjectID::from_slice(tbl) }, tblref)); + } + None => return Err(DdlError::ObjectNotFound), + }, + None => return Err(DdlError::DefaultNotFound), + }, } Ok(()) } @@ -222,29 +173,22 @@ impl Corestore { self.store.get_keyspace_atomic_ref(ksid) } /// Get an atomic reference to a table - pub fn get_table(&self, entity: BorrowedEntityGroup) -> KeyspaceResult> { + pub fn get_table(&self, entity: Entity<'_>) -> KeyspaceResult> { match entity { - BorrowedEntityGroup { - va: Some(ksid), - vb: Some(table), - } => match self.store.get_keyspace_atomic_ref(ksid) { + Entity::Full(ksid, table) => match self.store.get_keyspace_atomic_ref(ksid) { Some(ks) => match ks.get_table_atomic_ref(table) { Some(tbl) => Ok(tbl), None => Err(DdlError::ObjectNotFound), }, None => Err(DdlError::ObjectNotFound), }, - BorrowedEntityGroup { - va: Some(tbl), - vb: None, - } => match &self.estate.ks { + Entity::Single(tbl) | Entity::Partial(tbl) => match &self.estate.ks { Some((_, ks)) => match ks.get_table_atomic_ref(tbl) { Some(tbl) => Ok(tbl), None => Err(DdlError::ObjectNotFound), }, None => Err(DdlError::DefaultNotFound), }, - _ => unsafe { impossible!() }, } } pub fn get_ctable(&self) -> Option> { @@ -267,16 +211,17 @@ impl Corestore { /// **Trip switch handled:** Yes pub fn create_table( &self, - entity: OwnedEntityGroup, + entity: Entity<'_>, modelcode: u8, volatile: bool, ) -> KeyspaceResult<()> { + let entity = entity.into_owned(); // first lock the global flush state let flush_lock = registry::lock_flush_state(); let ret; match entity { // Important: create table is only ks - (Some(tblid), None) => { + OwnedEntity::Single(tblid) | OwnedEntity::Partial(tblid) => { ret = match &self.estate.ks { Some((_, ks)) => { let tbl = Table::from_model_code(modelcode, volatile); @@ -295,7 +240,7 @@ impl Corestore { None => Err(DdlError::DefaultNotFound), }; } - (Some(ksid), Some(tblid)) => { + OwnedEntity::Full(ksid, tblid) => { ret = match self.store.get_keyspace_atomic_ref(&ksid) { Some(kspace) => { let tbl = Table::from_model_code(modelcode, volatile); @@ -314,7 +259,6 @@ impl Corestore { None => Err(DdlError::ObjectNotFound), } } - _ => unsafe { impossible!() }, } // free the global flush lock drop(flush_lock); @@ -322,23 +266,16 @@ impl Corestore { } /// Drop a table - pub fn drop_table(&self, entity: BorrowedEntityGroup) -> KeyspaceResult<()> { + pub fn drop_table(&self, entity: Entity<'_>) -> KeyspaceResult<()> { match entity { - BorrowedEntityGroup { - va: Some(tblid), - vb: None, - } => match &self.estate.ks { + Entity::Single(tblid) | Entity::Partial(tblid) => match &self.estate.ks { Some((_, ks)) => ks.drop_table(tblid), None => Err(DdlError::DefaultNotFound), }, - BorrowedEntityGroup { - va: Some(ksid), - vb: Some(tblid), - } => match self.store.get_keyspace_atomic_ref(ksid) { + Entity::Full(ksid, tblid) => match self.store.get_keyspace_atomic_ref(ksid) { Some(ks) => ks.drop_table(tblid), None => Err(DdlError::ObjectNotFound), }, - _ => unsafe { impossible!() }, } } diff --git a/server/src/queryengine/ddl.rs b/server/src/queryengine/ddl.rs index 1046e722..9f35e765 100644 --- a/server/src/queryengine/ddl.rs +++ b/server/src/queryengine/ddl.rs @@ -77,7 +77,9 @@ action! { /// We should have ` (args) properties` fn create_table(handle: &Corestore, con: &'a mut T, mut act: ActionIter<'a>) { ensure_length(act.len(), |size| size > 1 && size < 4)?; - let (table_entity, model_code) = parser::parse_table_args(&mut act)?; + let table_name = unsafe { act.next().unsafe_unwrap() }; + let model_name = unsafe { act.next().unsafe_unwrap() }; + let (table_entity, model_code) = parser::parse_table_args(table_name, model_name)?; let is_volatile = match act.next() { Some(maybe_volatile) => { ensure_cond_or_err(maybe_volatile.eq(VOLATILE), responses::groups::UNKNOWN_PROPERTY)?; @@ -121,7 +123,7 @@ action! { ensure_length(act.len(), |size| size == 1)?; match act.next() { Some(eg) => { - let entity_group = parser::get_query_entity(eg)?; + let entity_group = parser::Entity::from_slice(eg)?; if registry::state_okay() { handle.drop_table(entity_group)?; con.write_response(responses::groups::OKAY).await?; diff --git a/server/src/queryengine/mod.rs b/server/src/queryengine/mod.rs index 4726f737..968be059 100644 --- a/server/src/queryengine/mod.rs +++ b/server/src/queryengine/mod.rs @@ -33,6 +33,7 @@ use crate::dbnet::connection::prelude::*; use crate::protocol::{ element::UnsafeElement, iter::AnyArrayIter, responses, PipelineQuery, SimpleQuery, UnsafeSlice, }; +use crate::queryengine::parser::Entity; use crate::{actions, admin}; use core::hint::unreachable_unchecked; mod ddl; @@ -192,7 +193,7 @@ action! { // SAFETY: Already checked len act.next_unchecked() }; - handle.swap_entity(parser::get_query_entity(entity)?)?; + handle.swap_entity(Entity::from_slice(entity)?)?; con.write_response(groups::OKAY).await?; Ok(()) } diff --git a/server/src/queryengine/parser.rs b/server/src/queryengine/parser.rs index 8b035b8f..6deb6e61 100644 --- a/server/src/queryengine/parser.rs +++ b/server/src/queryengine/parser.rs @@ -24,15 +24,14 @@ * */ -use crate::corestore::lazy::Lazy; -use crate::corestore::{BorrowedEntityGroup, OwnedEntityGroup}; +use crate::corestore::{lazy::Lazy, memstore::ObjectID}; use crate::kvengine::encoding; use crate::protocol::responses; -use crate::queryengine::ActionIter; -use crate::util::compiler; -use crate::util::compiler::cold_err; -use crate::util::Unwrappable; -use core::str; +use crate::util::{ + self, + compiler::{self, cold_err}, +}; +use core::{fmt, str}; use regex::Regex; type LazyRegexFn = Lazy Regex>; @@ -47,18 +46,18 @@ pub(super) static VALID_CONTAINER_NAME: LazyRegexFn = LazyRegexFn::new(|| Regex::new("^[a-zA-Z_][a-zA-Z_0-9]*$").unwrap()); pub(super) static VALID_TYPENAME: LazyRegexFn = LazyRegexFn::new(|| Regex::new("^<[a-zA-Z][a-zA-Z0-9]+[^>\\s]?>{1}$").unwrap()); -pub(super) fn parse_table_args( - act: &mut ActionIter, -) -> Result<(OwnedEntityGroup, u8), &'static [u8]> { - let table_name = unsafe { act.next().unsafe_unwrap() }; - let model_name = unsafe { act.next().unsafe_unwrap() }; + +pub(super) fn parse_table_args<'a>( + table_name: &'a [u8], + model_name: &'a [u8], +) -> Result<(Entity<'a>, u8), &'static [u8]> { if compiler::unlikely(!encoding::is_utf8(&table_name) || !encoding::is_utf8(&model_name)) { return Err(responses::groups::ENCODING_ERROR); } let model_name_str = unsafe { str::from_utf8_unchecked(model_name) }; // get the entity group - let entity_group = get_query_entity(table_name)?; + let entity_group = Entity::from_slice(table_name)?; let splits: Vec<&str> = model_name_str.split('(').collect(); if compiler::unlikely(splits.len() != 2) { return Err(responses::groups::BAD_EXPRESSION); @@ -136,151 +135,102 @@ pub(super) fn parse_table_args( (LIST_STR, _) | (LIST_BINSTR, _) => return Err(responses::groups::BAD_TYPE_FOR_KEY), _ => return Err(responses::groups::UNKNOWN_DATA_TYPE), }; - Ok(( - unsafe { - // SAFETY: All sizes checked here - entity_group.into_owned() - }, - model_code, - )) + Ok((entity_group, model_code)) } -#[cfg(test)] -pub(super) fn parse_table_args_test( - act: &mut std::vec::IntoIter, -) -> Result<(OwnedEntityGroup, u8), &'static [u8]> { - let table_name = unsafe { act.next().unsafe_unwrap() }; - let model_name = unsafe { act.next().unsafe_unwrap() }; - if compiler::unlikely(!encoding::is_utf8(&table_name) || !encoding::is_utf8(&model_name)) { - return Err(responses::groups::ENCODING_ERROR); - } - let model_name_str = unsafe { str::from_utf8_unchecked(&model_name) }; +type ByteSlice<'a> = &'a [u8]; - // get the entity group - let entity_group = get_query_entity(&table_name)?; - let splits: Vec<&str> = model_name_str.split('(').collect(); - if compiler::unlikely(splits.len() != 2) { - return Err(responses::groups::BAD_EXPRESSION); - } - let model_name_split = unsafe { ucidx!(splits, 0) }; - let model_args_split = unsafe { ucidx!(splits, 1) }; +#[derive(PartialEq)] +pub enum Entity<'a> { + /// Fully qualified syntax (ks:table) + Full(ByteSlice<'a>, ByteSlice<'a>), + /// Half entity syntax (only ks/table) + Single(ByteSlice<'a>), + /// Partial entity syntax (`:table`) + Partial(ByteSlice<'a>), +} - // model name has to have at least one char while model args should have - // atleast `)` 1 chars (for example if the model takes no arguments: `smh()`) - if compiler::unlikely(model_name_split.is_empty() || model_args_split.is_empty()) { - return Err(responses::groups::BAD_EXPRESSION); - } +#[derive(PartialEq)] +pub enum OwnedEntity { + Full(ObjectID, ObjectID), + Single(ObjectID), + Partial(ObjectID), +} - // THIS IS WHERE WE HANDLE THE NEWER MODELS - if model_name_split.as_bytes() != KEYMAP { - return Err(responses::groups::UNKNOWN_MODEL); +impl fmt::Debug for OwnedEntity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + OwnedEntity::Full(a, b) => write!( + f, + "Full('{}:{}')", + String::from_utf8_lossy(a), + String::from_utf8_lossy(b) + ), + OwnedEntity::Single(a) => write!(f, "Single('{}')", String::from_utf8_lossy(a)), + OwnedEntity::Partial(a) => write!(f, "Partial(':{}')", String::from_utf8_lossy(a)), + } } +} - let non_bracketed_end = - unsafe { ucidx!(*model_args_split.as_bytes(), model_args_split.len() - 1) != b')' }; - - if compiler::unlikely(non_bracketed_end) { - return Err(responses::groups::BAD_EXPRESSION); +impl<'a> fmt::Debug for Entity<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.as_owned()) } +} - // should be (ty1, ty2) - let model_args: Vec<&str> = model_args_split[..model_args_split.len() - 1] - .split(',') - .map(|v| v.trim()) - .collect(); - if compiler::unlikely(model_args.len() != 2) { - // nope, someone had fun with commas or they added more args - // let's check if it was comma fun or if it was arg fun - return cold_err({ - let all_nonzero = model_args.into_iter().all(|v| !v.is_empty()); - if all_nonzero { - // arg fun - Err(responses::groups::TOO_MANY_ARGUMENTS) +impl<'a> Entity<'a> { + pub fn from_slice(input: ByteSlice<'a>) -> Result, &'static [u8]> { + let parts: Vec<&[u8]> = input.split(|b| *b == b':').collect(); + if compiler::unlikely(parts.is_empty() || parts.len() > 2) { + return util::err(responses::groups::BAD_EXPRESSION); + } + // just the table + let first_entity = unsafe { ucidx!(parts, 0) }; + if parts.len() == 1 { + Ok(Entity::Single(Self::verify_entity_name(first_entity)?)) + } else { + let second_entity = Self::verify_entity_name(unsafe { ucidx!(parts, 1) })?; + if first_entity.is_empty() { + // partial syntax; so the table is in the second position + Ok(Entity::Partial(second_entity)) } else { - // comma fun - Err(responses::groups::BAD_EXPRESSION) + let keyspace = Self::verify_entity_name(first_entity)?; + let table = Self::verify_entity_name(second_entity)?; + Ok(Entity::Full(keyspace, table)) } - }); + } } - let key_ty = unsafe { ucidx!(model_args, 0) }; - let val_ty = unsafe { ucidx!(model_args, 1) }; - let valid_key_ty = if let Some(idx) = key_ty.chars().position(|v| v.eq(&'<')) { - VALID_CONTAINER_NAME.is_match(&key_ty[..idx]) && VALID_TYPENAME.is_match(&key_ty[idx..]) - } else { - VALID_CONTAINER_NAME.is_match(key_ty) - }; - let valid_val_ty = if let Some(idx) = val_ty.chars().position(|v| v.eq(&'<')) { - VALID_CONTAINER_NAME.is_match(&val_ty[..idx]) && VALID_TYPENAME.is_match(&val_ty[idx..]) - } else { - VALID_CONTAINER_NAME.is_match(val_ty) - }; - if compiler::unlikely(!valid_key_ty || !valid_val_ty) { - return Err(responses::groups::BAD_EXPRESSION); + #[inline(always)] + fn verify_entity_name(input: &[u8]) -> Result<&[u8], &'static [u8]> { + let valid_name = input.len() < 65 + && encoding::is_utf8(input) + && unsafe { VALID_CONTAINER_NAME.is_match(str::from_utf8_unchecked(input)) }; + if compiler::likely(valid_name && !input.is_empty()) { + // valid name + Ok(input) + } else if compiler::unlikely(input.is_empty()) { + // bad expression (something like `:`) + util::err(responses::groups::BAD_EXPRESSION) + } else if compiler::unlikely(input.eq(b"system")) { + // system cannot be switched to + util::err(responses::groups::PROTECTED_OBJECT) + } else { + // the container has a bad name + util::err(responses::groups::BAD_CONTAINER_NAME) + } } - let key_ty = key_ty.as_bytes(); - let val_ty = val_ty.as_bytes(); - let model_code: u8 = match (key_ty, val_ty) { - // pure KVE - (BINSTR, BINSTR) => 0, - (BINSTR, STR) => 1, - (STR, STR) => 2, - (STR, BINSTR) => 3, - // KVExt listmap - (BINSTR, LIST_BINSTR) => 4, - (BINSTR, LIST_STR) => 5, - (STR, LIST_BINSTR) => 6, - (STR, LIST_STR) => 7, - // KVExt bad keytypes (we can't use lists as keys for obvious reasons) - (LIST_STR, _) | (LIST_BINSTR, _) => return Err(responses::groups::BAD_TYPE_FOR_KEY), - _ => return Err(responses::groups::UNKNOWN_DATA_TYPE), - }; - Ok(( + pub fn as_owned(&self) -> OwnedEntity { unsafe { - // SAFETY: All sizes checked here - entity_group.into_owned() - }, - model_code, - )) -} -pub fn get_query_entity<'a>(input: &'a [u8]) -> Result { - let y: Vec<&[u8]> = input.split(|v| *v == b':').collect(); - unsafe { - if y.len() == 1 { - // just ks - let ksret = &ucidx!(y, 0); - #[allow(clippy::if_same_then_else)] - if compiler::unlikely(ksret.len() > 64 || ksret.is_empty()) { - Err(responses::groups::BAD_CONTAINER_NAME) - } else if compiler::unlikely( - !VALID_CONTAINER_NAME.is_match(str::from_utf8_unchecked(ksret)), - ) { - Err(responses::groups::BAD_CONTAINER_NAME) - } else if compiler::unlikely(ksret.eq(&"system".as_bytes())) { - Err(responses::groups::PROTECTED_OBJECT) - } else { - Ok(BorrowedEntityGroup::from((Some(*ksret), None))) + match self { + Self::Full(a, b) => { + OwnedEntity::Full(ObjectID::from_slice(a), ObjectID::from_slice(b)) + } + Self::Single(a) => OwnedEntity::Single(ObjectID::from_slice(a)), + Self::Partial(a) => OwnedEntity::Partial(ObjectID::from_slice(a)), } - } else if y.len() == 2 { - // tbl + ns - let ksret = &ucidx!(y, 0); - let tblret = &ucidx!(y, 1); - if compiler::unlikely(ksret.len() > 64 || tblret.len() > 64) { - Err(responses::groups::BAD_CONTAINER_NAME) - } else if compiler::unlikely(tblret.is_empty() || ksret.is_empty()) { - Err(responses::groups::BAD_EXPRESSION) - } else if compiler::unlikely( - !VALID_CONTAINER_NAME.is_match(str::from_utf8_unchecked(ksret)) - || !VALID_CONTAINER_NAME.is_match(str::from_utf8_unchecked(tblret)), - ) { - Err(responses::groups::BAD_CONTAINER_NAME) - } else if compiler::unlikely(ksret.eq(&"system".as_bytes())) { - Err(responses::groups::PROTECTED_OBJECT) - } else { - Ok(BorrowedEntityGroup::from((Some(*ksret), Some(*tblret)))) - } - } else { - // something wrong - cold_err(Err(responses::groups::BAD_EXPRESSION)) } } + pub fn into_owned(self) -> OwnedEntity { + self.as_owned() + } } diff --git a/server/src/queryengine/tests.rs b/server/src/queryengine/tests.rs index 17b51312..7486b423 100644 --- a/server/src/queryengine/tests.rs +++ b/server/src/queryengine/tests.rs @@ -27,352 +27,332 @@ use super::parser; mod parser_ddl_tests { - use super::parser::parse_table_args_test; - use crate::corestore::memstore::ObjectID; + use super::parser::Entity; + macro_rules! byvec { + ($($element:expr),*) => { + vec![ + $( + $element.as_bytes() + ),* + ] + }; + } + fn parse_table_args_test(input: Vec<&'static [u8]>) -> Result<(Entity<'_>, u8), &'static [u8]> { + super::parser::parse_table_args(&input[0], &input[1]) + } use crate::protocol::responses; #[test] fn test_table_args_valid() { // binstr, binstr - let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,binstr)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(binstr,binstr)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 0); // binstr, str - let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,str)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(binstr,str)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 1); // str, str - let mut it = vec![byt!("mytbl"), byt!("keymap(str,str)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(str,str)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 2); // str, binstr - let mut it = vec![byt!("mytbl"), byt!("keymap(str,binstr)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(str,binstr)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 3); // now test kvext: listmap // binstr, list - let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,list)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(binstr,list)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 4); // binstr, list - let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,list)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(binstr,list)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 5); // str, list - let mut it = vec![byt!("mytbl"), byt!("keymap(str,list)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + let it = byvec!("mytbl", "keymap(str,list)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 6); - // binstr, list - let mut it = vec![byt!("mytbl"), byt!("keymap(str,list)")].into_iter(); - let (tbl_name, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tbl_name, unsafe { - (Some(ObjectID::from_slice("mytbl")), None) - }); + // str, list + let it = byvec!("mytbl", "keymap(str,list)"); + let (tbl_name, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tbl_name, Entity::Single(b"mytbl")); assert_eq!(mcode, 7); } #[test] fn test_table_bad_ident() { - let mut it = vec![byt!("1one"), byt!("keymap(binstr,binstr)")].into_iter(); + let it = byvec!("1one", "keymap(binstr,binstr)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_CONTAINER_NAME ); - let mut it = vec![byt!("%whywouldsomeone"), byt!("keymap(binstr,binstr)")].into_iter(); + let it = byvec!("%whywouldsomeone", "keymap(binstr,binstr)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_CONTAINER_NAME ); } #[test] fn test_table_whitespaced_datatypes() { - let mut it = vec![byt!("mycooltbl"), byt!("keymap(binstr, binstr)")].into_iter(); - let (tblid, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tblid, unsafe { - (Some(ObjectID::from_slice("mycooltbl")), None) - }); + let it = byvec!("mycooltbl", "keymap(binstr, binstr)"); + let (tblid, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tblid, Entity::Single(b"mycooltbl")); assert_eq!(mcode, 0); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(binstr, str)")].into_iter(); - let (tblid, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tblid, unsafe { - (Some(ObjectID::from_slice("mycooltbl")), None) - }); + let it = byvec!("mycooltbl", "keymap(binstr, str)"); + let (tblid, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tblid, Entity::Single(b"mycooltbl")); assert_eq!(mcode, 1); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(str, str)")].into_iter(); - let (tblid, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tblid, unsafe { - (Some(ObjectID::from_slice("mycooltbl")), None) - }); + let it = byvec!("mycooltbl", "keymap(str, str)"); + let (tblid, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tblid, Entity::Single(b"mycooltbl")); assert_eq!(mcode, 2); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(str, binstr)")].into_iter(); - let (tblid, mcode) = parse_table_args_test(&mut it).unwrap(); - assert_eq!(tblid, unsafe { - (Some(ObjectID::from_slice("mycooltbl")), None) - }); + let it = byvec!("mycooltbl", "keymap(str, binstr)"); + let (tblid, mcode) = parse_table_args_test(it).unwrap(); + assert_eq!(tblid, Entity::Single(b"mycooltbl")); assert_eq!(mcode, 3); } #[test] fn test_table_badty() { - let mut it = vec![byt!("mycooltbl"), byt!("keymap(wth, str)")].into_iter(); + let it = byvec!("mycooltbl", "keymap(wth, str)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_DATA_TYPE ); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(wth, wth)")].into_iter(); + let it = byvec!("mycooltbl", "keymap(wth, wth)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_DATA_TYPE ); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(str, wth)")].into_iter(); + let it = byvec!("mycooltbl", "keymap(str, wth)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_DATA_TYPE ); - let mut it = vec![byt!("mycooltbl"), byt!("keymap(wth1, wth2)")].into_iter(); + let it = byvec!("mycooltbl", "keymap(wth1, wth2)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_DATA_TYPE ); } #[test] fn test_table_bad_model() { - let mut it = vec![byt!("mycooltbl"), byt!("wthmap(wth, wth)")].into_iter(); + let it = byvec!("mycooltbl", "wthmap(wth, wth)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_MODEL ); - let mut it = vec![byt!("mycooltbl"), byt!("wthmap(str, str)")].into_iter(); + let it = byvec!("mycooltbl", "wthmap(str, str)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_MODEL ); - let mut it = vec![byt!("mycooltbl"), byt!("wthmap()")].into_iter(); + let it = byvec!("mycooltbl", "wthmap()"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::UNKNOWN_MODEL ); } #[test] fn test_table_malformed_expr() { - let mut it = bi!("mycooltbl", "keymap("); + let it = byvec!("mycooltbl", "keymap("); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(,"); + let it = byvec!("mycooltbl", "keymap(,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(,,"); + let it = byvec!("mycooltbl", "keymap(,,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap),"); + let it = byvec!("mycooltbl", "keymap),"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap),,"); + let it = byvec!("mycooltbl", "keymap),,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap),,)"); + let it = byvec!("mycooltbl", "keymap),,)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(,)"); + let it = byvec!("mycooltbl", "keymap(,)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(,,)"); + let it = byvec!("mycooltbl", "keymap(,,)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap,"); + let it = byvec!("mycooltbl", "keymap,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap,,"); + let it = byvec!("mycooltbl", "keymap,,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap,,)"); + let it = byvec!("mycooltbl", "keymap,,)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(str,"); + let it = byvec!("mycooltbl", "keymap(str,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(str,str"); + let it = byvec!("mycooltbl", "keymap(str,str"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(str,str,"); + let it = byvec!("mycooltbl", "keymap(str,str,"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(str,str,)"); + let it = byvec!("mycooltbl", "keymap(str,str,)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); - let mut it = bi!("mycooltbl", "keymap(str,str,),"); + let it = byvec!("mycooltbl", "keymap(str,str,),"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_EXPRESSION ); } #[test] fn test_table_too_many_args() { - let mut it = bi!("mycooltbl", "keymap(str, str, str)"); + let it = byvec!("mycooltbl", "keymap(str, str, str)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::TOO_MANY_ARGUMENTS ); // this should be valid for not-yet-known data types too - let mut it = bi!("mycooltbl", "keymap(wth, wth, wth)"); + let it = byvec!("mycooltbl", "keymap(wth, wth, wth)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::TOO_MANY_ARGUMENTS ); } #[test] fn test_bad_key_type() { - let mut it = bi!("myverycooltbl", "keymap(list, str)"); + let it = byvec!("myverycooltbl", "keymap(list, str)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_TYPE_FOR_KEY ); - let mut it = bi!("myverycooltbl", "keymap(list, binstr)"); + let it = byvec!("myverycooltbl", "keymap(list, binstr)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_TYPE_FOR_KEY ); // for consistency checks - let mut it = bi!("myverycooltbl", "keymap(list, binstr)"); + let it = byvec!("myverycooltbl", "keymap(list, binstr)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_TYPE_FOR_KEY ); - let mut it = bi!("myverycooltbl", "keymap(list, str)"); + let it = byvec!("myverycooltbl", "keymap(list, str)"); assert_eq!( - parse_table_args_test(&mut it).unwrap_err(), + parse_table_args_test(it).unwrap_err(), responses::groups::BAD_TYPE_FOR_KEY ); } } mod entity_parser_tests { - use super::parser::get_query_entity; - use crate::corestore::BorrowedEntityGroup; + use super::parser::Entity; use crate::protocol::responses; #[test] fn test_query_full_entity_okay() { let x = byt!("ks:tbl"); - assert_eq!( - get_query_entity(&x).unwrap(), - BorrowedEntityGroup::from((Some("ks".as_bytes()), Some("tbl".as_bytes()))) - ); + assert_eq!(Entity::from_slice(&x).unwrap(), Entity::Full(b"ks", b"tbl")); } #[test] fn test_query_half_entity() { let x = byt!("tbl"); - assert_eq!( - get_query_entity(&x).unwrap(), - BorrowedEntityGroup::from((Some("tbl".as_bytes()), None)) - ) + assert_eq!(Entity::from_slice(&x).unwrap(), Entity::Single(b"tbl")) + } + #[test] + fn test_query_partial_entity() { + let x = byt!(":tbl"); + assert_eq!(Entity::from_slice(&x).unwrap(), Entity::Partial(b"tbl")) } #[test] fn test_query_entity_badexpr() { let x = byt!("ks:"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!(":"); assert_eq!( - get_query_entity(&x).unwrap_err(), - responses::groups::BAD_EXPRESSION - ); - let x = byt!(":tbl"); - assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("::"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("::ks"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("ks::tbl"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("ks::"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("ks::tbl::"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); let x = byt!("::ks::tbl::"); assert_eq!( - get_query_entity(&x).unwrap_err(), + Entity::from_slice(&x).unwrap_err(), responses::groups::BAD_EXPRESSION ); } @@ -381,7 +361,7 @@ mod entity_parser_tests { fn test_bad_entity_name() { let ename = byt!("$var"); assert_eq!( - get_query_entity(&ename).unwrap_err(), + Entity::from_slice(&ename).unwrap_err(), responses::groups::BAD_CONTAINER_NAME ); }