#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate uuid;
use serde::Serialize;
use std::str::FromStr;
pub mod node;
pub mod prelude;
pub type ResultList = Vec<Vec<u8>>;
pub type ReturnPkg = (
Option<[u8; 16]>,
Option<String>,
Option<Vec<u8>>,
Option<ResultList>,
Option<Vec<String>>,
);
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum KeyWord {
Unknown,
Archive,
First,
From,
Insert,
Into,
Last,
Limit,
Select,
Top,
Update,
Where,
}
impl From<&str> for KeyWord {
fn from(s: &str) -> Self {
match s.to_lowercase().as_str() {
"archive" => KeyWord::Archive,
"first" => KeyWord::First,
"from" => KeyWord::From,
"insert" => KeyWord::Insert,
"into" => KeyWord::Into,
"last" => KeyWord::Last,
"limit" => KeyWord::Limit,
"select" => KeyWord::Select,
"top" => KeyWord::Top,
"update" => KeyWord::Update,
"where" => KeyWord::Where,
_ => KeyWord::Unknown,
}
}
}
impl Into<&str> for KeyWord {
fn into(self) -> &'static str {
match self {
KeyWord::Unknown => "unknown",
KeyWord::Archive => "archive",
KeyWord::First => "first",
KeyWord::From => "from",
KeyWord::Insert => "insert",
KeyWord::Into => "into",
KeyWord::Last => "last",
KeyWord::Limit => "limit",
KeyWord::Select => "select",
KeyWord::Top => "top",
KeyWord::Update => "update",
KeyWord::Where => "where",
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Command {
pub action: Action,
pub limit: Option<Limits>,
pub ops: Vec<(LogicOp, What)>,
pub tag: String,
pub what: What,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum Action {
Default,
Archive([u8; 16]),
Insert(Vec<u8>),
Select,
Update(([u8; 16], Vec<u8>)),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum What {
Default,
Id([u8; 16]),
Index(String),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum LogicOp {
Default,
And,
Or,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum Limits {
Default,
Limit(usize),
First(usize),
Last(usize),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum Result {
Some(ReturnPkg),
None,
}
impl Default for Command {
fn default() -> Command {
Command {
action: Action::Default,
limit: None,
ops: vec![],
tag: "".to_string(),
what: What::Default,
}
}
}
impl Command {
pub fn new() -> Command {
Command::default()
}
pub fn parse(cmd: &str) -> std::result::Result<Command, Box<dyn std::error::Error>> {
let tmp = cmd.trim().to_string();
let split = tmp.split_at(7);
match split.0.trim().to_lowercase().as_str() {
"archive" => parse_archive(split.1),
"insert" => parse_insert(split.1),
"select" => parse_select(split.1),
"update" => parse_update(split.1),
_ => Err(From::from(format!(
"Invalid command: {} unrecognized.",
split.0
))),
}
}
pub fn with_action(mut self, action: Action) -> Self {
self.action = action;
self
}
pub fn with_limit(mut self, limit: Limits) -> Self {
self.limit = Some(limit);
self
}
pub fn with_what(mut self, what: What) -> Self {
self._what(what);
self
}
fn _what(&mut self, what: What) {
self.what = what;
}
pub fn with_and_what(mut self, what: What) -> Self {
self._and_what(what);
self
}
fn _and_what(&mut self, what: What) {
self.ops.push((LogicOp::And, what));
}
pub fn with_or_what(mut self, what: What) -> Self {
self._or_what(what);
self
}
fn _or_what(&mut self, what: What) {
self.ops.push((LogicOp::Or, what));
}
pub fn with_tag(mut self, tag: &str) -> Self {
self._tag(tag);
self
}
fn _tag(&mut self, tag: &str) {
self.tag = tag.to_string();
}
}
fn parse_archive(_select: &str) -> std::result::Result<Command, Box<dyn std::error::Error>> {
unimplemented!()
}
fn parse_item_arr(stmt: &str) -> std::result::Result<Vec<u8>, Box<dyn std::error::Error>> {
match (stmt.find('['), stmt.find(']')) {
(Some(start), Some(end)) => {
let obj = stmt.get(start..=end).unwrap();
match serde_json::from_str(obj) {
Ok(item) => Ok(item),
_ => Err(From::from("Invalid command.")),
}
}
(_, _) => Err(From::from("Invalid statement termination.")),
}
}
fn parse_insert(stmt: &str) -> std::result::Result<Command, Box<dyn std::error::Error>> {
let item_vec = parse_item_arr(stmt)?;
let mut item = Command::new().with_action(Action::Insert(item_vec));
let tag = parse_tag(stmt).expect("Failed to parse tag.");
item._tag(tag.as_str());
Ok(item)
}
fn parse_select(select: &str) -> std::result::Result<Command, Box<dyn std::error::Error>> {
let cmd = Command::new().with_action(Action::Select);
let pattern = (
select.find("from"),
select.find("where"),
select.find("limit"),
);
match pattern {
(Some(_), None, None) => {
let tag = parse_tag(select)?;
let mut cmd = cmd;
cmd._tag(&tag);
Ok(cmd)
}
(Some(_), Some(l_where), None) => {
let cmd_tag = parse_tag(select)?;
let mut cmd = cmd;
cmd._tag(&cmd_tag);
parse_where(select, l_where, select.len(), cmd)
}
(Some(_from), Some(_l_where), Some(_limit)) => {
unimplemented!()
}
(Some(_from), None, Some(_limit)) => unimplemented!(),
(None, _, _) => Err(From::from("from part required")),
}
}
fn parse_where(
stmt: &str,
l_where: usize,
stop: usize,
cmd: Command,
) -> std::result::Result<Command, Box<dyn std::error::Error>> {
match stmt.find("id") {
Some(_) => {
let id = parse_id(stmt);
if id.is_some() {
let id = *uuid::Uuid::from_str(&id.unwrap())?.as_bytes();
let mut cmd = cmd;
cmd._what(What::Id(id));
Ok(cmd)
} else {
Err(From::from("statement id is required"))
}
}
None => {
let l_where = stmt.get((l_where + 5)..stop).unwrap();
parse_what(l_where, cmd)
}
}
}
fn parse_id(stmt: &str) -> Option<String> {
let pattern = (stmt.find("id"), stmt.find("is"));
match pattern {
(Some(_), Some(is_idx)) => {
let tmp = stmt.get(is_idx + 2..stmt.len()).unwrap();
let rmv = next_keyword_idx(tmp);
if rmv.is_some() {
let rmv = rmv.unwrap();
Some(stmt.get(0..rmv).unwrap().trim().to_string())
} else {
Some(tmp.trim().to_string())
}
}
(Some(id_idx), None) => {
let tmp = stmt.get(id_idx + 2..stmt.len()).unwrap();
let rmv = next_keyword_idx(tmp);
if rmv.is_some() {
let rmv = rmv.unwrap();
Some(stmt.get(0..rmv).unwrap().trim().to_string())
} else {
Some(tmp.trim().to_string())
}
}
_ => None,
}
}
fn parse_what(
stmt: &str,
cmd: Command,
) -> std::result::Result<Command, Box<dyn std::error::Error>> {
let mut cmd = cmd;
match stmt.find("is") {
Some(_is) => {
let is: Vec<&str> = stmt.split("is").collect();
let mut next_modifier = None;
for condition in is {
let this_modifier = next_modifier.clone();
match (condition.trim().is_empty(), condition.len() > 4) {
(true, _) => (),
(false, false) => {
let what = condition.trim().to_string();
match this_modifier {
Some(LogicOp::And) => cmd._and_what(What::Index(what)),
Some(LogicOp::Or) => cmd._or_what(What::Index(what)),
Some(LogicOp::Default) | None => cmd._what(What::Index(what)),
}
}
(false, true) => {
let mut what = condition.trim().to_string();
let next_op = what.get((what.len() - 3)..what.len()).unwrap();
match next_op.trim() {
"and" => next_modifier = Some(LogicOp::And),
"or" => next_modifier = Some(LogicOp::Or),
_ => next_modifier = None,
}
if next_modifier.is_some() {
what = what.get(0..(what.len() - 3)).unwrap().trim().to_string();
}
match this_modifier {
Some(LogicOp::And) => cmd._and_what(What::Index(what)),
Some(LogicOp::Or) => cmd._or_what(What::Index(what)),
Some(LogicOp::Default) | None => cmd._what(What::Index(what)),
}
}
}
}
}
None => {
let stmt = stmt.trim().to_string();
cmd._what(What::Index(stmt))
}
}
Ok(cmd)
}
fn parse_tag(stmt: &str) -> std::result::Result<String, Box<dyn std::error::Error>> {
let kw_from: &str = KeyWord::From.into();
let kw_into: &str = KeyWord::Into.into();
let pattern = (stmt.find(kw_from), stmt.find(kw_into));
match pattern {
(Some(idx), None) | (None, Some(idx)) => {
let stmt_minus_kw = stmt
.get((idx + 4)..stmt.len())
.expect("Split off from failed");
let next_key_word = next_keyword_idx(stmt_minus_kw);
if next_key_word.is_some() {
let next_key_word = next_key_word.unwrap();
Ok(stmt_minus_kw
.get(0..next_key_word)
.expect("Seperate tag from statement failed")
.trim()
.to_string())
} else {
Ok(stmt_minus_kw
.get(0..stmt_minus_kw.len())
.expect("Seperate tag from statement failed")
.trim()
.to_string())
}
}
_ => Err(From::from("Failed to parse tag out of statement")),
}
}
fn next_keyword_idx(stmt: &str) -> Option<usize> {
let mut iter = stmt
.split_whitespace()
.filter(|&s| KeyWord::from(s) != KeyWord::Unknown);
let first = iter.nth(0);
if first.is_some() {
let first = first.unwrap();
return Some(stmt.find(first).expect("Shouldn't error"));
}
None
}
fn parse_update(stmt: &str) -> std::result::Result<Command, Box<dyn std::error::Error>> {
let item = parse_item_arr(stmt)?;
let id = parse_id(stmt);
let tag = parse_tag(stmt)?;
if id.is_some() {
let id = *uuid::Uuid::from_str(&id.unwrap())?.as_bytes();
let mut cmd = Command::new().with_action(Action::Update((id, item)));
cmd._tag(tag.as_str());
Ok(cmd)
} else {
Err(From::from("Statement id is required."))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use uuid::Uuid;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Test {
pub test: String,
pub test_int: i32,
pub test_lint: i64,
pub test_index: usize,
pub test_float: f32,
pub test_lfloat: f64,
pub test_bool: bool,
pub test_vec: Vec<u8>,
pub test_arr: [u8; 16],
}
impl Default for Test {
fn default() -> Self {
Test {
test: "Test".to_string(),
test_int: 0,
test_lint: 0,
test_index: 0,
test_float: 0.1,
test_lfloat: 0.22,
test_bool: false,
test_vec: vec![],
test_arr: [0; 16],
}
}
}
impl Test {
#[allow(clippy::neg_multiply, clippy::cast_lossless)]
pub fn new<S>(text: S, index: usize) -> Test
where
S: Into<String>,
{
let mut test = Test::default();
test.test = text.into();
test.test_int = (index as i32 * -1) as i32;
test.test_lint = (index as i32 * -1) as i64;
test.test_float = index as f32;
test.test_lfloat = index as f64;
test.test_index = index;
test
}
pub fn get_index(&self) -> usize {
self.test_index
}
pub fn serialize(&self) -> String {
serde_json::to_string(self).expect("Failed to serialize test data.")
}
}
use std::cmp::Ordering;
impl std::cmp::Ord for Test {
fn cmp(&self, other: &Self) -> Ordering {
self.get_index().cmp(&other.get_index())
}
}
impl Eq for Test {}
impl PartialOrd for Test {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.get_index().cmp(&other.get_index()))
}
}
impl PartialEq for Test {
fn eq(&self, other: &Self) -> bool {
self.get_index() == other.get_index()
}
}
#[test]
fn parse_update() {
let id = "936DA01F9ABD4d9d80C702AF85C822A8";
let test = Test::new("Some text", 1).serialize();
let test_vec = test.as_bytes().to_vec();
let sql_sorta = format!(
"update {} from dog where id {}",
serde_json::to_string(&test_vec).unwrap(),
id
);
let parse_cmd = Command::parse(sql_sorta.as_str()).expect("Error parsing update command.");
let uid = *Uuid::from_str(id).expect("Shouldn't fail").as_bytes();
let correct_cmd = Command::new()
.with_action(Action::Update((uid, test_vec)))
.with_tag("dog");
assert_eq!(correct_cmd, parse_cmd);
}
#[test]
fn parse_insert() {
let mut cmp = Command::new().with_action(Action::Insert(
"A dog is a dog is a fish".as_bytes().to_vec(),
));
cmp._tag("dog");
let tmp = "A dog is a dog is a fish".as_bytes().to_vec();
let cmd_string = format!("Insert {} into dog", serde_json::to_string(&tmp).unwrap());
match Command::parse(cmd_string.as_str()) {
Ok(cmd) => {
assert_eq!(cmp, cmd);
}
Err(_) => assert!(false),
}
}
#[test]
fn parse_select_and_or() {
let mut cmp = Command::new().with_action(Action::Select);
cmp._tag("frog");
cmp._what(What::Index("duck".into()));
cmp._and_what(What::Index("wet".into()));
cmp._or_what(What::Index("flower".into()));
match Command::parse("Select from frog where duck and is wet or is flower") {
Ok(cmd) => assert_eq!(cmp, cmd),
Err(_) => assert!(false),
}
}
#[test]
fn parse_select_id() {
let cmd = Command::parse(
format!("select from tag where id is 936DA01F9ABD4d9d80C702AF85C822A8").as_str(),
)
.expect("Valid shouldn't fail");
let mut cmd_cmp = Command::new().with_action(Action::Select);
cmd_cmp._tag("tag");
cmd_cmp._what(What::Id([
147, 109, 160, 31, 154, 189, 77, 157, 128, 199, 2, 175, 133, 200, 34, 168,
]));
assert_eq!(cmd_cmp, cmd);
}
#[test]
fn parse_select() {
let cmd = Command::parse("select from tag").expect("Valid shouldn't fail");
let mut cmd_cmp = Command::new().with_action(Action::Select);
cmd_cmp._tag("tag");
assert_eq!(cmd_cmp, cmd);
}
#[test]
fn parse_select_where() {
let cmd = Command::parse("select from tag where duck").expect("Valid shouldn't fail.");
let mut cmd_cmp = Command::new().with_action(Action::Select);
cmd_cmp._tag("tag");
cmd_cmp._what(What::Index("duck".to_string()));
assert_eq!(cmd_cmp, cmd);
}
}