Add `use $current`

next
Sayan Nandan 10 months ago
parent acd7b3842c
commit fce183afd9
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

16
Cargo.lock generated

@ -647,9 +647,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
@ -965,9 +965,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.9.3"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
@ -977,9 +977,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.3.6"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
@ -988,9 +988,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.7.4"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustc-demangle"

@ -75,6 +75,13 @@ pub struct Parameterizer {
query: Vec<u8>,
}
#[derive(Debug, PartialEq)]
pub enum ExecKind {
Standard(Query),
UseSpace(Query, String),
UseNull(Query),
}
impl Parameterizer {
pub fn new(q: String) -> Self {
Self {
@ -84,7 +91,7 @@ impl Parameterizer {
query: vec![],
}
}
pub fn parameterize(mut self) -> CliResult<Query> {
pub fn parameterize(mut self) -> CliResult<ExecKind> {
while self.not_eof() {
match self.buf[self.i] {
b if b.is_ascii_alphabetic() || b == b'_' => self.read_ident(),
@ -111,7 +118,22 @@ impl Parameterizer {
self.params.into_iter().for_each(|p| {
q.push_param(p);
});
Ok(q)
Ok(if qstr.eq_ignore_ascii_case("use null") {
ExecKind::UseNull(q)
} else {
let mut splits = qstr.split_ascii_whitespace();
let tok_use = splits.next();
let tok_name = splits.next();
match (tok_use, tok_name) {
(Some(tok_use), Some(tok_name))
if tok_use.eq_ignore_ascii_case("use")
&& !tok_name.eq_ignore_ascii_case("$current") =>
{
ExecKind::UseSpace(q, tok_name.into())
}
_ => ExecKind::Standard(q),
}
})
}
Err(_) => Err(CliError::QueryError("query is not valid UTF-8".into())),
}

@ -24,6 +24,8 @@
*
*/
use crate::query::ExecKind;
use {
crate::{
args::{ClientConfig, ClientConfigKind},
@ -91,8 +93,9 @@ fn repl<C: IsConnection>(mut con: C) -> CliResult<()> {
Ok(e) => e,
Err(e) => fatal!("error: failed to init REPL. {e}"),
};
let mut prompt = "> ".to_owned();
loop {
match editor.readline("> ") {
match editor.readline(&prompt) {
Ok(line) => match line.as_str() {
"!help" => println!("{TXT_WELCOME}"),
"exit" => break,
@ -102,7 +105,25 @@ fn repl<C: IsConnection>(mut con: C) -> CliResult<()> {
continue;
}
match query::Parameterizer::new(line).parameterize() {
Ok(q) => resp::format_response(con.execute_query(q)?)?,
Ok(q) => {
let mut new_prompt = None;
let q = match q {
ExecKind::Standard(q) => q,
ExecKind::UseNull(q) => {
new_prompt = Some("> ".into());
q
}
ExecKind::UseSpace(q, space) => {
new_prompt = Some(format!("{space}> "));
q
}
};
if resp::format_response(con.execute_query(q)?)? {
if let Some(pr) = new_prompt {
prompt = pr;
}
}
}
Err(e) => match e {
CliError::QueryError(e) => {
eprintln!("[skysh error]: bad query. {e}");

@ -34,10 +34,13 @@ use {
std::io::{self, Write},
};
pub fn format_response(resp: Response) -> CliResult<()> {
pub fn format_response(resp: Response) -> CliResult<bool> {
match resp {
Response::Empty => print_cyan("(Okay)\n")?,
Response::Error(e) => print_red(&format!("(server error code: {e})\n"))?,
Response::Error(e) => {
print_red(&format!("(server error code: {e})\n"))?;
return Ok(false);
}
Response::Value(v) => {
print_value(v)?;
println!();
@ -47,7 +50,7 @@ pub fn format_response(resp: Response) -> CliResult<()> {
println!();
}
};
Ok(())
Ok(true)
}
fn print_row(r: Row) -> CliResult<()> {

@ -28,7 +28,7 @@ use crate::engine::{
core::{dml, model::Model, space::Space},
error::{QueryError, QueryResult},
fractal::{Global, GlobalInstanceLike},
net::protocol::{ClientLocalState, Response, SQuery},
net::protocol::{ClientLocalState, Response, ResponseType, SQuery},
ql::{
ast::{traits::ASTNode, InplaceData, State},
ddl::Use,
@ -162,6 +162,20 @@ fn cstate_use(
}
cstate.set_cs(new_space.boxed_str());
}
Use::RefreshCurrent => match cstate.get_cs() {
None => return Ok(Response::Null),
Some(space) => {
if !global.namespace().contains_space(space) {
cstate.unset_cs();
return Err(QueryError::QExecObjectNotFound);
}
return Ok(Response::Serialized {
ty: ResponseType::String,
size: space.len(),
data: space.to_owned().into_bytes(),
});
}
},
}
Ok(Response::Empty)
}

@ -113,6 +113,7 @@ impl ClientLocalState {
#[derive(Debug, PartialEq)]
pub enum Response {
Empty,
Null,
Serialized {
ty: ResponseType,
size: usize,
@ -190,6 +191,7 @@ pub(super) async fn query_loop<S: Socket>(
con.write_u8(b'\n').await?;
con.write_all(&data).await?;
}
Ok(Response::Null) => con.write_u8(ResponseType::Null.value_u8()).await?,
Err(e) => {
let [a, b] = (e.value_u8() as u16).to_le_bytes();
con.write_all(&[ResponseType::Error.value_u8(), a, b])

@ -41,24 +41,34 @@ use {
#[derive(Debug, PartialEq)]
pub enum Use<'a> {
Space(Ident<'a>),
RefreshCurrent,
Null,
}
impl<'a> ASTNode<'a> for Use<'a> {
const MUST_USE_FULL_TOKEN_RANGE: bool = true;
const VERIFIES_FULL_TOKEN_RANGE_USAGE: bool = true;
const VERIFIES_FULL_TOKEN_RANGE_USAGE: bool = false;
fn __base_impl_parse_from_state<Qd: super::ast::QueryData<'a>>(
state: &mut super::ast::State<'a, Qd>,
) -> crate::engine::error::QueryResult<Self> {
/*
should have either an ident or null
*/
if state.remaining() != 1 {
if state.exhausted() | (state.remaining() > 2) {
return Err(QueryError::QLInvalidSyntax);
}
Ok(match state.fw_read() {
Token::Ident(new_space) => Self::Space(*new_space),
Token![null] => Self::Null,
Token::Ident(id) => Self::Space(id.clone()),
Token![$] => {
if state.exhausted() {
return Err(QueryError::QLInvalidSyntax);
}
match state.fw_read() {
Token::Ident(id) if id.eq_ignore_ascii_case("current") => Self::RefreshCurrent,
_ => return Err(QueryError::QLInvalidSyntax),
}
}
_ => return Err(QueryError::QLInvalidSyntax),
})
}

@ -73,3 +73,13 @@ fn use_null() {
let mut state = State::new_inplace(&t[1..]);
assert_eq!(Use::test_parse_from_state(&mut state).unwrap(), Use::Null);
}
#[test]
fn use_current() {
let t = lex_insecure(b"use $current").unwrap();
let mut state = State::new_inplace(&t[1..]);
assert_eq!(
Use::test_parse_from_state(&mut state).unwrap(),
Use::RefreshCurrent
);
}

Loading…
Cancel
Save