sql_cli/sql/parser/expressions/
comparison.rs1use crate::sql::parser::ast::SqlExpression;
5use crate::sql::parser::lexer::Token;
6use tracing::debug;
7
8use super::{log_parse_decision, trace_parse_entry, trace_parse_exit};
9
10pub fn parse_comparison<P>(parser: &mut P) -> Result<SqlExpression, String>
13where
14 P: ParseComparison + ?Sized,
15{
16 trace_parse_entry("parse_comparison", parser.current_token());
17
18 let mut left = parser.parse_additive()?;
19
20 if matches!(parser.current_token(), Token::Between) {
22 debug!("BETWEEN operator detected");
23 log_parse_decision(
24 "parse_comparison",
25 parser.current_token(),
26 "BETWEEN operator - parsing range bounds",
27 );
28
29 parser.advance(); let lower = parser.parse_additive()?;
31 parser.consume(Token::And)?; let upper = parser.parse_additive()?;
33
34 let result = Ok(SqlExpression::Between {
35 expr: Box::new(left),
36 lower: Box::new(lower),
37 upper: Box::new(upper),
38 });
39 trace_parse_exit("parse_comparison", &result);
40 return result;
41 }
42
43 if matches!(parser.current_token(), Token::Not) {
45 parser.advance(); if matches!(parser.current_token(), Token::In) {
48 debug!("NOT IN operator detected");
49 log_parse_decision(
50 "parse_comparison",
51 parser.current_token(),
52 "NOT IN operator - parsing value list",
53 );
54
55 parser.advance(); parser.consume(Token::LeftParen)?;
57
58 if matches!(parser.current_token(), Token::Select) {
60 debug!("Detected NOT IN subquery");
61 let subquery = parser.parse_subquery()?;
62 parser.consume(Token::RightParen)?;
63
64 let result = Ok(SqlExpression::NotInSubquery {
65 expr: Box::new(left),
66 subquery: Box::new(subquery),
67 });
68 trace_parse_exit("parse_comparison", &result);
69 return result;
70 } else {
71 let values = parser.parse_expression_list()?;
73 parser.consume(Token::RightParen)?;
74
75 let result = Ok(SqlExpression::NotInList {
76 expr: Box::new(left),
77 values,
78 });
79 trace_parse_exit("parse_comparison", &result);
80 return result;
81 }
82 } else {
83 return Err("Expected IN after NOT".to_string());
84 }
85 }
86
87 if matches!(parser.current_token(), Token::Is) {
89 parser.advance(); if matches!(parser.current_token(), Token::Not) {
92 parser.advance(); if matches!(parser.current_token(), Token::Null) {
94 debug!("IS NOT NULL operator detected");
95 log_parse_decision(
96 "parse_comparison",
97 parser.current_token(),
98 "IS NOT NULL operator",
99 );
100
101 parser.advance(); left = SqlExpression::BinaryOp {
103 left: Box::new(left),
104 op: "IS NOT NULL".to_string(),
105 right: Box::new(SqlExpression::Null),
106 };
107 } else {
108 return Err("Expected NULL after IS NOT".to_string());
109 }
110 } else if matches!(parser.current_token(), Token::Null) {
111 debug!("IS NULL operator detected");
112 log_parse_decision(
113 "parse_comparison",
114 parser.current_token(),
115 "IS NULL operator",
116 );
117
118 parser.advance(); left = SqlExpression::BinaryOp {
120 left: Box::new(left),
121 op: "IS NULL".to_string(),
122 right: Box::new(SqlExpression::Null),
123 };
124 } else {
125 return Err("Expected NULL or NOT after IS".to_string());
126 }
127 }
128 else if let Some(op) = get_comparison_op(parser.current_token()) {
130 log_parse_decision(
131 "parse_comparison",
132 parser.current_token(),
133 &format!("Comparison operator '{}' found", op),
134 );
135
136 debug!(operator = %op, "Processing comparison operator");
137
138 parser.advance();
139 let right = parser.parse_additive()?;
140 left = SqlExpression::BinaryOp {
141 left: Box::new(left),
142 op,
143 right: Box::new(right),
144 };
145 }
146
147 let result = Ok(left);
148 trace_parse_exit("parse_comparison", &result);
149 result
150}
151
152pub fn parse_in_operator<P>(parser: &mut P, expr: SqlExpression) -> Result<SqlExpression, String>
155where
156 P: ParseComparison + ?Sized,
157{
158 trace_parse_entry("parse_in_operator", parser.current_token());
159
160 if matches!(parser.current_token(), Token::In) {
161 debug!("IN operator detected");
162 log_parse_decision(
163 "parse_in_operator",
164 parser.current_token(),
165 "IN operator - parsing value list",
166 );
167
168 parser.advance(); parser.consume(Token::LeftParen)?;
170
171 if matches!(parser.current_token(), Token::Select) {
173 debug!("Detected IN subquery");
174 let subquery = parser.parse_subquery()?;
175 parser.consume(Token::RightParen)?;
176
177 let result = Ok(SqlExpression::InSubquery {
178 expr: Box::new(expr),
179 subquery: Box::new(subquery),
180 });
181 trace_parse_exit("parse_in_operator", &result);
182 return result;
183 } else {
184 let values = parser.parse_expression_list()?;
186 parser.consume(Token::RightParen)?;
187
188 let result = Ok(SqlExpression::InList {
189 expr: Box::new(expr),
190 values,
191 });
192 trace_parse_exit("parse_in_operator", &result);
193 return result;
194 }
195 } else {
196 Ok(expr)
197 }
198}
199
200fn get_comparison_op(token: &Token) -> Option<String> {
202 match token {
203 Token::Equal => Some("=".to_string()),
204 Token::NotEqual => Some("!=".to_string()),
205 Token::LessThan => Some("<".to_string()),
206 Token::GreaterThan => Some(">".to_string()),
207 Token::LessThanOrEqual => Some("<=".to_string()),
208 Token::GreaterThanOrEqual => Some(">=".to_string()),
209 Token::Like => Some("LIKE".to_string()),
210 _ => None,
211 }
212}
213
214pub trait ParseComparison {
216 fn current_token(&self) -> &Token;
217 fn advance(&mut self);
218 fn consume(&mut self, expected: Token) -> Result<(), String>;
219
220 fn parse_primary(&mut self) -> Result<SqlExpression, String>;
222 fn parse_additive(&mut self) -> Result<SqlExpression, String>;
223 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
224
225 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
227}