Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ToSql trait which displays AST as SQL text format #554

Merged
merged 49 commits into from Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e4560d7
add expr_decoder
bearney74 May 15, 2022
0750bd0
add decoder tests for various expr enums
bearney74 May 16, 2022
ad77579
remove comments
bearney74 May 16, 2022
fd3c7fa
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 16, 2022
73b3019
add Aggregate tests
bearney74 May 16, 2022
d46bbee
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 18, 2022
95dbb3b
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 19, 2022
586ec11
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 22, 2022
36a5b6b
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 25, 2022
e4f87e0
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 26, 2022
8ab5f94
add description column for show indexes command
bearney74 May 26, 2022
cde046c
coverage failed
bearney74 May 26, 2022
273847f
use strum screaming camel case
bearney74 May 26, 2022
19589e9
uppercase CASE, AS and EXTRACT
bearney74 May 26, 2022
fc4d7df
remove necessary Display from enum
bearney74 May 26, 2022
6709b29
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 26, 2022
890e58c
Int to INT
bearney74 May 26, 2022
9e6c413
Merge branch 'ExprDecode' of github.com:earney/gluesql into ExprDecode
bearney74 May 26, 2022
ddba6ef
Int to INT
bearney74 May 26, 2022
f14f6df
Merge branch 'main' into ExprDecode
bearney74 May 28, 2022
768db2b
fix merge issues
bearney74 May 28, 2022
b74ad34
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 29, 2022
dffcf30
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 30, 2022
54ecbe6
add stub statements for expression decoder
bearney74 May 30, 2022
ac0d99a
remove _ => statement
bearney74 May 30, 2022
bc956f4
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 31, 2022
549529a
Merge branch 'gluesql:main' into ExprDecode
bearney74 May 31, 2022
2ca46f0
merge hexstring code
bearney74 May 31, 2022
555abc3
use join function
bearney74 Jun 1, 2022
32cc07f
expr_decode to ToSql
bearney74 Jun 1, 2022
49e8aec
implement ToSql
bearney74 Jun 2, 2022
3b25e6f
move unary and binary operators to use ToSql
bearney74 Jun 2, 2022
4229c93
Merge branch 'gluesql:main' into ExprDecode
bearney74 Jun 2, 2022
58991f4
fmt
bearney74 Jun 2, 2022
056358e
fmt
bearney74 Jun 2, 2022
4bd52cb
fix payload.rs
bearney74 Jun 3, 2022
ed31677
add ToSql module to js
bearney74 Jun 3, 2022
84778f1
make fmt happy
bearney74 Jun 3, 2022
c6fe845
make changes requested by reviewers
bearney74 Jun 3, 2022
8c8bb91
Merge branch 'gluesql:main' into ExprDecode
bearney74 Jun 4, 2022
758509c
make changes requested by reviewers
bearney74 Jun 6, 2022
94e94c6
fix test
bearney74 Jun 6, 2022
dd5da90
make fmt happy
bearney74 Jun 6, 2022
adf2db1
revert show indexes portion of PR
bearney74 Jun 6, 2022
bcbfb7a
add unary/binary op test cases, make code adjustments
bearney74 Jun 6, 2022
382af28
fix module import
bearney74 Jun 6, 2022
6ee365b
Merge branch 'gluesql:main' into ExprDecode
bearney74 Jun 6, 2022
52bbf44
merge with main
bearney74 Jun 6, 2022
043896b
fix nested string; add nested test
bearney74 Jun 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add decoder tests for various expr enums
  • Loading branch information
bearney74 committed May 16, 2022
commit 0750bd0681807133bc4925a60056512230813269
2 changes: 1 addition & 1 deletion core/src/ast/ast_literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use {
strum_macros::Display,
};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
pub enum AstLiteral {
Boolean(bool),
Number(BigDecimal),
Expand Down
195 changes: 153 additions & 42 deletions core/src/ast/expr_decoder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::Expr;
use super::{Expr, AstLiteral};


//pub enum DecoderErrors {
// #[error("unimplemented Decode Expression: {:}")]
Expand All @@ -11,83 +12,193 @@ use super::Expr;
// *value
//}

fn decode(e: Expr) -> String {
fn decode(e: &Expr) -> String {
match e {
Expr::Identifier(s) => s.to_string(),
Expr::BinaryOp { left, op, right } => {
format!("{:} {:} {:}", decode(*left), op.to_string(), decode(*right))
format!("{:} {:} {:}", decode(&*left), op, decode(&*right))
This conversation was marked as resolved.
Show resolved Hide resolved
}

Expr::CompoundIdentifier(s) => s.iter().fold("".to_string(), |acc, x| acc + x),
Expr::IsNull(s) => format!("isNull({:})", *s),
Expr::IsNotNull(s) => format!("isNotNull({:})", *s),
Expr::CompoundIdentifier(s) => {
// is there a better way of doing this? (ie adding '.' between each string?)
// tried fold and couldn't figure out how add . between each item
let mut str:String="".to_string();
for _s in s {
if !str.is_empty() { str+="."}
str+=_s;

}
str
}
Expr::IsNull(s) => format!("{:} IS NULL", decode(s)),
Expr::IsNotNull(s) => format!("{:} IS NOT NULL", decode(s)),
Expr::InList {
expr,
list,
negated,
} => format!(
"InList({:}, {:}, negated:{:})",
decode(*expr),
(*list).iter().fold("".to_string(), |acc, x| acc + decode(*x)),
negated
),
} => {
// is there a fold that will do this?
let mut s:String = "".to_string();

for item in list {
if !s.is_empty() {
s+=",";
}
s+=&decode(&item);
}

match negated {
true => format!("{:} NOT IN ({:})", decode(&expr), s),
false => format!("{:} IN ({:})", decode(&expr), s),
}
},
// Expr::InSubquery {expr, subquery, negated} => format!("InSubquery({:}, subquery:{:}, negated: {:})", decode(*expr), *subquery, negated),
Expr::Between {
expr,
negated,
low,
high,
} => format!(
"Between ({:}, negated:{:}, low:{:}, high:{:})",
decode(*expr),
negated,
decode(*low),
decode(*high)
),
Expr::UnaryOp { op, expr } => format!("{:} {:}", op.to_string(), decode(*expr)),
} => match negated {
true => format!("{:} NOT BETWEEN {:} AND {:}", decode(&*expr),
decode(&*low), decode(&*high)),

false => format!("{:} BETWEEN {:} AND {:}", decode(&*expr),
decode(&*low), decode(&*high)),
},
Expr::UnaryOp { op, expr } => format!("{:}{:}", op, decode(&*expr)),
Expr::Cast { expr, data_type } => {
format!("cast({:} as {:}", decode(*expr), data_type.to_string())
format!("cast({:} as {:})", decode(&*expr), data_type)
}
Expr::Extract { field, expr } => {
format!("extract({:} from {:}", field.to_string(), decode(*expr))
format!("extract({:} from \"{:}\")", field, decode(&*expr))
}
Expr::Nested(expr) => format!("Nested({:})", decode(*expr)),
// Expr::Literal(s) => format!("{:}", s),
Expr::TypedString { data_type, value } => format!("{:}({:})", data_type.to_string(), value),
// Expr::Function(f) => format!("{:}", *f.to_string()),
// Expr::Aggregate(a) => format!("{}", *a.to_string()),
// Expr::Exists(q) => format!("Exists({:})", *query),
// Expr::Subquery(q) => format!("Subquery({:})", *query),
/*
Expr::Case { operand, when_then, else_result } => format!("case(operand:{:}, when_then:{:}, else_result:{:}", )
Case {
operand: Option<Box<Expr>>,
when_then: Vec<(Expr, Expr)>,
else_result: Option<Box<Expr>>,
Expr::Nested(expr) => format!("todo:Nested({:})", decode(&*expr)),
Expr::Literal(s) => match s {
AstLiteral::Boolean(b) => format!("{:}", b),
AstLiteral::Number(d) => format!("{:}", d),
AstLiteral::QuotedString(qs) => format!("\"{:}\"", qs),
AstLiteral::Null => "Null".to_string(),
AstLiteral::Interval{..} => "Interval not implemented yet..".to_string(),
},
Expr::TypedString { data_type, value } => format!("{:}(\"{:}\")", data_type, value),
// todo's...
//Expr::Function(f) => format!("{:}", *f.to_string()),
//Expr::Aggregate(a) => format!("{}", *a.to_string()),
//Expr::Exists(q) => format!("Exists({:})", *query),
//Expr::Subquery(q) => format!("Subquery({:})", *query),


Expr::Case { operand, when_then, else_result } => {
let mut str=match operand {
Some(s) => format!("CASE {:}", decode(s)),
None => format!("CASE "),
};
for (_when, _then) in when_then {
str+=format!("\nWHEN {:} THEN {:}", decode(_when), decode(_then)).as_str();
}

match else_result {
Some(s) => str+=format!("\nELSE {:}", decode(s)).as_str(),
None => str+="", // no operation?
};
str + "\nEND"
},
*/
_ => format!("Unimplemented Decode Expression: {:}", e.to_string()),
_ => format!("Unimplemented Decode Expression: {:}", e),
}
}

#[cfg(test)]
mod tests {

use super::Expr;
use crate::ast::expr_decoder::decode;
use crate::ast::BinaryOperator;
use bigdecimal::BigDecimal;
use std::str::FromStr;
use crate::ast::{AstLiteral, BinaryOperator, UnaryOperator,
Expr, expr_decoder::decode,
DataType,DateTimeField,};

#[test]
fn basic_decoder() {
assert_eq!("id".to_string(), decode(Expr::Identifier("id".to_string())));
//Identifier
assert_eq!("id".to_string(), decode(&Expr::Identifier("id".to_string())));

//BinaryOp
assert_eq!(
"id + num",
decode(Expr::BinaryOp {
decode(&Expr::BinaryOp {
left: Box::new(Expr::Identifier("id".to_string())),
op: BinaryOperator::Plus,
right: Box::new(Expr::Identifier("num".to_string()))
})
);

//unaryop
assert_eq!("-id",
decode(&Expr::UnaryOp{op:UnaryOperator::Minus,
expr:Box::new(Expr::Identifier("id".to_string()))}));

//CompoundIdentifier
assert_eq!("id.name.first",
decode(&Expr::CompoundIdentifier(vec!["id".to_string(), "name".to_string(), "first".to_string()])));

//IsNUll
let id_expr:Box<Expr> = Box::new(Expr::Identifier("id".to_string()));
assert_eq!("id IS NULL", decode(&Expr::IsNull(id_expr)));

//IsNotNull
let id_expr:Box<Expr> = Box::new(Expr::Identifier("id".to_string()));
assert_eq!("id IS NOT NULL", decode(&Expr::IsNotNull(id_expr)));

//Cast
//assert_eq!("cast 1.0 as int)", decode(expr));

//TypeString
assert_eq!(r#"Int("1")"#,
decode(&Expr::TypedString{data_type:DataType::Int,
value:"1".to_string()}));

//extract
assert_eq!(r#"extract(Minute from "2022-05-05 01:02:03")"#,
decode(&Expr::Extract{field:DateTimeField::Minute,
expr:Box::new(Expr::Identifier("2022-05-05 01:02:03".to_string()))}));

//between
assert_eq!("id BETWEEN low AND high",
decode(&Expr::Between{expr:Box::new(Expr::Identifier("id".to_string())),
negated: false,
low: Box::new(Expr::Identifier("low".to_string())),
high: Box::new(Expr::Identifier("high".to_string()))})
);

//not between
assert_eq!("id NOT BETWEEN low AND high",
decode(&Expr::Between{expr:Box::new(Expr::Identifier("id".to_string())),
negated: true,
low: Box::new(Expr::Identifier("low".to_string())),
high: Box::new(Expr::Identifier("high".to_string()))}));

// in list
assert_eq!(r#"id IN ("a","b","c")"#,
decode(&Expr::InList{expr:Box::new(Expr::Identifier("id".to_string())),
list:vec![Expr::Literal(AstLiteral::QuotedString("a".to_string())),
Expr::Literal(AstLiteral::QuotedString("b".to_string())),
Expr::Literal(AstLiteral::QuotedString("c".to_string()))],
negated:false}));


//not in list
assert_eq!(r#"id NOT IN ("a","b","c")"#,
decode(&Expr::InList{expr:Box::new(Expr::Identifier("id".to_string())),
list:vec![Expr::Literal(AstLiteral::QuotedString("a".to_string())),
Expr::Literal(AstLiteral::QuotedString("b".to_string())),
Expr::Literal(AstLiteral::QuotedString("c".to_string()))],
negated:true}));

assert_eq!("CASE id\nWHEN 1 THEN \"a\"\nWHEN 2 THEN \"b\"\nELSE \"c\"\nEND",
decode(&Expr::Case{operand:Some(Box::new(Expr::Identifier("id".to_string()))),
when_then:vec![(Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1").unwrap())), Expr::Literal(AstLiteral::QuotedString("a".to_string()))),
(Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())), Expr::Literal(AstLiteral::QuotedString("b".to_string())))],
else_result:Some(Box::new(Expr::Literal(AstLiteral::QuotedString("c".to_string()))))}
));

}
}