Add the `whereami` action (#232)

* Move macros into module

* Add the `whereami` action to identify the current entity

* Show entity group in the skysh prompt

* Add tests and actiondoc for `whereami`

* Add changelog entry

* Upgrade deps
next
Sayan 3 years ago committed by GitHub
parent c260dac3a4
commit 76f493753b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,11 +6,12 @@ All changes in this project will be noted in this file.
### Additions
- Pipelined queries are now supported
### Improvements
- `skyd`:
- Pipelined queries are now supported
- The `whereami` action was added which lets one find out which entity the current connection
is connected to
- `skysh`:
- now shows the current entity in the prompt
- handles special character strings more reliably
- now supports splitting a command across multiple lines
- now supports multi-line pastes

12
Cargo.lock generated

@ -71,9 +71,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cc"
version = "1.0.71"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
[[package]]
name = "cfg-if"
@ -929,7 +929,7 @@ dependencies = [
[[package]]
name = "skytable"
version = "0.6.2-alpha.2"
source = "git+https://github.com/skytable/client-rust?branch=next#43ab1e47903a3772657351bc5dea64cc4258f491"
source = "git+https://github.com/skytable/client-rust?branch=next#0cf07e341b4da9fa452a92571ffd5ec5d3e02c5a"
dependencies = [
"bytes",
"openssl",
@ -940,7 +940,7 @@ dependencies = [
[[package]]
name = "skytable"
version = "0.6.2-alpha.2"
source = "git+https://github.com/skytable/client-rust.git#43ab1e47903a3772657351bc5dea64cc4258f491"
source = "git+https://github.com/skytable/client-rust.git#0cf07e341b4da9fa452a92571ffd5ec5d3e02c5a"
[[package]]
name = "smallvec"
@ -988,9 +988,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.20.5"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e223c65cd36b485a34c2ce6e38efa40777d31c4166d9076030c74cdcf971679f"
checksum = "fb6c2c4a6ca462f07ca89841a2618dca6e405304d19ae238997e64915d89f513"
dependencies = [
"cfg-if",
"core-foundation-sys",

@ -64,6 +64,13 @@ global:
syntax: [FLUSHDB, FLUSHDB <entity>]
desc: Removes all entries stored in the current table or in the provided entity
return: [Rcode 0, Rcode 5]
- name: WHEREAMI
complexity: O(1)
accept: [AnyArray]
syntax: [WHEREAMI]
desc: |
Returns a flat array with either the name of the current keyspace as the first element or if a default table
is set, then it returns the keyspace name as the first element and the table name as the second element
keyvalue:
generic:
- name: DEL

@ -39,9 +39,8 @@ use skytable::Pipeline;
use skytable::Query;
use std::io::stdout;
use std::process;
const ADDR: &str = "127.0.0.1";
const SKYSH_BLANK: &str = " > ";
const SKYSH_PROMPT: &str = "skysh> ";
const SKYSH_HISTORY_FILE: &str = ".sky_history";
const HELP_TEXT: &str = r#"
@ -90,6 +89,20 @@ your hands, the sky is the only limit on what you can create!
/// written to the socket (which is either `localhost:2003` or it is determined by
/// command line parameters)
pub async fn start_repl() {
let mut skysh_blank: String = " > ".to_owned();
let mut skysh_prompt: String = "skysh@default:default> ".to_owned();
let mut did_swap = false;
macro_rules! readln {
($editor:expr) => {
match $editor.readline(&skysh_blank) {
Ok(l) => l,
Err(ReadlineError::Interrupted) => return,
Err(err) => fatal!("ERROR: Failed to read line with error: {}", err),
}
};
}
let cfg_layout = load_yaml!("./cli.yml");
let matches = App::from_yaml(cfg_layout).get_matches();
let host = libsky::option_unwrap_or!(matches.value_of("host"), ADDR);
@ -118,6 +131,18 @@ pub async fn start_repl() {
Ok(c) => c,
Err(e) => fatal!("Failed to connect to server with error: {}", e),
};
macro_rules! checkswap {
() => {
if did_swap {
// noice, we need to poll for the location of the new entity
runner
.check_entity(&mut skysh_blank, &mut skysh_prompt)
.await;
}
};
}
if let Some(eval_expr) = matches.value_of("eval") {
if !eval_expr.is_empty() {
runner.run_query(eval_expr).await;
@ -135,7 +160,7 @@ pub async fn start_repl() {
},
}
loop {
match editor.readline(SKYSH_PROMPT) {
match editor.readline(&skysh_prompt) {
Ok(mut line) => {
macro_rules! tokenize {
($inp:expr) => {
@ -176,6 +201,10 @@ pub async fn start_repl() {
let mut pipeline = Pipeline::new();
line = readln!(editor);
loop {
did_swap = line
.get(..3)
.map(|v| v.eq_ignore_ascii_case("use"))
.unwrap_or(did_swap);
if !line.is_empty() {
if *(line.as_bytes().last().unwrap()) == b';' {
break;
@ -192,6 +221,7 @@ pub async fn start_repl() {
pipeline.push(q);
}
runner.run_pipeline(pipeline).await;
checkswap!();
}
_ => eskysh!("Unknown shell command"),
}
@ -210,7 +240,12 @@ pub async fn start_repl() {
line.drain(line.len() - 2..);
line.extend(cl.chars());
}
runner.run_query(&line).await
did_swap = line
.get(..3)
.map(|v| v.eq_ignore_ascii_case("use"))
.unwrap_or(did_swap);
runner.run_query(&line).await;
checkswap!();
}
}
}

@ -120,13 +120,3 @@ macro_rules! fatal {
::std::process::exit(0x01)
}};
}
macro_rules! readln {
($editor:expr) => {
match $editor.readline(SKYSH_BLANK) {
Ok(l) => l,
Err(ReadlineError::Interrupted) => return,
Err(err) => fatal!("ERROR: Failed to read line with error: {}", err),
}
};
}

@ -84,6 +84,46 @@ impl Runner {
Err(e) => fatal!("An I/O error occurred while querying: {}", e),
}
}
pub async fn check_entity(&mut self, blank: &mut String, prompt: &mut String) {
let query: Query = tokenizer::get_query(b"whereami").unwrap();
let ret = match self {
Self::Insecure(con) => con.run_simple_query(&query).await,
Self::Secure(con) => con.run_simple_query(&query).await,
};
let ret = match ret {
Ok(resp) => resp,
Err(e) => fatal!("An I/O error occurred while querying: {}", e),
};
match ret {
Element::Array(Array::Flat(frr)) => match frr.len() {
1 => {
let elem = match &frr[0] {
FlatElement::String(st) => st,
_ => fatal!("The server returned an unexpected response while checking entity state"),
};
*blank = format!(" {blank}> ", blank = " ".repeat(elem.len()));
*prompt = format!("skysh@{ks}> ", ks = elem);
}
2 => {
let ks = match &frr[0] {
FlatElement::String(st) => st,
_ => fatal!("The server returned an unexpected response while checking entity state"),
};
let tbl = match &frr[1] {
FlatElement::String(st) => st,
_ => fatal!("The server returned an unexpected response while checking entity state"),
};
*blank = format!(" {blank}> ", blank = " ".repeat(ks.len() + tbl.len() + 1));
*prompt = format!("skysh@{ks}:{tbl}> ", ks = ks, tbl = tbl);
}
count => fatal!(
"The server returned {} IDs while checking entity state",
count
),
},
_ => fatal!("The server returned the wrong data type for entity state check"),
}
}
}
fn print_element(el: Element) {

@ -36,7 +36,7 @@ winapi = { version = "0.3.9", features = ["fileapi"] }
[target.'cfg(unix)'.build-dependencies]
# external deps
cc = "1.0.71"
cc = "1.0.72"
[dev-dependencies]
# internal deps
@ -51,7 +51,7 @@ rand = "0.8.4"
tokio = { version = "1.13.0", features = ["test-util"] }
[target.'cfg(unix)'.dependencies]
# external deps
libc = "0.2.106"
libc = "0.2.107"
[features]
nightly = []

@ -0,0 +1,179 @@
/*
* Created on Thu Nov 11 2021
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2021, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/*
Don't modulo because it's an L1 miss and an L2 hit. Use lowbit checks to check for parity
*/
#[macro_export]
/// endian independent check to see if the lowbit is set or not. Returns true if the lowbit
/// is set. this is undefined to be applied on signed values on one's complement targets
macro_rules! is_lowbit_set {
($v:expr) => {
$v & 1 == 1
};
}
#[macro_export]
/// endian independent check to see if the lowbit is unset or not. Returns true if the lowbit
/// is unset. this is undefined to be applied on signed values on one's complement targets
macro_rules! is_lowbit_unset {
($v:expr) => {
$v & 1 == 0
};
}
#[macro_export]
macro_rules! err_if_len_is {
($buf:ident, $con:ident, eq $len:literal) => {
if $buf.len() == $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, not $len:literal) => {
if $buf.len() != $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, gt $len:literal) => {
if $buf.len() > $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, lt $len:literal) => {
if $buf.len() < $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, gt_or_eq $len:literal) => {
if $buf.len() >= $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, lt_or_eq $len:literal) => {
if $buf.len() <= $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($con:ident, $expr:expr) => {
if $expr {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
}
#[macro_export]
macro_rules! kve {
($con:expr, $store:expr) => {
match $store.get_kvstore() {
Ok(store) => store,
_ => {
// wrong model
return $con
.write_response(crate::protocol::responses::groups::WRONG_MODEL)
.await;
}
}
};
}
#[macro_export]
macro_rules! default_keyspace {
($store:expr, $con:expr) => {
match $store.get_keyspace() {
Ok(ks) => ks,
Err(_) => {
return $con
.write_response(crate::protocol::responses::groups::DEFAULT_UNSET)
.await;
}
}
};
}
#[macro_export]
macro_rules! conwrite {
($con:expr, $what:expr) => {
$con.write_response($what).await
};
}
#[macro_export]
macro_rules! aerr {
($con:expr, aerr) => {
return conwrite!($con, crate::protocol::responses::groups::ACTION_ERR)
};
}
#[macro_export]
macro_rules! get_tbl {
($entity:expr, $store:expr, $con:expr) => {{
use crate::corestore::memstore::DdlError;
match $store.get_table($entity) {
Ok(tbl) => tbl,
Err(DdlError::DefaultNotFound) => {
return conwrite!($con, crate::protocol::responses::groups::DEFAULT_UNSET);
}
Err(DdlError::ObjectNotFound) => {
return conwrite!(
$con,
crate::protocol::responses::groups::CONTAINER_NOT_FOUND
);
}
Err(_) => unsafe { impossible!() },
}
}};
($store:expr, $con:expr) => {{
match $store.get_ctable() {
Some(tbl) => tbl,
None => return conwrite!($con, crate::protocol::responses::groups::DEFAULT_UNSET),
}
}};
}
#[macro_export]
macro_rules! handle_entity {
($con:expr, $ident:expr) => {{
match crate::queryengine::parser::get_query_entity(&$ident) {
Ok(e) => e,
Err(e) => return conwrite!($con, e),
}
}};
}

@ -30,6 +30,8 @@
//! of the actions supported by Skytable
//!
#[macro_use]
mod macros;
pub mod dbsize;
pub mod del;
pub mod exists;
@ -48,6 +50,7 @@ pub mod set;
pub mod strong;
pub mod update;
pub mod uset;
pub mod whereami;
pub mod heya {
//! Respond to `HEYA` queries
use crate::dbnet::connection::prelude::*;
@ -65,78 +68,3 @@ pub mod heya {
}
);
}
/*
Don't modulo because it's an L1 miss and an L2 hit. Use lowbit checks to check for parity
*/
#[macro_export]
/// endian independent check to see if the lowbit is set or not. Returns true if the lowbit
/// is set. this is undefined to be applied on signed values on one's complement targets
macro_rules! is_lowbit_set {
($v:expr) => {
$v & 1 == 1
};
}
#[macro_export]
/// endian independent check to see if the lowbit is unset or not. Returns true if the lowbit
/// is unset. this is undefined to be applied on signed values on one's complement targets
macro_rules! is_lowbit_unset {
($v:expr) => {
$v & 1 == 0
};
}
#[macro_export]
macro_rules! err_if_len_is {
($buf:ident, $con:ident, eq $len:literal) => {
if $buf.len() == $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, not $len:literal) => {
if $buf.len() != $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, gt $len:literal) => {
if $buf.len() > $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, lt $len:literal) => {
if $buf.len() < $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, gt_or_eq $len:literal) => {
if $buf.len() >= $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($buf:ident, $con:ident, lt_or_eq $len:literal) => {
if $buf.len() <= $len {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
($con:ident, $expr:expr) => {
if $expr {
return $con
.write_response(crate::protocol::responses::groups::ACTION_ERR)
.await;
}
};
}

@ -0,0 +1,47 @@
/*
* Created on Fri Nov 12 2021
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2021, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use crate::dbnet::connection::prelude::*;
use crate::resp::writer::FlatArrayWriter;
action! {
fn whereami(store: &Corestore, con: &mut T, iter: ActionIter<'a>) {
err_if_len_is!(iter, con, not 0);
match store.get_ids() {
(Some(ks), Some(tbl)) => {
let mut writer = unsafe { FlatArrayWriter::new(con, b'+', 2).await? };
writer.write_element(ks).await?;
writer.write_element(tbl).await?;
},
(Some(ks), None) => {
let mut writer = unsafe { FlatArrayWriter::new(con, b'+', 1).await? };
writer.write_element(ks).await?;
},
_ => unsafe { impossible!() }
}
Ok(())
}
}

@ -95,16 +95,44 @@ impl<'a> From<BorrowedEntityGroupRaw<'a>> for BorrowedEntityGroup<'a> {
}
}
#[derive(Debug, Clone)]
struct ConnectionEntityState {
/// the current table for a connection
table: Option<(ObjectID, Arc<Table>)>,
/// the current keyspace for a connection
ks: Option<(ObjectID, Arc<Keyspace>)>,
}
impl ConnectionEntityState {
fn default(ks: Arc<Keyspace>, tbl: Arc<Table>) -> Self {
Self {
table: Some((DEFAULT.clone(), tbl)),
ks: Some((DEFAULT.clone(), ks)),
}
}
fn set_ks(&mut self, ks: Arc<Keyspace>, ksid: ObjectID) {
self.ks = Some((ksid, ks));
self.table = None;
}
fn set_table(&mut self, ks: Arc<Keyspace>, ksid: ObjectID, tbl: Arc<Table>, tblid: ObjectID) {
self.ks = Some((ksid, ks));
self.table = Some((tblid, tbl));
}
fn get_id_pack(&self) -> (Option<&ObjectID>, Option<&ObjectID>) {
(
self.ks.as_ref().map(|(id, _)| id),
self.table.as_ref().map(|(id, _)| id),
)
}
}
/// The top level abstraction for the in-memory store. This is free to be shared across
/// threads, cloned and well, whatever. Most importantly, clones have an independent container
/// state that is the state of one connection and its container state preferences are never
/// synced across instances. This is important (see the impl for more info)
#[derive(Debug, Clone)]
pub struct Corestore {
/// the default keyspace for this instance of the object
cks: Option<Arc<Keyspace>>,
/// the current table for this instance of the object
ctable: Option<Arc<Table>>,
estate: ConnectionEntityState,
/// an atomic reference to the actual backing storage
store: Arc<Memstore>,
/// the snapshot engine
@ -125,8 +153,7 @@ impl Corestore {
let cks = unsafe { store.get_keyspace_atomic_ref(&DEFAULT).unsafe_unwrap() };
let ctable = unsafe { cks.get_table_atomic_ref(&DEFAULT).unsafe_unwrap() };
Self {
cks: Some(cks),
ctable: Some(ctable),
estate: ConnectionEntityState::default(cks, ctable),
store: Arc::new(store),
sengine,
}
@ -148,10 +175,9 @@ impl Corestore {
va: Some(ks),
vb: None,
} => match self.store.get_keyspace_atomic_ref(ks) {
Some(ksref) => {
self.cks = Some(ksref);
self.ctable = None;
}
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
@ -160,7 +186,14 @@ impl Corestore {
vb: Some(tbl),
} => match self.store.get_keyspace_atomic_ref(ks) {
Some(kspace) => match kspace.get_table_atomic_ref(tbl) {
Some(tblref) => self.ctable = Some(tblref),
Some(tblref) => unsafe {
self.estate.set_table(
kspace,
ObjectID::from_slice(ks),
tblref,
ObjectID::from_slice(tbl),
)
},
None => return Err(DdlError::ObjectNotFound),
},
None => return Err(DdlError::ObjectNotFound),
@ -192,8 +225,8 @@ impl Corestore {
BorrowedEntityGroup {
va: Some(tbl),
vb: None,
} => match &self.cks {
Some(ks) => match ks.get_table_atomic_ref(tbl) {
} => match &self.estate.ks {
Some((_, ks)) => match ks.get_table_atomic_ref(tbl) {
Some(tbl) => Ok(tbl),
None => Err(DdlError::ObjectNotFound),
},
@ -203,16 +236,15 @@ impl Corestore {
}
}
pub fn get_ctable(&self) -> Option<Arc<Table>> {
self.ctable.clone()
self.estate.table.as_ref().map(|(_, tbl)| tbl.clone())
}
/// Get the key/value store
///
/// `Err`s are propagated if the target table has an incorrect table or if
/// the default table is unset
pub fn get_kvstore(&self) -> KeyspaceResult<&KVEngine> {
match &self.ctable {
Some(tbl) => match tbl.get_kvstore() {
match &self.estate.table {
Some((_, tbl)) => match tbl.get_kvstore() {
Ok(kvs) => Ok(kvs),
_ => Err(DdlError::WrongModel),
},
@ -240,8 +272,8 @@ impl Corestore {
match entity {
// Important: create table <tblname> is only ks
(Some(tblid), None) => {
ret = match &self.cks {
Some(ks) => {
ret = match &self.estate.ks {
Some((_, ks)) => {
let tbl = Table::from_model_code(modelcode, volatile);
if let Some(tbl) = tbl {
if ks.create_table(tblid, tbl) {
@ -290,8 +322,8 @@ impl Corestore {
BorrowedEntityGroup {
va: Some(tblid),
vb: None,
} => match &self.cks {
Some(ks) => ks.drop_table(tblid),
} => match &self.estate.ks {
Some((_, ks)) => ks.drop_table(tblid),
None => Err(DdlError::DefaultNotFound),
},
BorrowedEntityGroup {
@ -363,4 +395,7 @@ impl Corestore {
pub fn strong_count(&self) -> usize {
Arc::strong_count(&self.store)
}
pub fn get_ids(&self) -> (Option<&ObjectID>, Option<&ObjectID>) {
self.estate.get_id_pack()
}
}

@ -91,79 +91,6 @@ pub mod prelude {
pub use crate::registry;
pub use crate::util::Unwrappable;
pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[macro_export]
macro_rules! kve {
($con:expr, $store:expr) => {
match $store.get_kvstore() {
Ok(store) => store,
_ => {
// wrong model
return $con
.write_response(crate::protocol::responses::groups::WRONG_MODEL)
.await;
}
}
};
}
#[macro_export]
macro_rules! default_keyspace {
($store:expr, $con:expr) => {
match $store.get_keyspace() {
Ok(ks) => ks,
Err(_) => {
return $con
.write_response(crate::protocol::responses::groups::DEFAULT_UNSET)
.await;
}
}
};
}
#[macro_export]
macro_rules! conwrite {
($con:expr, $what:expr) => {
$con.write_response($what).await
};
}
#[macro_export]
macro_rules! aerr {
($con:expr, aerr) => {
return conwrite!($con, crate::protocol::responses::groups::ACTION_ERR)
};
}
#[macro_export]
macro_rules! get_tbl {
($entity:expr, $store:expr, $con:expr) => {{
use crate::corestore::memstore::DdlError;
match $store.get_table($entity) {
Ok(tbl) => tbl,
Err(DdlError::DefaultNotFound) => {
return conwrite!($con, crate::protocol::responses::groups::DEFAULT_UNSET);
}
Err(DdlError::ObjectNotFound) => {
return conwrite!(
$con,
crate::protocol::responses::groups::CONTAINER_NOT_FOUND
);
}
Err(_) => unsafe { impossible!() },
}
}};
($store:expr, $con:expr) => {{
match $store.get_ctable() {
Some(tbl) => tbl,
None => return conwrite!($con, crate::protocol::responses::groups::DEFAULT_UNSET),
}
}};
}
#[macro_export]
macro_rules! handle_entity {
($con:expr, $ident:expr) => {{
match crate::queryengine::parser::get_query_entity(&$ident) {
Ok(e) => e,
Err(e) => return conwrite!($con, e),
}
}};
}
}
/// # The `ProtocolConnectionExt` trait

@ -164,7 +164,8 @@ where
MPOP => actions::mpop::mpop,
LSET => actions::lists::lset,
LGET => actions::lists::lget::lget,
LMOD => actions::lists::lmod::lmod
LMOD => actions::lists::lmod::lmod,
WHEREAMI => actions::whereami::whereami
);
}
Ok(())

@ -27,7 +27,8 @@
#[sky_macros::dbtest]
mod __private {
use libstress::utils;
use skytable::{Element, Query, RespCode};
use skytable::types::{Array, FlatElement};
use skytable::{query, Element, Query, RespCode};
async fn test_create_keyspace() {
let mut rng = rand::thread_rng();
let ksname = utils::rand_alphastring(10, &mut rng);
@ -169,4 +170,38 @@ mod __private {
Element::RespCode(RespCode::ActionError)
)
}
async fn test_whereami() {
let mykeyspace: Vec<&str> = __MYENTITY__.split(':').collect::<Vec<&str>>();
query.push("whereami");
assert_eq!(
con.run_simple_query(&query).await.unwrap(),
Element::Array(Array::Flat(vec![
FlatElement::String(mykeyspace[0].to_owned()),
FlatElement::String(mykeyspace[1].to_owned())
]))
);
runeq!(
con,
query!("use", "default"),
Element::RespCode(RespCode::Okay)
);
runeq!(
con,
query!("whereami"),
Element::Array(Array::Flat(vec![FlatElement::String("default".to_owned())]))
);
runeq!(
con,
query!("use", "default:default"),
Element::RespCode(RespCode::Okay)
);
runeq!(
con,
query!("whereami"),
Element::Array(Array::Flat(vec![
FlatElement::String("default".to_owned()),
FlatElement::String("default".to_owned())
]))
);
}
}

@ -15,4 +15,4 @@ clap = { version = "2.33.3", features = ["yaml"] }
devtimer = "4.0.1"
rand = "0.8.4"
serde = { version = "1.0.130", features = ["derive"] }
serde_json = "1.0.68"
serde_json = "1.0.69"

@ -12,7 +12,7 @@ libstress = { path = "../libstress" }
skytable = { git = "https://github.com/skytable/client-rust.git", branch = "next", features = [
"dbg",
] }
sysinfo = "0.20.5"
sysinfo = "0.21.1"
devtimer = "4.0.1"
# external deps
env_logger = "0.9.0"

Loading…
Cancel
Save