Skip to content

Commit

Permalink
make and use sql value literal type
Browse files Browse the repository at this point in the history
  • Loading branch information
JRMurr committed Mar 6, 2023
1 parent cc008fe commit 55d6624
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 28 deletions.
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[workspace]
members = [
"crates/*",
]
members = ["crates/*"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# https://doc.rust-lang.org/nightly/cargo/reference/specifying-dependencies.html#inheriting-a-dependency-from-a-workspace
[workspace.dependencies]
derive_more = "0.99.17"
bigdecimal = { version = "0.3.0", features = ["serde"] }
miette = "5.5.0"
serde = { version = "1.0.151", features = ["derive"] }
thiserror = "1.0.38"
thiserror = "1.0.38"
8 changes: 4 additions & 4 deletions crates/sql_jr_execution/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
derive_more = "0.99.17"
miette = {workspace = true}
serde = {workspace = true}
derive_more = { workspace = true }
miette = { workspace = true }
serde = { workspace = true }
sql_jr_parser = { path = "../sql_jr_parser" }
thiserror = {workspace = true}
thiserror = { workspace = true }
11 changes: 6 additions & 5 deletions crates/sql_jr_execution/src/row.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{collections::HashMap, rc::Rc};

use derive_more::Display;
use sql_jr_parser::value::Value;

use crate::{error::QueryExecutionError, table::ColumnInfo};
/// A Row in a Query Response
Expand All @@ -9,11 +10,11 @@ use crate::{error::QueryExecutionError, table::ColumnInfo};
pub struct Row<'a> {
id: usize,
columns: Rc<ColumnInfo>,
data: HashMap<&'a String, &'a String>,
data: HashMap<&'a String, &'a Value>,
}

impl<'a> Row<'a> {
pub fn new(columns: Rc<ColumnInfo>, id: usize, data: HashMap<&'a String, &'a String>) -> Self {
pub fn new(columns: Rc<ColumnInfo>, id: usize, data: HashMap<&'a String, &'a Value>) -> Self {
Self { id, columns, data }
}

Expand All @@ -28,15 +29,15 @@ impl<'a> Row<'a> {
/// Panics if the column does not exist
/// See [`try_get`](Self::try_get) for a non-panicking
/// version.
pub fn get(&self, column: &String) -> String {
pub fn get(&self, column: &String) -> Value {
self.try_get(column).unwrap()
}

/// Get a single value from the row
pub fn try_get(&self, column: &String) -> Result<String, QueryExecutionError> {
pub fn try_get(&self, column: &String) -> Result<Value, QueryExecutionError> {
self.data.get(column).map_or_else(
|| Err(QueryExecutionError::ColumnDoesNotExist(column.to_owned())),
|val| Ok(val.to_string()),
|val| Ok((*val).clone()),
)
}
}
6 changes: 3 additions & 3 deletions crates/sql_jr_execution/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use std::{
};

use serde::{Deserialize, Serialize};
use sql_jr_parser::Column;
use sql_jr_parser::{value::Value, Column};

use crate::{error::QueryExecutionError, row::Row};

/// A row stored in a table
#[derive(Debug, Clone, Default, Serialize, Deserialize, derive_more::From)]
pub struct StoredRow {
data: HashMap<String, String>,
data: HashMap<String, Value>, // TODO: store bytes instead of the value enum
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, derive_more::From)]
Expand Down Expand Up @@ -61,7 +61,7 @@ impl Table {
///
/// Assumes the values are in the same order of the [`Column`]s passed to
/// create
pub fn insert(&mut self, values: Vec<String>) {
pub fn insert(&mut self, values: Vec<Value>) {
let id = self
.rows
.last_key_value()
Expand Down
8 changes: 5 additions & 3 deletions crates/sql_jr_parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ version = "0.1.0"
edition = "2021"

[dependencies]
miette = {workspace = true}
derive_more = { workspace = true }
miette = { workspace = true }
nom = "7.1.1"
nom_locate = "4.0.0"
nom-supreme = "0.8.0"
serde = {workspace = true}
thiserror = {workspace = true}
serde = { workspace = true }
thiserror = { workspace = true }
bigdecimal = { workspace = true }
6 changes: 5 additions & 1 deletion crates/sql_jr_parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub fn parse_multiple_queries(input: &str) -> Result<Vec<SqlQuery>, FormattedErr
mod tests {

use super::*;
use crate::value::Value;

#[test]
fn test_error() {
Expand All @@ -107,7 +108,10 @@ mod tests {
fn test_insert() {
let expected = InsertStatement {
table: "foo".to_string(),
values: vec!["foo".to_string(), "bar".to_string()],
values: vec![
Value::String("foo".to_string()),
Value::String("bar".to_string()),
],
};
assert_eq!(
SqlQuery::parse_from_raw("insert into foo values foo,bar;")
Expand Down
9 changes: 6 additions & 3 deletions crates/sql_jr_parser/src/commands/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ use nom::{
use nom_supreme::{tag::complete::tag_no_case, ParserExt};
use serde::{Deserialize, Serialize};

use crate::parse::{comma_sep, identifier, Parse, ParseResult, RawSpan};
use crate::{
parse::{comma_sep, identifier, Parse, ParseResult, RawSpan},
value::Value,
};

#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct InsertStatement {
pub table: String,
pub values: Vec<String>, // for now just Strings
pub values: Vec<Value>,
} // TODO: impl display

impl<'a> Parse<'a> for InsertStatement {
Expand All @@ -23,7 +26,7 @@ impl<'a> Parse<'a> for InsertStatement {
preceded(multispace1, tag_no_case("into")),
preceded(multispace1, identifier.context("Table Name")),
preceded(multispace1, tag_no_case("values")),
preceded(multispace1, comma_sep(identifier).context("Values")),
preceded(multispace1, comma_sep(Value::parse).context("Values")),
)),
)(input)?;

Expand Down
1 change: 1 addition & 0 deletions crates/sql_jr_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub mod ast;
pub mod commands;
pub mod error;
pub mod parse;
pub mod value;

pub use commands::{Column, SqlTypeInfo};
85 changes: 85 additions & 0 deletions crates/sql_jr_parser/src/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use std::str::FromStr;

use bigdecimal::BigDecimal;
use derive_more::Display;
use nom::{
branch::alt,
bytes::complete::{take_until, take_while},
character::complete::multispace0,
error::context,
sequence::{preceded, terminated, tuple},
Parser,
};
use nom_supreme::tag::complete::tag;
use serde::{Deserialize, Serialize};

use crate::parse::{peek_then_cut, Parse, ParseResult, RawSpan};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
pub enum Value {
Number(BigDecimal), // TODO: should we make literals for ints vs floats?
String(String),
}

/// Parse a single quoted string value
fn parse_string_value(input: RawSpan<'_>) -> ParseResult<'_, Value> {
// TODO: look into https://github.com/rust-bakery/nom/blob/main/examples/string.rs
// for escaped strings
let (remaining, (_, str_value)) = context(
"String Literal",
tuple((
tag("'"),
take_until("'").map(|s: RawSpan| Value::String(s.fragment().to_string())),
)),
)(input)?;

Ok((remaining, str_value))
}

/// Parse a numeric literal
fn parse_number_value(input: RawSpan<'_>) -> ParseResult<'_, Value> {
let (remaining, digits) =
context("Number Literal", take_while(|c: char| c.is_numeric()))(input)?; // TODO: handle floats

let digits = digits.fragment();

Ok((
remaining,
Value::Number(BigDecimal::from_str(digits).unwrap()),
))
}

impl<'a> Parse<'a> for Value {
fn parse(input: RawSpan<'a>) -> ParseResult<'a, Self> {
context(
"Value",
preceded(
multispace0,
terminated(
alt((peek_then_cut("'", parse_string_value), parse_number_value)),
multispace0,
),
),
)(input)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_string() {
let expected = Value::String("123abc new".to_string());

assert_eq!(Value::parse_from_raw("'123abc new'").unwrap().1, expected)
}

#[test]
fn test_number() {
let num = BigDecimal::from_str("123456").unwrap();
let expected = Value::Number(num);

assert_eq!(Value::parse_from_raw("123456").unwrap().1, expected)
}
}
2 changes: 1 addition & 1 deletion crates/sql_jr_repl/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn display_response(res: ExecResponse) {
.collect();
builder.set_columns(&columns);
for row in table_iter {
builder.add_record(columns.iter().map(|col| row.get(col)));
builder.add_record(columns.iter().map(|col| row.get(col).to_string()));
}
println!("{}", builder.build())
}
Expand Down
8 changes: 4 additions & 4 deletions queries/basic.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CREATE TABLE foo (
column1 int,
column2 string
col1 int,
col2 string
);

INSERT INTO foo
Expand All @@ -12,8 +12,8 @@ INSERT INTO foo
4, 5;

SELECT
column1,
column2
col1,
col2
FROM
foo;

0 comments on commit 55d6624

Please sign in to comment.