sql_cli/sql/parser/
legacy.rs1use crate::config::schema_config;
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum SqlToken {
10 Select,
11 From,
12 Where,
13 OrderBy,
14 Identifier(String),
15 Column(String),
16 Table(String),
17 Operator(String),
18 String(String),
19 Number(String),
20 Function(String),
21 Comma,
22 Dot,
23 OpenParen,
24 CloseParen,
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum ParseState {
29 Start,
30 AfterSelect,
31 InColumnList,
32 AfterFrom,
33 InTableName,
34 AfterTable,
35 InWhere,
36 InOrderBy,
37}
38
39impl ParseState {
40 pub fn get_suggestions(&self, schema: &Schema) -> Vec<String> {
41 match self {
42 ParseState::Start => vec!["SELECT".to_string()],
43 ParseState::AfterSelect => schema.get_all_columns(),
44 ParseState::InColumnList => {
45 let mut suggestions = schema.get_all_columns();
46 suggestions.push("FROM".to_string());
47 suggestions
48 }
49 ParseState::AfterFrom => schema.get_table_names(),
50 ParseState::InTableName => schema.get_table_names(),
51 ParseState::AfterTable => vec!["WHERE".to_string(), "ORDER BY".to_string()],
52 ParseState::InWhere => schema.get_all_columns(),
53 ParseState::InOrderBy => schema.get_all_columns(),
54 }
55 }
56}
57
58#[derive(Debug, Clone)]
59pub struct ParseContext {
60 pub state: ParseState,
61 pub partial_word: Option<String>,
62}
63
64#[derive(Debug, Clone)]
65pub struct SqlParser {
66 pub tokens: Vec<SqlToken>,
67 pub current_state: ParseState,
68}
69
70impl Default for SqlParser {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76impl SqlParser {
77 #[must_use]
78 pub fn new() -> Self {
79 Self {
80 tokens: Vec::new(),
81 current_state: ParseState::Start,
82 }
83 }
84
85 pub fn parse_quick(&mut self, query: &str) -> ParseState {
86 let query_upper = query.to_uppercase();
88 if query_upper.contains("SELECT") && query_upper.contains("FROM") {
89 if query_upper.contains("WHERE") {
90 ParseState::InWhere
91 } else {
92 ParseState::AfterFrom
93 }
94 } else if query_upper.contains("SELECT") {
95 ParseState::AfterSelect
96 } else {
97 ParseState::Start
98 }
99 }
100
101 pub fn parse_to_position(&mut self, query: &str, position: usize) -> ParseState {
102 let query_up_to_position = &query[..position.min(query.len())];
103 self.parse_quick(query_up_to_position)
104 }
105
106 pub fn get_completion_context(&mut self, input: &str) -> ParseContext {
107 ParseContext {
108 state: self.parse_quick(input),
109 partial_word: None, }
111 }
112
113 pub fn parse_partial(&mut self, input: &str) -> ParseState {
114 self.parse_quick(input)
115 }
116}
117
118#[derive(Debug, Clone)]
119pub struct Schema {
120 tables: Vec<TableInfo>,
121}
122
123#[derive(Debug, Clone)]
124pub struct TableInfo {
125 pub name: String,
126 pub columns: Vec<String>,
127}
128
129impl Default for Schema {
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135impl Schema {
136 #[must_use]
137 pub fn new() -> Self {
138 let trade_deal_columns = schema_config::get_full_trade_deal_columns();
140
141 Self {
142 tables: vec![
143 TableInfo {
144 name: "trade_deal".to_string(),
145 columns: trade_deal_columns,
146 },
147 TableInfo {
148 name: "test".to_string(),
149 columns: vec![
150 "id".to_string(),
151 "name".to_string(),
152 "value".to_string(),
153 "timestamp".to_string(),
154 ],
155 },
156 ],
157 }
158 }
159
160 pub fn get_table_names(&self) -> Vec<String> {
161 self.tables.iter().map(|t| t.name.clone()).collect()
162 }
163
164 pub fn get_columns_for_table(&self, table_name: &str) -> Vec<String> {
165 self.tables
166 .iter()
167 .find(|t| t.name.eq_ignore_ascii_case(table_name))
168 .map(|t| t.columns.clone())
169 .unwrap_or_default()
170 }
171
172 pub fn get_all_columns(&self) -> Vec<String> {
173 let mut all_columns = Vec::new();
174 for table in &self.tables {
175 all_columns.extend(table.columns.clone());
176 }
177 all_columns.sort();
178 all_columns.dedup();
179 all_columns
180 }
181
182 pub fn set_single_table(&mut self, table_name: &str, columns: Vec<String>) {
184 self.tables.clear();
185 self.tables.push(TableInfo {
186 name: table_name.to_string(),
187 columns,
188 });
189 }
190
191 pub fn get_columns(&self, table_name: &str) -> Vec<String> {
192 self.get_columns_for_table(table_name)
193 }
194
195 pub fn get_first_table_name(&self) -> Option<String> {
196 self.tables.first().map(|t| t.name.clone())
197 }
198
199 pub fn add_table(&mut self, name: String, columns: Vec<String>) {
200 self.tables.retain(|t| t.name != name);
202 self.tables.push(TableInfo { name, columns });
203 }
204
205 pub fn has_table(&self, table_name: &str) -> bool {
206 self.tables
207 .iter()
208 .any(|t| t.name.eq_ignore_ascii_case(table_name))
209 }
210}