sqlite_fsr/command/sql/parser/
sql_statement.rs1
2use std::iter::Peekable;
3
4use crate::{command::sql::parser::{sql_token::{Symbol, Tokenize}, SQLToken}, models::error::SQLSyntaxError};
5
6pub enum SQLStatement {
7 Select(SelectStatement),
8 CreateTable(CreateTableStatement),
9}
10
11#[derive(Debug)]
12pub struct CreateTableStatement {
13 pub table_name: String,
14 pub columns: Vec<String>,
15 pub integer_primary_key_column: Option<usize>
16}
17
18impl CreateTableStatement {
19
20 pub fn from_tokens(tokens: Vec<SQLToken>) -> Self {
21
22 let mut tokens_cursor = tokens.into_iter().peekable();
23
24 if let Some(SQLToken::Identifier(second_word)) = tokens_cursor.nth(1) { assert!(second_word == "TABLE"); }
25 else { panic!(); }
26
27 let mut table_name = String::new();
28 if let Some(SQLToken::Identifier(third_word)) = tokens_cursor.next() { table_name = third_word }
29 else { panic!(); }
30
31 let columns_defintions = Self::extract_column_definitions(&mut tokens_cursor);
32 let integer_primary_key_column = columns_defintions.iter().position(|column_definition| {column_definition.len() >= 4 && (column_definition[1].to_uppercase() == "INTEGER" && column_definition[2].to_uppercase() == "PRIMARY" && column_definition[3].to_uppercase() == "KEY") } );
33 let mut columns: Vec<String> = columns_defintions.iter()
34 .map(|column_defintion| column_defintion[0].clone())
35 .collect();
36
37
38 Self { table_name, columns, integer_primary_key_column }
39 }
40
41 fn extract_column_definitions(tokens_iterator: &mut Peekable<std::vec::IntoIter<SQLToken>>) -> Vec<Vec<String>> {
42 let mut column_definitions: Vec<Vec<String>> = Vec::new();
43 if let Some(SQLToken::Symbol(Symbol::LeftParenthesis)) = tokens_iterator.next() {
44
45 while !matches!(tokens_iterator.peek(), Some(&SQLToken::Symbol(Symbol::RightParenthesis))) & !matches!(tokens_iterator.peek(), None){
46 let mut column_defintion_components: Vec<String> = Vec::new();
47
48 loop {
49 let token = tokens_iterator.next_if(|t| !matches!(t, SQLToken::Symbol(Symbol::RightParenthesis)));
50 match token {
51 Some(SQLToken::Identifier(column_defintion_component)) => column_defintion_components.push(column_defintion_component.to_string()),
52 Some(SQLToken::Symbol(Symbol::Comma)) => { break; }
53 _ => break
54 }
55 }
56 column_definitions.push(column_defintion_components);
57 }
58
59 } else { panic!() }
60
61 return column_definitions;
62 }
63
64}
65
66pub struct SelectStatement {
67 pub table_name: String,
68 pub columns: Option<Vec<String>>,
69 pub where_clause: Option<Condition>,
70 pub aggregator_function: Option<AggregatorFunction>
71}
72pub struct Condition {
73 pub left: String,
74 pub operator: String,
75 pub right: String
76}
77
78#[derive(Debug, PartialEq)]
79pub enum AggregatorFunction {
80 COUNT,
81 SUM
82}
83
84impl SelectStatement {
85 pub fn from_tokens(tokens: Vec<SQLToken>) -> Self {
86 let mut tokens_cursor = tokens.into_iter().peekable();
87
88 if let Some(SQLToken::Keyword(first_word)) = tokens_cursor.nth(0) { assert!(first_word == "SELECT") }
89 else { panic!() }
90
91 tokens_cursor.next_if(|t| matches!(t, SQLToken::Symbol(Symbol::LeftParenthesis)));
92
93 let aggregator_function = if let Some(SQLToken::Identifier(token)) = tokens_cursor.peek() {
94 match token.as_str() {
95 "COUNT" => {
96 tokens_cursor.next();
97 Some(AggregatorFunction::COUNT)
98 },
99 "SUM" => {
100 tokens_cursor.next();
101 Some(AggregatorFunction::SUM)
102 },
103 _ => None
104 }
105 } else { panic!("Was expecting Indetifier token.") };
106
107 tokens_cursor.next_if(|t| matches!(t, SQLToken::Symbol(Symbol::LeftParenthesis)));
108
109 let columns: Option<Vec<String>> = if let Some(SQLToken::Identifier(token)) = tokens_cursor.peek() {
110 match token.as_str() {
111 "*" => {
112 tokens_cursor.next();
113 None
114 },
115 _ => Self::extract_columns(&mut tokens_cursor)
116 }
117 } else { panic!() };
118
119 tokens_cursor.next_if(|t| matches!(t, SQLToken::Symbol(Symbol::RightParenthesis)));
120
121 if let Some(SQLToken::Keyword(first_word_after_columns)) = tokens_cursor.next() { assert!(first_word_after_columns == "FROM") }
122 else { panic!() }
123
124 let table_name = match tokens_cursor.next() {
125 Some(SQLToken::Identifier(tablename)) => tablename,
126 _ => panic!()
127 };
128
129 Self { columns, table_name, where_clause: None, aggregator_function }
130 }
131
132 fn extract_columns(tokens_iterator: &mut Peekable<std::vec::IntoIter<SQLToken>>) -> Option<Vec<String>> {
133 let mut columns: Vec<String> = Vec::new();
134
135 while !matches!(tokens_iterator.peek(), Some(&SQLToken::Symbol(Symbol::RightParenthesis)))
136 & !matches!(tokens_iterator.peek(), Some(&SQLToken::Keyword(_)))
137 & !matches!(tokens_iterator.peek(), None) {
138
139 let token = tokens_iterator.next();
140 match token {
141 Some(SQLToken::Identifier(column)) => columns.push(column),
142 Some(SQLToken::Symbol(Symbol::Comma)) => continue,
143 Some(SQLToken::Symbol(Symbol::RightParenthesis)) => break,
144 _ => panic!()
145 }
146
147 }
148
149 match columns.len() {
150 0 => return None,
151 _ => return Some(columns)
152 }
153 }
154}
155
156
157
158pub trait ToSQLStatement {
159 fn to_sql_statment(&self) -> Result<SQLStatement, SQLSyntaxError>;
160}
161
162impl ToSQLStatement for &str {
163 fn to_sql_statment(&self) -> Result<SQLStatement, SQLSyntaxError> {
164 let tokens: Vec<SQLToken> = self.tokenize();
165
166 match &tokens[0] {
167 SQLToken::Keyword(s) if s == "CREATE" => Ok(SQLStatement::CreateTable(CreateTableStatement::from_tokens(tokens))),
168 SQLToken::Keyword(s) if s == "SELECT" => Ok(SQLStatement::Select(SelectStatement::from_tokens(tokens))),
169 _ => Err(SQLSyntaxError::UnexpectedToken(String::new()))
170 }
171 }
172}
173
174impl ToSQLStatement for Vec<&str> {
175 fn to_sql_statment(&self) -> Result<SQLStatement, SQLSyntaxError> {
176 let joined = self.join(" ");
177 joined.as_str().to_sql_statment()
178 }
179}
180
181
182
183pub struct CreateIndexStatement {
184 tablename: String,
185 columns: Vec<String>
186}
187
188impl CreateIndexStatement {
189 pub fn from_tokens(tokens: Vec<SQLToken>) -> Self {
190 let tablename = String::new();
191 let columns = Vec::new();
192
193 CreateIndexStatement { tablename, columns }
194 }
195}