Implement Close command to close current DB.
* Closes existing open db and opens new in memory db
This commit is contained in:
parent
f3d39d4194
commit
45d00c43ac
4 changed files with 140 additions and 32 deletions
|
@ -8,12 +8,13 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use combine::{eof, many, many1, sep_by, skip_many, token, Parser};
|
||||
use combine::{any, eof, many, many1, sep_by, skip_many, token, Parser};
|
||||
use combine::combinator::{choice, try};
|
||||
use combine::char::{alpha_num, space, string};
|
||||
use combine::char::{space, string};
|
||||
|
||||
pub static HELP_COMMAND: &'static str = &"help";
|
||||
pub static OPEN_COMMAND: &'static str = &"open";
|
||||
pub static CLOSE_COMMAND: &'static str = &"close";
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Command {
|
||||
|
@ -21,6 +22,7 @@ pub enum Command {
|
|||
Query(Vec<String>),
|
||||
Help(Vec<String>),
|
||||
Open(String),
|
||||
Close,
|
||||
Err(String),
|
||||
}
|
||||
|
||||
|
@ -29,29 +31,50 @@ impl Command {
|
|||
match self {
|
||||
&Command::Query(_) |
|
||||
&Command::Transact(_) => false,
|
||||
_ => true
|
||||
&Command::Help(_) |
|
||||
&Command::Open(_) |
|
||||
&Command::Close |
|
||||
&Command::Err(_) => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(s: &str) -> Command {
|
||||
let help_parser = string(HELP_COMMAND).and(skip_many(space())).and(sep_by::<Vec<_>, _, _>(many1::<Vec<_>, _>(alpha_num()), token(' '))).map(|x| {
|
||||
let args: Vec<String> = x.1.iter().map(|v| v.iter().collect() ).collect();
|
||||
let help_parser = string(HELP_COMMAND)
|
||||
.and(skip_many(space()))
|
||||
.and(many::<Vec<_>, _>(try(any())))
|
||||
.map(|x| {
|
||||
let remainder: String = x.1.iter().collect();
|
||||
let args: Vec<String> = remainder.split(" ").filter_map(|s| if s.is_empty() { None } else { Some(s.to_string())}).collect();
|
||||
Command::Help(args)
|
||||
});
|
||||
|
||||
let open_parser = string(OPEN_COMMAND).and(space()).and(many1::<Vec<_>, _>(alpha_num()).and(eof())).map(|x| {
|
||||
let arg: String = (x.1).0.iter().collect();
|
||||
Command::Open(arg)
|
||||
let open_parser = string(OPEN_COMMAND)
|
||||
.and(skip_many(space()))
|
||||
.and(many1::<Vec<_>, _>(try(any())))
|
||||
.map(|x| {
|
||||
let remainder: String = x.1.iter().collect();
|
||||
let args: Vec<String> = remainder.split(" ").filter_map(|s| if s.is_empty() { None } else { Some(s.to_string())}).collect();
|
||||
if args.len() > 1 {
|
||||
return Command::Err(format!("Unrecognized argument {:?}", (&args[1]).clone()));
|
||||
}
|
||||
Command::Open((&args[0]).clone())
|
||||
});
|
||||
|
||||
token('.')
|
||||
.and(choice::<[&mut Parser<Input = _, Output = Command>; 2], _>
|
||||
let close_parser = string(CLOSE_COMMAND)
|
||||
.and(skip_many(space()))
|
||||
.map( |_| Command::Close );
|
||||
|
||||
skip_many(space())
|
||||
.and(token('.'))
|
||||
.and(choice::<[&mut Parser<Input = _, Output = Command>; 3], _>
|
||||
([&mut try(help_parser),
|
||||
&mut try(open_parser),]))
|
||||
&mut try(open_parser),
|
||||
&mut try(close_parser),]))
|
||||
.skip(eof())
|
||||
.parse(s)
|
||||
.map(|x| x.0)
|
||||
.unwrap_or(('0', Command::Err(format!("Invalid command {:?}", s)))).1
|
||||
.unwrap_or((((), '0'), Command::Err(format!("Invalid command {:?}", s)))).1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -70,6 +93,18 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help_parser_dot_arg() {
|
||||
let input = ".help .command1";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Help(args) => {
|
||||
assert_eq!(args, vec![".command1"]);
|
||||
},
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help_parser_no_args() {
|
||||
let input = ".help";
|
||||
|
@ -102,7 +137,7 @@ mod tests {
|
|||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Err(message) => {
|
||||
assert_eq!(message, format!("Invalid command {:?}", input));
|
||||
assert_eq!(message, "Unrecognized argument \"database2\"");
|
||||
},
|
||||
_ => assert!(false)
|
||||
}
|
||||
|
@ -120,6 +155,30 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_parser_path_arg() {
|
||||
let input = ".open /path/to/my.db";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Open(arg) => {
|
||||
assert_eq!(arg, "/path/to/my.db".to_string());
|
||||
},
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_parser_file_arg() {
|
||||
let input = ".open my.db";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Open(arg) => {
|
||||
assert_eq!(arg, "my.db".to_string());
|
||||
},
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_parser_no_args() {
|
||||
let input = ".open";
|
||||
|
@ -132,6 +191,48 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_parser_with_args() {
|
||||
let input = ".close arg1";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Err(message) => {
|
||||
assert_eq!(message, format!("Invalid command {:?}", input));
|
||||
},
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_parser_no_args() {
|
||||
let input = ".close";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Close => assert!(true),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_parser_no_args_trailing_whitespace() {
|
||||
let input = ".close ";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Close => assert!(true),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parser_preceeding_trailing_whitespace() {
|
||||
let input = " .close ";
|
||||
let cmd = command(&input);
|
||||
match cmd {
|
||||
Command::Close => assert!(true),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_parser_no_dot() {
|
||||
let input = "help command1 command2";
|
||||
|
|
|
@ -28,9 +28,8 @@ pub enum InputResult {
|
|||
More(Command),
|
||||
/// End of file reached
|
||||
Eof,
|
||||
/// Error while parsing input; a Rust parsing error will have printed out
|
||||
/// error messages and therefore contain no error message.
|
||||
InputError(Option<String>),
|
||||
/// Error while parsing input;
|
||||
InputError(String),
|
||||
}
|
||||
|
||||
/// Reads input from `stdin`
|
||||
|
|
|
@ -66,9 +66,7 @@ impl Repl {
|
|||
break;
|
||||
},
|
||||
InputError(err) => {
|
||||
if let Some(err) = err {
|
||||
println!("{}", err);
|
||||
}
|
||||
more = None;
|
||||
},
|
||||
};
|
||||
|
@ -82,6 +80,7 @@ impl Repl {
|
|||
Command::Open(db) => {
|
||||
self.store.open(Some(db));
|
||||
},
|
||||
Command::Close => self.store.close(),
|
||||
Command::Err(message) => println!("{}", message),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
@ -93,7 +92,10 @@ impl Repl {
|
|||
println!(".{} - {}", cmd, msg);
|
||||
}
|
||||
} else {
|
||||
for arg in args {
|
||||
for mut arg in args {
|
||||
if arg.chars().nth(0).unwrap() == '.' {
|
||||
arg.remove(0);
|
||||
}
|
||||
let msg = COMMAND_HELP.get(arg.as_str());
|
||||
if msg.is_some() {
|
||||
println!(".{} - {}", arg, msg.unwrap());
|
||||
|
|
|
@ -18,28 +18,34 @@ use mentat::conn::Conn;
|
|||
pub struct Store {
|
||||
handle: rusqlite::Connection,
|
||||
conn: Conn,
|
||||
db_name: String,
|
||||
}
|
||||
|
||||
fn db_output_name(db_name: &String) -> String {
|
||||
if db_name.is_empty() { "in memory db".to_string() } else { db_name.clone() }
|
||||
if db_name.is_empty() { "in-memory db".to_string() } else { db_name.clone() }
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub fn new(database: Option<String>) -> Store {
|
||||
let db_name = database.unwrap_or("".to_string());
|
||||
let output_name = db_output_name(&db_name);
|
||||
let mut handle = new_connection(db_name).expect("Couldn't open conn.");
|
||||
let mut handle = new_connection(&db_name).expect("Couldn't open conn.");
|
||||
let conn = Conn::connect(&mut handle).expect("Couldn't open DB.");
|
||||
println!("Database {:?} opened", output_name);
|
||||
Store { handle, conn }
|
||||
println!("Database {:?} opened", db_output_name(&db_name));
|
||||
Store { handle, conn, db_name }
|
||||
}
|
||||
|
||||
pub fn open(&mut self, database: Option<String>) {
|
||||
let db_name = database.unwrap_or("".to_string());
|
||||
let output_name = db_output_name(&db_name);
|
||||
self.handle = new_connection(db_name).expect("Couldn't open conn.");
|
||||
self.db_name = database.unwrap_or("".to_string());
|
||||
self.handle = new_connection(&self.db_name).expect("Couldn't open conn.");
|
||||
self.conn = Conn::connect(&mut self.handle).expect("Couldn't open DB.");
|
||||
println!("Database {:?} opened", output_name);
|
||||
println!("Database {:?} opened", db_output_name(&self.db_name));
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
self.handle = new_connection("").expect("Couldn't close conn.");
|
||||
self.conn = Conn::connect(&mut self.handle).expect("Couldn't close DB.");
|
||||
println!("Database {:?} closed", db_output_name(&self.db_name));
|
||||
self.db_name = "".to_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue