Skip to content

Commit

Permalink
Syntax changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Kakapio committed Apr 7, 2024
1 parent 76ea8b2 commit dc03ab5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 63 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
# rust-sql
# rust-sql

To do:
Custom row types defined through JSON.
HTTP connectivity support.
Include a SQL Driver to test out connectivity. Likely written in GoLang.

Stretch goals:
Custom CLI GUI.
Multiple tables in database.
47 changes: 24 additions & 23 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ use std::process::exit;

#[derive(PartialEq, Debug, Default)]
pub enum ExecuteResult {
SUCCESS,
Success,
#[default]
TABLE_FULL,
TableFull,
}

/// Represents a single SQL table.
pub struct Table {
pub data: Vec<Row>,
}
Expand All @@ -20,83 +21,82 @@ impl Table {
}

pub fn entrypoint() {
let stdin = io::stdin(); // binding a handle.
let stdin = io::stdin();
let mut table = Table::new();

loop
// same as while(true)
{
loop {
let mut input = String::new();

println!("Please enter the SQL command: ");
stdin.read_line(&mut input).expect("Failed to read line.");
input = input.trim().to_string(); // remove trailing newline.
input = input.trim().to_string(); // Remove trailing newline.

// Is a command
if input.starts_with('.') {
match execute_command(&input) {
MetaCommandResult::SUCCESS => {
continue;
} // Executed command, get next input.
MetaCommandResult::UNRECOGNIZED => {
MetaCommandResult::Success => {
continue; // Executed command, get next input.
}
MetaCommandResult::Unrecognized => {
println!("Unrecognized command: {}", input);
continue; // skip this iteration of our IO loop.
continue; // Skip this iteration of our IO loop.
}
}
}

let mut statement = Statement::default();

match prepare_statement(&input, &mut statement) {
PrepareResult::SUCCESS => {
PrepareResult::Success => {
println!("Successfully prepared statement...")
}
PrepareResult::UNRECOGNIZED => {
PrepareResult::Unrecognized => {
println!("Unrecognized keyword at start of {}", input);
continue;
}
PrepareResult::SYNTAX_ERROR => {
PrepareResult::SyntaxError => {
println!("Unrecognized syntax for command. Did you follow the proper format?");
continue;
}
}

match execute_statement(statement, &mut table) {
ExecuteResult::SUCCESS => {
ExecuteResult::Success => {
println!("Successfully executed...")
}
ExecuteResult::TABLE_FULL => {
ExecuteResult::TableFull => {
println!("Table is full...")
}
}
}
}

/// Used to execute non-sql CLI commands, e.g exit.
pub fn execute_command(cmd: &String) -> MetaCommandResult {
if cmd == ".exit" {
exit(0);
} else {
return MetaCommandResult::UNRECOGNIZED;
return MetaCommandResult::Unrecognized;
}
}

fn execute_statement(statement: Statement, tb: &mut Table) -> ExecuteResult {
match statement.cmd {
StatementType::INSERT => {
StatementType::Insert => {
println!("Performing an insert...");
execute_insert(statement, tb)
}
StatementType::SELECT => {
StatementType::Select => {
println!("Performing a select...");
execute_select(statement, tb)
}
}
}

// Todo: Should I move or borrow statement... I think move?
fn execute_insert(statement: Statement, table: &mut Table) -> ExecuteResult {
table.data.push(statement.row_instance);
ExecuteResult::SUCCESS

ExecuteResult::Success
}

fn execute_select(statement: Statement, table: &mut Table) -> ExecuteResult {
Expand All @@ -105,5 +105,6 @@ fn execute_select(statement: Statement, table: &mut Table) -> ExecuteResult {
println!("Found data: {:?}", row);
}
}
ExecuteResult::SUCCESS

ExecuteResult::Success
}
67 changes: 38 additions & 29 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
use scan_fmt::*;

/// The execution result of a non-SQL command.
#[derive(PartialEq, Debug, Default)]
pub enum MetaCommandResult {
SUCCESS,
Success,
#[default]
UNRECOGNIZED,
Unrecognized,
}

/// The result of parsing a statement and converting it to virtual machine bytecode.
#[derive(PartialEq, Debug, Default)]
pub enum PrepareResult {
SUCCESS,
Success,
#[default]
UNRECOGNIZED,
SYNTAX_ERROR,
Unrecognized,
SyntaxError,
}

/// The SQL statements we have available to the user.
#[derive(PartialEq, Debug, Default)]
pub enum StatementType {
INSERT,
Insert,
#[default]
SELECT,
Select,
}

/// A particular statement with its corresponding data.
#[derive(PartialEq, Debug, Default)]
pub struct Statement {
pub cmd: StatementType,
Expand All @@ -36,30 +40,35 @@ pub struct Row {
}

pub fn prepare_statement(cmd: &String, statement: &mut Statement) -> PrepareResult {
// First six chars are insert. We use a substring since this is followed by data.
if cmd.len() >= 6 && &cmd[0..6] == "insert" {
statement.cmd = StatementType::INSERT;
// Use fall-through logic here in the future.
if cmd.len() >= 6 {
// First six chars are insert. We use a substring since this is followed by data.
if &cmd[0..6] == "insert" {
statement.cmd = StatementType::Insert;

// This is how we take our formatted string and put it into variables.
let (id, username, email) = match scan_fmt!(cmd, "insert {} {} {}", u32, String, String) {
Ok((id, username, email)) => (id, username, email),
Err(_) => {
println!("Parsing error");
return PrepareResult::SYNTAX_ERROR;
}
};
// This is how we take our formatted string and put it into variables.
let (id, username, email) = match scan_fmt!(cmd, "insert {} {} {}", u32, String, String)
{
Ok((id, username, email)) => (id, username, email),
Err(_) => {
println!("Parsing error");
return PrepareResult::SyntaxError;
}
};

statement.row_instance = Row {
id,
username,
email,
};
return PrepareResult::SUCCESS;
}
if cmd == "select" {
statement.cmd = StatementType::SELECT;
return PrepareResult::SUCCESS;
statement.row_instance = Row {
id,
username,
email,
};
return PrepareResult::Success;
}
// This can be either 'select' returning all, or 'select 2' return item with ID 2.
else if &cmd[0..6] == "select" {
statement.cmd = StatementType::Select;
return PrepareResult::Success;
}
}

return PrepareResult::UNRECOGNIZED;
return PrepareResult::Unrecognized;
}
18 changes: 8 additions & 10 deletions src/tests/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::parser::*;
fn execute_command_unrecognized() {
let cmd = String::from(".dummy");
let out = execute_command(&cmd);
assert_eq!(out, MetaCommandResult::UNRECOGNIZED);
assert_eq!(out, MetaCommandResult::Unrecognized);
}

// Testing whether the enum is set properly.
Expand All @@ -15,7 +15,7 @@ fn prepare_statement_set_insert() {
let mut out_statement = Statement::default();
let cmd = String::from("insert");
prepare_statement(&cmd, &mut out_statement);
assert_eq!(out_statement.cmd, StatementType::INSERT);
assert_eq!(out_statement.cmd, StatementType::Insert);
}

// Testing whether the enum is set properly.
Expand All @@ -24,25 +24,23 @@ fn prepare_statement_set_select() {
let mut out_statement = Statement::default();
let cmd = String::from("select");
prepare_statement(&cmd, &mut out_statement);
assert_eq!(out_statement.cmd, StatementType::SELECT);
assert_eq!(out_statement.cmd, StatementType::Select);
}

// Testing whether the output result is correct.
#[test]
fn prepare_statement_out_success() {
let mut out_statement = Statement::default();
let cmd = String::from("insert 10 monkeylover [email protected]");
let out_result = prepare_statement(&cmd, &mut out_statement);
assert_eq!(out_result, PrepareResult::SUCCESS);
let out_result = prepare_statement(&cmd, &mut Statement::default());
assert_eq!(out_result, PrepareResult::Success);
}

// Testing whether the output result handles bad commands.
#[test]
fn prepare_statement_out_failure() {
let mut out_statement = Statement::default();
let cmd = String::from("dummy");
let out_result = prepare_statement(&cmd, &mut out_statement);
assert_eq!(out_result, PrepareResult::UNRECOGNIZED);
let out_result = prepare_statement(&cmd, &mut Statement::default());
assert_eq!(out_result, PrepareResult::Unrecognized);
}

// Testing whether the insert syntax error is handled.
Expand All @@ -51,7 +49,7 @@ fn prepare_statement_out_syntax_error() {
let mut out_statement = Statement::default();
let cmd = String::from("insert");
let out_result = prepare_statement(&cmd, &mut out_statement);
assert_eq!(out_result, PrepareResult::SYNTAX_ERROR);
assert_eq!(out_result, PrepareResult::SyntaxError);
}

// Testing whether the parsing works.
Expand Down

0 comments on commit dc03ab5

Please sign in to comment.