Enable table access using partial entity syntax

next
Sayan Nandan 3 years ago
parent d30bc38fbe
commit 369f7b89ed
No known key found for this signature in database
GPG Key ID: 8BC07A0A4D41DD52

@ -15,6 +15,8 @@ All changes in this project will be noted in this file.
- `auth restore <username>`
- `auth restore <origin key> <username>`
- 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

@ -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),
}

@ -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<T> = Result<T, DdlError>;
type OptionTuple<T> = (Option<T>, Option<T>);
/// An owned entity group
pub type OwnedEntityGroup = OptionTuple<ObjectID>;
/// 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<BorrowedEntityGroupRaw<'a>> 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<Arc<Table>> {
pub fn get_table(&self, entity: Entity<'_>) -> KeyspaceResult<Arc<Table>> {
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<Arc<Table>> {
@ -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 <tblname> 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!() },
}
}

@ -77,7 +77,9 @@ action! {
/// We should have `<tableid> <model>(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?;

@ -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(())
}

@ -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, fn() -> 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<bytes::Bytes>,
) -> 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<Entity<'a>, &'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<BorrowedEntityGroup, &'static [u8]> {
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()
}
}

@ -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<binstr>
let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,list<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,list<binstr>)");
let (tbl_name, mcode) = parse_table_args_test(it).unwrap();
assert_eq!(tbl_name, Entity::Single(b"mytbl"));
assert_eq!(mcode, 4);
// binstr, list<str>
let mut it = vec![byt!("mytbl"), byt!("keymap(binstr,list<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,list<str>)");
let (tbl_name, mcode) = parse_table_args_test(it).unwrap();
assert_eq!(tbl_name, Entity::Single(b"mytbl"));
assert_eq!(mcode, 5);
// str, list<binstr>
let mut it = vec![byt!("mytbl"), byt!("keymap(str,list<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,list<binstr>)");
let (tbl_name, mcode) = parse_table_args_test(it).unwrap();
assert_eq!(tbl_name, Entity::Single(b"mytbl"));
assert_eq!(mcode, 6);
// binstr, list<binstr>
let mut it = vec![byt!("mytbl"), byt!("keymap(str,list<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)
});
// str, list<str>
let it = byvec!("mytbl", "keymap(str,list<str>)");
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>, str)");
let it = byvec!("myverycooltbl", "keymap(list<str>, 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>, binstr)");
let it = byvec!("myverycooltbl", "keymap(list<binstr>, 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<str>, binstr)");
let it = byvec!("myverycooltbl", "keymap(list<str>, 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<binstr>, str)");
let it = byvec!("myverycooltbl", "keymap(list<binstr>, 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
);
}

Loading…
Cancel
Save