skysh: Add `--eval` for running queries directly

next
Sayan Nandan 7 months ago
parent 2670e5a974
commit ebd04a557e
No known key found for this signature in database
GPG Key ID: 0EBD769024B24F0A

@ -14,6 +14,7 @@ OPTIONS:
--user Set the user for this client session
--password Set the password for this client session
--tls-cert Set the TLS certificate to use (for TLS endpoints)
--eval Execute and print the query (password must be set)
NOTES:
- skysh will also look for the `{password_env_var}` environment variable

@ -68,6 +68,7 @@ pub enum ClientConfigKind {
pub enum Task {
HelpMessage(String),
OpenShell(ClientConfig),
ExecOnce(ClientConfig, String),
}
enum TaskInner {
@ -156,10 +157,13 @@ pub fn parse() -> CliResult<Task> {
}
}
};
let eval = args.remove("--eval");
if args.is_empty() {
Ok(Task::OpenShell(ClientConfig::new(
endpoint, username, password,
)))
let client = ClientConfig::new(endpoint, username, password);
match eval {
Some(query) => Ok(Task::ExecOnce(client, query)),
None => Ok(Task::OpenShell(client)),
}
} else {
Err(CliError::ArgsErr(format!("found unknown arguments")))
}

@ -50,6 +50,16 @@ fn run() -> error::CliResult<()> {
match args::parse()? {
Task::HelpMessage(msg) => println!("{msg}"),
Task::OpenShell(cfg) => repl::start(cfg)?,
Task::ExecOnce(cfg, query) => {
let query = skytable::query!(query);
let resp = query::connect(
cfg,
false,
|mut c| Ok(c.query(&query)),
|mut c| Ok(c.query(&query)),
)??;
resp::format_response(resp, false, false);
}
}
Ok(())
}

@ -25,12 +25,46 @@
*/
use {
crate::error::{CliError, CliResult},
crate::{
args::{ClientConfig, ClientConfigKind},
error::{CliError, CliResult},
},
skytable::{
error::ClientResult, query::SQParam, response::Response, Connection, ConnectionTls, Query,
error::ClientResult, query::SQParam, response::Response, Config, Connection, ConnectionTls,
Query,
},
};
pub fn connect<T>(
cfg: ClientConfig,
print_con_info: bool,
tcp_f: impl Fn(Connection) -> CliResult<T>,
tls_f: impl Fn(ConnectionTls) -> CliResult<T>,
) -> CliResult<T> {
match cfg.kind {
ClientConfigKind::Tcp(host, port) => {
let c = Config::new(&host, port, &cfg.username, &cfg.password).connect()?;
if print_con_info {
println!(
"Authenticated as '{}' on {}:{} over Skyhash/TCP\n---",
&cfg.username, &host, &port
);
}
tcp_f(c)
}
ClientConfigKind::Tls(host, port, cert) => {
let c = Config::new(&host, port, &cfg.username, &cfg.password).connect_tls(&cert)?;
if print_con_info {
println!(
"Authenticated as '{}' on {}:{} over Skyhash/TLS\n---",
&cfg.username, &host, &port
);
}
tls_f(c)
}
}
}
pub trait IsConnection {
fn execute_query(&mut self, q: Query) -> ClientResult<Response>;
}

@ -24,18 +24,15 @@
*
*/
use crate::query::ExecKind;
use {
crate::{
args::{ClientConfig, ClientConfigKind},
args::ClientConfig,
error::{CliError, CliResult},
query::{self, IsConnection},
query::{self, ExecKind, IsConnection},
resp,
},
crossterm::{cursor, execute, terminal},
rustyline::{config::Configurer, error::ReadlineError, DefaultEditor},
skytable::Config,
std::io::{stdout, ErrorKind},
};
@ -43,24 +40,7 @@ const SKYSH_HISTORY_FILE: &str = ".sky_history";
const TXT_WELCOME: &str = include_str!("../help_text/welcome");
pub fn start(cfg: ClientConfig) -> CliResult<()> {
match cfg.kind {
ClientConfigKind::Tcp(host, port) => {
let c = Config::new(&host, port, &cfg.username, &cfg.password).connect()?;
println!(
"Authenticated as '{}' on {}:{} over Skyhash/TCP\n---",
&cfg.username, &host, &port
);
repl(c)
}
ClientConfigKind::Tls(host, port, cert) => {
let c = Config::new(&host, port, &cfg.username, &cfg.password).connect_tls(&cert)?;
println!(
"Authenticated as '{}' on {}:{} over Skyhash/TLS\n---",
&cfg.username, &host, &port
);
repl(c)
}
}
query::connect(cfg, true, repl, repl)
}
fn repl<C: IsConnection>(mut con: C) -> CliResult<()> {
@ -123,7 +103,7 @@ fn repl<C: IsConnection>(mut con: C) -> CliResult<()> {
q
}
};
if resp::format_response(con.execute_query(q)?, special) {
if resp::format_response(con.execute_query(q)?, special, true) {
if let Some(pr) = new_prompt {
prompt = pr;
}

@ -29,28 +29,43 @@ use {
skytable::response::{Response, Row, Value},
};
pub fn format_response(resp: Response, print_special: bool) -> bool {
macro_rules! pprint {
($pretty:expr, $base:literal$(.$f:ident())*) => {
if $pretty {
let pretty = $base$(.$f())*;
println!("{}", pretty);
} else {
println!("{}", $base);
}
}
}
pub fn format_response(resp: Response, print_special: bool, pretty_format: bool) -> bool {
match resp {
Response::Empty => println!("{}", "(Okay)".cyan()),
Response::Empty => pprint!(pretty_format, "(Okay)".cyan()),
Response::Error(e) => {
println!("{}", format!("(server error code: {e})").red());
return false;
}
Response::Value(v) => {
print_value(v, print_special);
print_value(v, print_special, pretty_format);
println!();
}
Response::Row(r) => {
print_row(r);
print_row(r, pretty_format);
println!();
}
Response::Rows(rows) => {
if rows.is_empty() {
println!("{}", "[0 rows returned]".grey().italic());
pprint!(pretty_format, "[0 rows returned]".grey().italic());
} else {
for (i, row) in rows.into_iter().enumerate().map(|(i, r)| (i + 1, r)) {
print!("{} ", format!("({i})").grey().bold());
print_row(row);
if pretty_format {
println!("{}", "({i})".grey().bold())
} else {
println!("({i})")
}
print_row(row, pretty_format);
println!();
}
}
@ -59,11 +74,11 @@ pub fn format_response(resp: Response, print_special: bool) -> bool {
true
}
fn print_row(r: Row) {
fn print_row(r: Row, pretty_format: bool) {
print!("(");
let mut columns = r.into_values().into_iter().peekable();
while let Some(cell) = columns.next() {
print_value(cell, false);
print_value(cell, false, pretty_format);
if columns.peek().is_some() {
print!(", ");
}
@ -71,10 +86,10 @@ fn print_row(r: Row) {
print!(")");
}
fn print_value(v: Value, print_special: bool) {
fn print_value(v: Value, print_special: bool, pretty_format: bool) {
match v {
Value::Null => print!("{}", "null".grey().italic()),
Value::String(s) => print_string(&s, print_special),
Value::Null => pprint!(pretty_format, "null".grey().italic()),
Value::String(s) => print_string(&s, print_special, pretty_format),
Value::Binary(b) => print_binary(&b),
Value::Bool(b) => print!("{b}"),
Value::UInt8(i) => print!("{i}"),
@ -91,7 +106,7 @@ fn print_value(v: Value, print_special: bool) {
print!("[");
let mut items = items.into_iter().peekable();
while let Some(item) = items.next() {
print_value(item, print_special);
print_value(item, print_special, pretty_format);
if items.peek().is_some() {
print!(", ");
}
@ -113,7 +128,10 @@ fn print_binary(b: &[u8]) {
print!("]");
}
fn print_string(s: &str, print_special: bool) {
fn print_string(s: &str, print_special: bool, pretty_format: bool) {
if !pretty_format {
print!("{s}");
} else {
if print_special {
print!("{}", s.italic().grey());
} else {
@ -131,4 +149,5 @@ fn print_string(s: &str, print_special: bool) {
}
print!("\"");
}
}
}

Loading…
Cancel
Save