Skip to content

Commit 5abd9e7

Browse files
committed
Modularized into separate files
Add ToString implementation on the components
1 parent 34913c7 commit 5abd9e7

File tree

8 files changed

+1097
-781
lines changed

8 files changed

+1097
-781
lines changed

src/sqlast.rs

Lines changed: 163 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ use chrono::{NaiveDate,
2525
};
2626

2727
use uuid::Uuid;
28+
pub use self::value::Value;
29+
pub use self::sqltype::SQLType;
30+
pub use self::table_key::{
31+
AlterOperation,
32+
TableKey,
33+
Key
34+
};
35+
36+
pub use self::sql_operator::SQLOperator;
37+
38+
mod value;
39+
mod sqltype;
40+
mod table_key;
41+
mod sql_operator;
2842

2943
/// SQL Abstract Syntax Tree (AST)
3044
#[derive(Debug, Clone, PartialEq)]
@@ -36,7 +50,7 @@ pub enum ASTNode {
3650
/// Multi part identifier e.g. `myschema.dbo.mytable`
3751
SQLCompoundIdentifier(Vec<String>),
3852
/// Assigment e.g. `name = 'Fred'` in an UPDATE statement
39-
SQLAssignment(String, Box<ASTNode>),
53+
SQLAssignment(SQLAssignment),
4054
/// `IS NULL` expression
4155
SQLIsNull(Box<ASTNode>),
4256
/// `IS NOT NULL` expression
@@ -102,7 +116,7 @@ pub enum ASTNode {
102116
/// TABLE
103117
table_name: String,
104118
/// Column assignments
105-
assignemnts: Vec<SQLAssigment>,
119+
assignments: Vec<SQLAssignment>,
106120
/// WHERE
107121
selection: Option<Box<ASTNode>>,
108122
},
@@ -112,9 +126,6 @@ pub enum ASTNode {
112126
relation: Option<Box<ASTNode>>,
113127
/// WHERE
114128
selection: Option<Box<ASTNode>>,
115-
/// ORDER BY
116-
order_by: Option<Vec<SQLOrderByExpr>>,
117-
limit: Option<Box<ASTNode>>,
118129
},
119130
/// CREATE TABLE
120131
SQLCreateTable {
@@ -131,41 +142,134 @@ pub enum ASTNode {
131142
}
132143
}
133144

134-
/// SQL values such as int, double, string timestamp
135-
#[derive(Debug, Clone, PartialEq)]
136-
pub enum Value{
137-
/// Literal signed long
138-
Long(i64),
139-
/// Literal floating point value
140-
Double(f64),
141-
/// Unquoted string
142-
String(String),
143-
Uuid(Uuid),
144-
/// 'string value'
145-
SingleQuotedString(String),
146-
/// "string value"
147-
DoubleQuotedString(String),
148-
/// Boolean value true or false,
149-
Boolean(bool),
150-
/// Date value
151-
Date(NaiveDate),
152-
// Time
153-
Time(NaiveTime),
154-
/// Date and time
155-
DateTime(NaiveDateTime),
156-
/// Timstamp with time zone
157-
Timestamp(DateTime<FixedOffset>),
158-
/// NULL value in insert statements,
159-
Null,
145+
146+
impl ToString for ASTNode{
147+
148+
fn to_string(&self) -> String {
149+
match self{
150+
ASTNode::SQLIdentifier(s) => s.to_string(),
151+
ASTNode::SQLWildcard => "*".to_string(),
152+
ASTNode::SQLCompoundIdentifier(s) => s.join("."),
153+
ASTNode::SQLAssignment(ass) => ass.to_string(),
154+
ASTNode::SQLIsNull(ast) => format!("{} IS NULL",ast.as_ref().to_string()),
155+
ASTNode::SQLIsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
156+
ASTNode::SQLBinaryExpr{left, op, right} => {
157+
format!("{} {} {}", left.as_ref().to_string(), op.to_string(), right.as_ref().to_string())
158+
}
159+
ASTNode::SQLCast{expr, data_type} => {
160+
format!("CAST({} AS {})", expr.as_ref().to_string(), data_type.to_string())
161+
}
162+
ASTNode::SQLNested(ast) => format!("({})", ast.as_ref().to_string()),
163+
ASTNode::SQLUnary {operator, rex } => {
164+
format!("{} {}", operator.to_string(), rex.as_ref().to_string())
165+
}
166+
ASTNode::SQLValue(v) => v.to_string(),
167+
ASTNode::SQLFunction{id, args} => format!("{}({})", id, args.iter().map(|a|a.to_string()).collect::<Vec<String>>().join(", ")),
168+
ASTNode::SQLSelect{
169+
projection,
170+
relation,
171+
selection,
172+
order_by,
173+
group_by,
174+
having,
175+
limit,
176+
} => {
177+
let mut s = format!("SELECT {}", projection.iter().map(|p|p.to_string()).collect::<Vec<String>>().join(", "));
178+
if let Some(relation) = relation{
179+
s += &format!(" FROM {}", relation.as_ref().to_string());
180+
}
181+
if let Some(selection) = selection{
182+
s += &format!(" WHERE {}", selection.as_ref().to_string());
183+
}
184+
if let Some(group_by) = group_by {
185+
s += &format!(" GROUP BY {}", group_by.iter().map(|g|g.to_string()).collect::<Vec<String>>().join(", "));
186+
}
187+
if let Some(having) = having{
188+
s += &format!(" HAVING {}", having.as_ref().to_string());
189+
}
190+
if let Some(order_by) = order_by{
191+
s += &format!(" ORDER BY {}", order_by.iter().map(|o|o.to_string()).collect::<Vec<String>>().join(", "));
192+
}
193+
if let Some(limit) = limit {
194+
s += &format!(" LIMIT {}", limit.as_ref().to_string());
195+
}
196+
s
197+
}
198+
ASTNode::SQLInsert{ table_name, columns, values } => {
199+
let mut s = format!("INSERT INTO {}", table_name);
200+
if columns.len() > 0 {
201+
s += &format!(" ({})", columns.join(", "));
202+
}
203+
if values.len() > 0 {
204+
s += &format!(" VALUES({})",
205+
values.iter()
206+
.map(|row|row.iter().map(|c|c.to_string())
207+
.collect::<Vec<String>>().join(", ")
208+
).collect::<Vec<String>>().join(", ")
209+
);
210+
}
211+
s
212+
}
213+
ASTNode::SQLCopy{table_name, columns, values} => {
214+
let mut s = format!("COPY {}", table_name);
215+
if columns.len() > 0 {
216+
s += &format!(" ({})", columns.iter().map(|c|c.to_string()).collect::<Vec<String>>().join(", "));
217+
}
218+
s += " FROM stdin; ";
219+
if values.len() > 0 {
220+
s += &format!("\n{}",
221+
values.iter()
222+
.map(|v|v.to_string())
223+
.collect::<Vec<String>>().join("\t")
224+
);
225+
}
226+
s
227+
}
228+
ASTNode::SQLUpdate{table_name, assignments, selection} => {
229+
let mut s = format!("UPDATE {}", table_name);
230+
if assignments.len() > 0 {
231+
s += &format!("{}", assignments.iter().map(|ass|ass.to_string()).collect::<Vec<String>>().join(", "));
232+
}
233+
if let Some(selection) = selection{
234+
s += &format!(" WHERE {}", selection.as_ref().to_string());
235+
}
236+
s
237+
}
238+
ASTNode::SQLDelete{relation, selection} => {
239+
let mut s = String::from("DELETE");
240+
if let Some(relation) = relation{
241+
s += &format!(" FROM {}", relation.as_ref().to_string());
242+
}
243+
if let Some(selection) = selection{
244+
s += &format!(" WHERE {}", selection.as_ref().to_string());
245+
}
246+
s
247+
}
248+
ASTNode::SQLCreateTable{name, columns} => {
249+
format!("CREATE TABLE {} ({})", name, columns.iter().map(|c|c.to_string()).collect::<Vec<String>>().join(", "))
250+
}
251+
ASTNode::SQLAlterTable{name, operation} => {
252+
format!("ALTER TABLE {} {}", name, operation.to_string())
253+
}
254+
}
255+
}
160256
}
161257

162258
/// SQL assignment `foo = expr` as used in SQLUpdate
259+
/// TODO: unify this with the ASTNode SQLAssignment
163260
#[derive(Debug, Clone, PartialEq)]
164-
pub struct SQLAssigment {
261+
pub struct SQLAssignment {
165262
id: String,
166263
value: Box<ASTNode>,
167264
}
168265

266+
impl ToString for SQLAssignment{
267+
268+
fn to_string(&self) -> String {
269+
format!("SET {} = {}", self.id, self.value.as_ref().to_string())
270+
}
271+
}
272+
169273
/// SQL ORDER BY expression
170274
#[derive(Debug, Clone, PartialEq)]
171275
pub struct SQLOrderByExpr {
@@ -179,109 +283,45 @@ impl SQLOrderByExpr {
179283
}
180284
}
181285

286+
impl ToString for SQLOrderByExpr{
287+
fn to_string(&self) -> String {
288+
if self.asc{
289+
format!("{} ASC", self.expr.as_ref().to_string())
290+
}else{
291+
format!("{} DESC", self.expr.as_ref().to_string())
292+
}
293+
}
294+
}
295+
182296
/// SQL column definition
183297
#[derive(Debug, Clone, PartialEq)]
184298
pub struct SQLColumnDef {
185299
pub name: String,
186300
pub data_type: SQLType,
187-
pub allow_null: bool,
188301
pub is_primary: bool,
189302
pub is_unique: bool,
190303
pub default: Option<Box<ASTNode>>,
304+
pub allow_null: bool,
191305
}
192306

193-
/// SQL datatypes for literals in SQL statements
194-
#[derive(Debug, Clone, PartialEq)]
195-
pub enum SQLType {
196-
/// Fixed-length character type e.g. CHAR(10)
197-
Char(Option<usize>),
198-
/// Variable-length character type e.g. VARCHAR(10)
199-
Varchar(Option<usize>),
200-
/// Uuid value
201-
Uuid,
202-
/// Large character object e.g. CLOB(1000)
203-
Clob(usize),
204-
/// Fixed-length binary type e.g. BINARY(10)
205-
Binary(usize),
206-
/// Variable-length binary type e.g. VARBINARY(10)
207-
Varbinary(usize),
208-
/// Large binary object e.g. BLOB(1000)
209-
Blob(usize),
210-
/// Decimal type with precision and optional scale e.g. DECIMAL(10,2)
211-
Decimal(usize, Option<usize>),
212-
/// Small integer
213-
SmallInt,
214-
/// Integer
215-
Int,
216-
/// Big integer
217-
BigInt,
218-
/// Floating point with optional precision e.g. FLOAT(8)
219-
Float(Option<usize>),
220-
/// Floating point e.g. REAL
221-
Real,
222-
/// Double e.g. DOUBLE PRECISION
223-
Double,
224-
/// Boolean
225-
Boolean,
226-
/// Date
227-
Date,
228-
/// Time
229-
Time,
230-
/// Timestamp
231-
Timestamp,
232-
/// Regclass used in postgresql serial
233-
Regclass,
234-
/// Text
235-
Text,
236-
/// Bytea
237-
Bytea,
238-
/// Custom type such as enums
239-
Custom(String),
240-
/// Arrays
241-
Array(Box<SQLType>),
242-
}
243307

244-
/// SQL Operator
245-
#[derive(Debug, PartialEq, Clone)]
246-
pub enum SQLOperator {
247-
Plus,
248-
Minus,
249-
Multiply,
250-
Divide,
251-
Modulus,
252-
Gt,
253-
Lt,
254-
GtEq,
255-
LtEq,
256-
Eq,
257-
NotEq,
258-
And,
259-
Or,
260-
}
308+
impl ToString for SQLColumnDef{
261309

262-
#[derive(Debug, PartialEq, Clone)]
263-
pub enum AlterOperation{
264-
AddConstraint(TableKey),
265-
RemoveConstraint{
266-
name: String,
310+
fn to_string(&self) -> String {
311+
let mut s = format!("{} {}", self.name, self.data_type.to_string());
312+
if self.is_primary{
313+
s += " PRIMARY KEY";
314+
}
315+
if self.is_unique{
316+
s += " UNIQUE";
317+
}
318+
if let Some(ref default) = self.default{
319+
s += &format!(" DEFAULT {}", default.as_ref().to_string());
320+
}
321+
if !self.allow_null{
322+
s += " NOT NULL";
323+
}
324+
s
267325
}
268326
}
269327

270-
271-
#[derive(Debug, PartialEq, Clone)]
272-
pub struct Key{
273-
pub name: Option<String>,
274-
pub columns: Vec<String>,
275-
}
276-
277-
#[derive(Debug, PartialEq, Clone)]
278-
pub enum TableKey{
279-
PrimaryKey(Key),
280-
UniqueKey(Key),
281-
Key(Key),
282-
ForeignKey {
283-
key: Key,
284-
foreign_table: String,
285-
referred_columns: Vec<String>,
286-
}
287-
}

src/sqlast/sql_operator.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
/// SQL Operator
3+
#[derive(Debug, PartialEq, Clone)]
4+
pub enum SQLOperator {
5+
Plus,
6+
Minus,
7+
Multiply,
8+
Divide,
9+
Modulus,
10+
Gt,
11+
Lt,
12+
GtEq,
13+
LtEq,
14+
Eq,
15+
NotEq,
16+
And,
17+
Or,
18+
}
19+
20+
impl ToString for SQLOperator{
21+
22+
fn to_string(&self) -> String {
23+
match self{
24+
SQLOperator::Plus => "+".to_string(),
25+
SQLOperator::Minus => "-".to_string(),
26+
SQLOperator::Multiply => "*".to_string(),
27+
SQLOperator::Divide => "/".to_string(),
28+
SQLOperator::Modulus => "%".to_string(),
29+
SQLOperator::Gt => ">".to_string(),
30+
SQLOperator::Lt => "<".to_string(),
31+
SQLOperator::GtEq => ">=".to_string(),
32+
SQLOperator::LtEq => "<=".to_string(),
33+
SQLOperator::Eq => "=".to_string(),
34+
SQLOperator::NotEq => "!=".to_string(),
35+
SQLOperator::And => "AND".to_string(),
36+
SQLOperator::Or => "OR".to_string(),
37+
}
38+
}
39+
}
40+

0 commit comments

Comments
 (0)