REPL implementation based on contribution: https://github.com/cozodb/cozo/issues/31

main
Ziyang Hu 2 years ago
parent 09cd9cb962
commit 2b4a0fc7a8

175
Cargo.lock generated

@ -474,6 +474,17 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "clipboard-win"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219"
dependencies = [
"error-code",
"str-buf",
"winapi",
]
[[package]]
name = "cmake"
version = "0.1.49"
@ -658,8 +669,11 @@ dependencies = [
"cozo",
"env_logger",
"log",
"miette",
"prettytable",
"rand 0.8.5",
"rouille",
"rustyline",
"serde",
"serde_derive",
"serde_json",
@ -844,6 +858,27 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if 1.0.0",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "document-features"
version = "0.2.7"
@ -859,6 +894,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "encode_unicode"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "encoding_rs"
version = "0.8.31"
@ -868,6 +909,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "endian-type"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
[[package]]
name = "env_logger"
version = "0.10.0"
@ -902,6 +949,16 @@ dependencies = [
"libc",
]
[[package]]
name = "error-code"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
dependencies = [
"libc",
"str-buf",
]
[[package]]
name = "fail"
version = "0.4.0"
@ -928,6 +985,17 @@ dependencies = [
"instant",
]
[[package]]
name = "fd-lock"
version = "3.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb21c69b9fea5e15dbc1049e4b77145dd0ba1c84019c488102de0dc4ea4b0a27"
dependencies = [
"cfg-if 1.0.0",
"rustix",
"windows-sys 0.42.0",
]
[[package]]
name = "filetime"
version = "0.2.19"
@ -1882,6 +1950,26 @@ dependencies = [
"smallvec",
]
[[package]]
name = "nibble_vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
dependencies = [
"smallvec",
]
[[package]]
name = "nix"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"libc",
]
[[package]]
name = "nom"
version = "5.1.2"
@ -2309,6 +2397,20 @@ dependencies = [
"syn",
]
[[package]]
name = "prettytable"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46480520d1b77c9a3482d39939fcf96831537a250ec62d4fd8fbdf8e0302e781"
dependencies = [
"csv",
"encode_unicode",
"is-terminal",
"lazy_static",
"term",
"unicode-width",
]
[[package]]
name = "priority-queue"
version = "1.3.0"
@ -2585,6 +2687,16 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radix_trie"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
dependencies = [
"endian-type",
"nibble_vec",
]
[[package]]
name = "rand"
version = "0.7.3"
@ -2687,6 +2799,17 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom 0.2.8",
"redox_syscall",
"thiserror",
]
[[package]]
name = "regex"
version = "1.7.0"
@ -2866,6 +2989,35 @@ dependencies = [
"webpki",
]
[[package]]
name = "rustversion"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "rustyline"
version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1cd5ae51d3f7bf65d7969d579d502168ef578f289452bd8ccc91de28fda20e"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"clipboard-win",
"dirs-next",
"fd-lock",
"libc",
"log",
"memchr",
"nix",
"radix_trie",
"scopeguard",
"unicode-segmentation",
"unicode-width",
"utf8parse",
"winapi",
]
[[package]]
name = "ryu"
version = "1.0.12"
@ -3142,6 +3294,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "str-buf"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
[[package]]
name = "strsim"
version = "0.10.0"
@ -3263,6 +3421,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
@ -3679,6 +3848,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "uuid"
version = "1.2.2"

@ -52,3 +52,6 @@ serde_derive = "1.0.137"
serde = { version = "1.0.137" }
chrono = "0.4.19"
serde_json = "1.0.81"
prettytable = "0.10.0"
rustyline = "10.0.0"
miette = { version = "5.5.0", features = ["fancy"] }

@ -26,6 +26,12 @@ see `./cozoserver -h`
To stop Cozo, press `CTRL-C`, or send `SIGTERM` to the process with e.g. `kill`.
## The REPL
If you start the server with the `-r` or `--repl` option, a web server will not be started.
Instead, a terminal-based REPL is presented for you. The engine options can be used when
invoking the executable to choose the backend.
## The query API
Queries are run by sending HTTP POST requests to the server.

@ -10,6 +10,7 @@ use std::collections::BTreeMap;
use std::fmt::Debug;
use std::fs;
use std::net::Ipv6Addr;
use std::process::exit;
use std::str::FromStr;
use clap::Parser;
@ -21,6 +22,10 @@ use serde_json::json;
use cozo::*;
use crate::repl::repl_main;
mod repl;
#[derive(Parser, Debug)]
#[clap(version, about, long_about = None)]
struct Args {
@ -40,6 +45,10 @@ struct Args {
#[clap(short, long, default_value_t = String::from("{}"))]
config: String,
/// When on, start REPL instead of starting a webserver
#[clap(short, long)]
repl: bool,
/// Address to bind the service to
#[clap(short, long, default_value_t = String::from("127.0.0.1"))]
bind: String,
@ -80,6 +89,17 @@ fn main() {
db.restore_backup(restore_path).unwrap();
}
if args.repl {
if let Err(e) = repl_main(db) {
eprintln!("{}", e);
exit(-1);
}
} else {
server_main(args, db)
}
}
fn server_main(args: Args, db: DbInstance) {
let conf_path = format!("{}.{}.cozo_auth", args.path, args.engine);
let auth_guard = match fs::read_to_string(&conf_path) {
Ok(s) => s.trim().to_string(),

@ -0,0 +1,113 @@
/*
* Copyright 2022, The Cozo Project Authors.
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// This file is based on code contributed by https://github.com/rhn
use std::error::Error;
use prettytable;
use rustyline;
use cozo;
use cozo::DbInstance;
struct Indented;
impl rustyline::hint::Hinter for Indented {
type Hint = String;
}
impl rustyline::highlight::Highlighter for Indented {}
impl rustyline::completion::Completer for Indented {
type Candidate = String;
fn update(
&self,
_line: &mut rustyline::line_buffer::LineBuffer,
_start: usize,
_elected: &str,
) {
unreachable!();
}
}
impl rustyline::Helper for Indented {}
impl rustyline::validate::Validator for Indented {
fn validate(
&self,
ctx: &mut rustyline::validate::ValidationContext<'_>,
) -> rustyline::Result<rustyline::validate::ValidationResult> {
Ok(if ctx.input().starts_with(" ") {
if ctx.input().ends_with("\n") {
rustyline::validate::ValidationResult::Valid(None)
} else {
rustyline::validate::ValidationResult::Incomplete
}
} else {
rustyline::validate::ValidationResult::Valid(None)
})
}
}
pub(crate) fn repl_main(db: DbInstance) -> Result<(), Box<dyn Error>> {
let mut exit = false;
let mut rl = rustyline::Editor::<Indented>::new()?;
rl.set_helper(Some(Indented));
loop {
let readline = rl.readline("=> ");
match readline {
Ok(line) => {
match db.run_script(&line, Default::default()) {
Ok(out) => {
use prettytable::format;
let mut table = prettytable::Table::new();
let headers = out
.headers
.iter()
.map(prettytable::Cell::from)
.collect::<Vec<_>>();
table.set_titles(prettytable::Row::new(headers));
let rows = out
.rows
.iter()
.map(|r| r.iter().map(|c| format!("{}", c)).collect::<Vec<_>>())
.collect::<Vec<_>>();
let rows = rows
.iter()
.map(|r| r.iter().map(prettytable::Cell::from).collect::<Vec<_>>());
for row in rows {
table.add_row(prettytable::Row::new(row));
}
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
table.printstd();
}
Err(mut err) => {
if err.source_code().is_none() {
err = err.with_source_code(line.to_string());
}
eprintln!("{:?}", err);
}
};
rl.add_history_entry(line);
}
Err(rustyline::error::ReadlineError::Interrupted) => {
if exit {
break;
} else {
println!("Again to exit");
exit = true;
}
}
Err(rustyline::error::ReadlineError::Eof) => break,
Err(e) => eprintln!("{:?}", e),
}
}
Ok(())
}
Loading…
Cancel
Save