Skip to content

Commit 2b9a8e9

Browse files
committed
Added UnknownCommand error; Refactored RELP, SQL and MetaCommand modules; Refactored main.rs to be cleaner and moremodular also. Started Parser implementation. Still working in progress, since I am still experimenting with the design
1 parent 8a401ee commit 2b9a8e9

File tree

9 files changed

+300
-165
lines changed

9 files changed

+300
-165
lines changed

src/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub enum SQLRiteError {
1717
General(String),
1818
Internal(String),
1919
SqlError(ParserError),
20+
UnknownCommand(String),
2021
// IoError(io::Error),
2122
}
2223

@@ -57,6 +58,7 @@ impl Display for SQLRiteError {
5758
SQLRiteError::SqlError(ref desc) => write!(f, "SQL error: {:?}", desc),
5859
// SQLRiteError::IoError(ref desc) => write!(f, "IO error: {}", desc),
5960
SQLRiteError::Internal(desc) => write!(f, "Internal SQLRite error: {}", desc),
61+
SQLRiteError::UnknownCommand(desc) => write!(f, "Unknown command error: {}", desc),
6062
}
6163
}
6264
}

src/main.rs

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
extern crate clap;
22

3+
mod meta_command;
34
mod repl;
45
mod sql;
56
mod error;
67

7-
use repl::{REPLHelper, get_config};
8-
use repl::meta_command::*;
9-
use sql::*;
8+
use repl::{REPLHelper, get_config, get_command_type, CommandType};
9+
use meta_command::{handle_meta_command};
10+
use sql::{process_command};
1011

1112
use rustyline::error::ReadlineError;
1213
use rustyline::{Editor};
@@ -47,11 +48,8 @@ fn main() -> rustyline::Result<()> {
4748
"Connected to a transient in-memory database.\n",
4849
"Use '.open FILENAME' to reopen on a persistent database.");
4950

50-
// Counter is set to improve user experience and show user how many
51-
// commands he has ran.
52-
let mut count = 1;
5351
loop {
54-
let p = format!("rust-sqlite | {}> ", count);
52+
let p = format!("sqlrite> ");
5553
repl.helper_mut()
5654
.expect("No helper found")
5755
.colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p);
@@ -62,17 +60,19 @@ fn main() -> rustyline::Result<()> {
6260
match readline {
6361
Ok(command) => {
6462
repl.add_history_entry(command.as_str());
65-
if command.starts_with(".") {
66-
let action = get_meta_command(&command);
67-
match action {
68-
Some(response) => println!("{}",response),
69-
None => break,
63+
match get_command_type(&command.trim().to_owned()) {
64+
CommandType::SQLCommand(_cmd) => {
65+
let _ = match process_command(&command) {
66+
Ok(response) => println!("{}",response),
67+
Err(err) => println!("An error occured: {}", err),
68+
};
69+
}
70+
CommandType::MetaCommand(cmd) => {
71+
let _ = match handle_meta_command(cmd) {
72+
Ok(response) => println!("{}",response),
73+
Err(err) => println!("An error occured: {}", err),
74+
};
7075
}
71-
}else{
72-
let _ = match prepare_statement(&command) {
73-
Ok(response) => println!("{}",response),
74-
Err(err) => println!("An error occured: {}", err),
75-
};
7676
}
7777
}
7878
Err(ReadlineError::Interrupted) => {
@@ -86,7 +86,6 @@ fn main() -> rustyline::Result<()> {
8686
break;
8787
}
8888
}
89-
count += 1;
9089
}
9190
repl.append_history("history").unwrap();
9291

src/meta_command/mod.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::error::{Result, SQLRiteError};
2+
3+
use std::fmt;
4+
5+
#[derive(Debug, PartialEq)]
6+
pub enum MetaCommand {
7+
Exit,
8+
Help,
9+
Open(String),
10+
Unknown,
11+
}
12+
13+
/// Trait responsible for translating type into a formated text.
14+
impl fmt::Display for MetaCommand {
15+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16+
match self {
17+
MetaCommand::Exit => f.write_str(".exit"),
18+
MetaCommand::Help => f.write_str(".help"),
19+
MetaCommand::Open(_) => f.write_str(".open"),
20+
MetaCommand::Unknown => f.write_str("Unknown command"),
21+
}
22+
}
23+
}
24+
25+
impl MetaCommand {
26+
pub fn new(command: String) -> MetaCommand {
27+
let args: Vec<&str> = command.split_whitespace().collect();
28+
let cmd = args[0].to_owned();
29+
match cmd.as_ref() {
30+
".exit" => MetaCommand::Exit,
31+
".help" => MetaCommand::Help,
32+
".open" => MetaCommand::Open(command),
33+
_ => MetaCommand::Unknown,
34+
}
35+
}
36+
}
37+
38+
pub fn handle_meta_command(command: MetaCommand) -> Result<String> {
39+
match command {
40+
MetaCommand::Exit => std::process::exit(0),
41+
MetaCommand::Help => {
42+
Ok(format!("{}{}{}{}{}","Special commands:\n",
43+
".help - Display this message\n",
44+
".open <FILENAME> - Reopens a persistent database.\n",
45+
".ast <QUERY> - Show the abstract syntax tree for QUERY.\n",
46+
".exit - Quits this application"))
47+
},
48+
MetaCommand::Open(args) => Ok(format!("To be implemented: {}", args)),
49+
MetaCommand::Unknown => Err(SQLRiteError::UnknownCommand(format!("Unknown command or invalid arguments. Enter '.help'"))),
50+
}
51+
}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use super::*;
56+
57+
#[test]
58+
fn get_meta_command_exit_test() {
59+
let inputed_command = MetaCommand::Help;
60+
61+
let result = handle_meta_command(inputed_command);
62+
assert_eq!(result.is_ok(), true);
63+
}
64+
65+
#[test]
66+
fn get_meta_command_open_test() {
67+
let inputed_command = MetaCommand::Open(".open database.db".to_string());
68+
69+
let result = handle_meta_command(inputed_command);
70+
assert_eq!(result.is_ok(), true);
71+
}
72+
73+
#[test]
74+
fn get_meta_command_unknown_command_test() {
75+
let inputed_command = MetaCommand::Unknown;
76+
77+
let result = handle_meta_command(inputed_command);
78+
assert_eq!(result.is_err(), true);
79+
}
80+
81+
#[test]
82+
fn meta_command_display_trait_test() {
83+
let exit = MetaCommand::Exit;
84+
let help = MetaCommand::Help;
85+
let open = MetaCommand::Open(".open database.db".to_string());
86+
let unknown = MetaCommand::Unknown;
87+
88+
assert_eq!(format!("{}", exit), ".exit");
89+
assert_eq!(format!("{}", help), ".help");
90+
assert_eq!(format!("{}", open), ".open");
91+
assert_eq!(format!("{}", unknown), "Unknown command");
92+
}
93+
}

src/repl/meta_command.rs

-129
This file was deleted.

src/repl/mod.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
pub mod meta_command;
1+
use crate::meta_command::*;
2+
use crate::sql::*;
23

34
use std::{borrow::Cow::{self, Borrowed, Owned}};
45

@@ -11,6 +12,21 @@ use rustyline::validate::{ValidationContext, ValidationResult};
1112
use rustyline::hint::{Hinter, HistoryHinter};
1213
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
1314

15+
/// We have two different types of commands MetaCommand and SQLCommand
16+
#[derive(Debug, PartialEq)]
17+
pub enum CommandType {
18+
MetaCommand(MetaCommand),
19+
SQLCommand(SQLCommand),
20+
}
21+
22+
/// Returns the type of command inputed in the REPL
23+
pub fn get_command_type(command: &String) -> CommandType {
24+
match command.starts_with(".") {
25+
true => CommandType::MetaCommand(MetaCommand::new(command.to_owned())),
26+
false => CommandType::SQLCommand(SQLCommand::new(command.to_owned())),
27+
}
28+
}
29+
1430
// REPL Helper Struct with all functionalities
1531
#[derive(Helper, Completer)]
1632
pub struct REPLHelper {
@@ -100,4 +116,28 @@ pub fn get_config() -> Config {
100116
.edit_mode(EditMode::Emacs)
101117
.output_stream(OutputStreamType::Stdout)
102118
.build()
119+
}
120+
121+
#[cfg(test)]
122+
mod tests {
123+
use super::*;
124+
125+
#[test]
126+
fn get_command_type_meta_command_test() {
127+
let input = String::from(".help");
128+
let expected = CommandType::MetaCommand(MetaCommand::Help);
129+
130+
let result = get_command_type(&input);
131+
assert_eq!(result, expected);
132+
}
133+
134+
#[test]
135+
fn get_command_type_sql_command_test() {
136+
let input = String::from("SELECT * from users;");
137+
let expected = CommandType::SQLCommand(SQLCommand::Unknown(input.clone()));
138+
139+
let result = get_command_type(&input);
140+
assert_eq!(result, expected);
141+
142+
}
103143
}

0 commit comments

Comments
 (0)