1#[derive(Debug, Clone, PartialEq)]
10pub struct Comment {
11 pub text: String,
13 pub is_line_comment: bool,
15}
16
17impl Comment {
18 pub fn line(text: String) -> Self {
20 Self {
21 text,
22 is_line_comment: true,
23 }
24 }
25
26 pub fn block(text: String) -> Self {
28 Self {
29 text,
30 is_line_comment: false,
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Hash)]
39pub enum QuoteStyle {
40 None,
42 DoubleQuotes,
44 Brackets,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Hash)]
50pub struct ColumnRef {
51 pub name: String,
52 pub quote_style: QuoteStyle,
53 pub table_prefix: Option<String>,
55}
56
57impl ColumnRef {
58 pub fn unquoted(name: String) -> Self {
60 Self {
61 name,
62 quote_style: QuoteStyle::None,
63 table_prefix: None,
64 }
65 }
66
67 pub fn quoted(name: String) -> Self {
69 Self {
70 name,
71 quote_style: QuoteStyle::DoubleQuotes,
72 table_prefix: None,
73 }
74 }
75
76 pub fn qualified(table: String, name: String) -> Self {
78 Self {
79 name,
80 quote_style: QuoteStyle::None,
81 table_prefix: Some(table),
82 }
83 }
84
85 pub fn to_qualified_string(&self) -> String {
87 match &self.table_prefix {
88 Some(table) => format!("{}.{}", table, self.name),
89 None => self.name.clone(),
90 }
91 }
92
93 pub fn bracketed(name: String) -> Self {
95 Self {
96 name,
97 quote_style: QuoteStyle::Brackets,
98 table_prefix: None,
99 }
100 }
101
102 pub fn to_sql(&self) -> String {
104 let column_part = match self.quote_style {
105 QuoteStyle::None => self.name.clone(),
106 QuoteStyle::DoubleQuotes => format!("\"{}\"", self.name),
107 QuoteStyle::Brackets => format!("[{}]", self.name),
108 };
109
110 match &self.table_prefix {
111 Some(table) => format!("{}.{}", table, column_part),
112 None => column_part,
113 }
114 }
115}
116
117impl PartialEq<str> for ColumnRef {
118 fn eq(&self, other: &str) -> bool {
119 self.name == other
120 }
121}
122
123impl PartialEq<&str> for ColumnRef {
124 fn eq(&self, other: &&str) -> bool {
125 self.name == *other
126 }
127}
128
129impl std::fmt::Display for ColumnRef {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 write!(f, "{}", self.to_sql())
132 }
133}
134
135#[derive(Debug, Clone)]
136pub enum SqlExpression {
137 Column(ColumnRef),
138 StringLiteral(String),
139 NumberLiteral(String),
140 BooleanLiteral(bool),
141 Null, DateTimeConstructor {
143 year: i32,
144 month: u32,
145 day: u32,
146 hour: Option<u32>,
147 minute: Option<u32>,
148 second: Option<u32>,
149 },
150 DateTimeToday {
151 hour: Option<u32>,
152 minute: Option<u32>,
153 second: Option<u32>,
154 },
155 MethodCall {
156 object: String,
157 method: String,
158 args: Vec<SqlExpression>,
159 },
160 ChainedMethodCall {
161 base: Box<SqlExpression>,
162 method: String,
163 args: Vec<SqlExpression>,
164 },
165 FunctionCall {
166 name: String,
167 args: Vec<SqlExpression>,
168 distinct: bool, },
170 WindowFunction {
171 name: String,
172 args: Vec<SqlExpression>,
173 window_spec: WindowSpec,
174 },
175 BinaryOp {
176 left: Box<SqlExpression>,
177 op: String,
178 right: Box<SqlExpression>,
179 },
180 InList {
181 expr: Box<SqlExpression>,
182 values: Vec<SqlExpression>,
183 },
184 NotInList {
185 expr: Box<SqlExpression>,
186 values: Vec<SqlExpression>,
187 },
188 Between {
189 expr: Box<SqlExpression>,
190 lower: Box<SqlExpression>,
191 upper: Box<SqlExpression>,
192 },
193 Not {
194 expr: Box<SqlExpression>,
195 },
196 CaseExpression {
197 when_branches: Vec<WhenBranch>,
198 else_branch: Option<Box<SqlExpression>>,
199 },
200 SimpleCaseExpression {
201 expr: Box<SqlExpression>,
202 when_branches: Vec<SimpleWhenBranch>,
203 else_branch: Option<Box<SqlExpression>>,
204 },
205 ScalarSubquery {
208 query: Box<SelectStatement>,
209 },
210 InSubquery {
213 expr: Box<SqlExpression>,
214 subquery: Box<SelectStatement>,
215 },
216 Unnest {
220 column: Box<SqlExpression>,
221 delimiter: String,
222 },
223 NotInSubquery {
226 expr: Box<SqlExpression>,
227 subquery: Box<SelectStatement>,
228 },
229 InSubqueryTuple {
233 exprs: Vec<SqlExpression>,
234 subquery: Box<SelectStatement>,
235 },
236 NotInSubqueryTuple {
239 exprs: Vec<SqlExpression>,
240 subquery: Box<SelectStatement>,
241 },
242}
243
244#[derive(Debug, Clone)]
245pub struct WhenBranch {
246 pub condition: Box<SqlExpression>,
247 pub result: Box<SqlExpression>,
248}
249
250#[derive(Debug, Clone)]
251pub struct SimpleWhenBranch {
252 pub value: Box<SqlExpression>,
253 pub result: Box<SqlExpression>,
254}
255
256#[derive(Debug, Clone)]
259pub struct WhereClause {
260 pub conditions: Vec<Condition>,
261}
262
263#[derive(Debug, Clone)]
264pub struct Condition {
265 pub expr: SqlExpression,
266 pub connector: Option<LogicalOp>, }
268
269#[derive(Debug, Clone)]
270pub enum LogicalOp {
271 And,
272 Or,
273}
274
275#[derive(Debug, Clone, PartialEq)]
278pub enum SortDirection {
279 Asc,
280 Desc,
281}
282
283impl SortDirection {
284 pub fn as_u8(&self) -> u8 {
285 match self {
286 SortDirection::Asc => 0,
287 SortDirection::Desc => 1,
288 }
289 }
290}
291
292#[derive(Debug, Clone)]
295pub struct OrderByColumn {
296 pub column: String,
297 pub direction: SortDirection,
298}
299
300#[derive(Debug, Clone)]
302pub struct OrderByItem {
303 pub expr: SqlExpression,
304 pub direction: SortDirection,
305}
306
307impl OrderByItem {
308 pub fn from_column_name(name: String, direction: SortDirection) -> Self {
310 Self {
311 expr: SqlExpression::Column(ColumnRef {
312 name,
313 quote_style: QuoteStyle::None,
314 table_prefix: None,
315 }),
316 direction,
317 }
318 }
319
320 pub fn from_expression(expr: SqlExpression, direction: SortDirection) -> Self {
322 Self { expr, direction }
323 }
324}
325
326#[derive(Debug, Clone, PartialEq)]
330pub enum FrameBound {
331 UnboundedPreceding,
332 CurrentRow,
333 Preceding(i64),
334 Following(i64),
335 UnboundedFollowing,
336}
337
338#[derive(Debug, Clone, Copy, PartialEq)]
340pub enum FrameUnit {
341 Rows,
342 Range,
343}
344
345impl FrameUnit {
346 pub fn as_u8(&self) -> u8 {
347 match self {
348 FrameUnit::Rows => 0,
349 FrameUnit::Range => 1,
350 }
351 }
352}
353
354#[derive(Debug, Clone)]
356pub struct WindowFrame {
357 pub unit: FrameUnit,
358 pub start: FrameBound,
359 pub end: Option<FrameBound>, }
361
362#[derive(Debug, Clone)]
363pub struct WindowSpec {
364 pub partition_by: Vec<String>,
365 pub order_by: Vec<OrderByItem>,
366 pub frame: Option<WindowFrame>, }
368
369impl WindowSpec {
370 pub fn compute_hash(&self) -> u64 {
373 use std::collections::hash_map::DefaultHasher;
374 use std::hash::{Hash, Hasher};
375
376 let mut hasher = DefaultHasher::new();
377
378 for col in &self.partition_by {
380 col.hash(&mut hasher);
381 }
382
383 for item in &self.order_by {
385 format!("{:?}", item.expr).hash(&mut hasher);
388 item.direction.as_u8().hash(&mut hasher);
389 }
390
391 if let Some(ref frame) = self.frame {
393 frame.unit.as_u8().hash(&mut hasher);
394 format!("{:?}", frame.start).hash(&mut hasher);
395 if let Some(ref end) = frame.end {
396 format!("{:?}", end).hash(&mut hasher);
397 }
398 }
399
400 hasher.finish()
401 }
402}
403
404#[derive(Debug, Clone, PartialEq)]
408pub enum SetOperation {
409 UnionAll,
411 Union,
413 Intersect,
415 Except,
417}
418
419#[derive(Debug, Clone)]
421pub enum SelectItem {
422 Column {
424 column: ColumnRef,
425 leading_comments: Vec<Comment>,
426 trailing_comment: Option<Comment>,
427 },
428 Expression {
430 expr: SqlExpression,
431 alias: String,
432 leading_comments: Vec<Comment>,
433 trailing_comment: Option<Comment>,
434 },
435 Star {
437 table_prefix: Option<String>, leading_comments: Vec<Comment>,
439 trailing_comment: Option<Comment>,
440 },
441 StarExclude {
443 table_prefix: Option<String>,
444 excluded_columns: Vec<String>,
445 leading_comments: Vec<Comment>,
446 trailing_comment: Option<Comment>,
447 },
448}
449
450#[derive(Debug, Clone)]
451pub struct SelectStatement {
452 pub distinct: bool, pub columns: Vec<String>, pub select_items: Vec<SelectItem>, pub from_source: Option<TableSource>, #[deprecated(note = "Use from_source instead")]
461 pub from_table: Option<String>,
462 #[deprecated(note = "Use from_source instead")]
463 pub from_subquery: Option<Box<SelectStatement>>, #[deprecated(note = "Use from_source instead")]
465 pub from_function: Option<TableFunction>, #[deprecated(note = "Use from_source instead")]
467 pub from_alias: Option<String>, pub joins: Vec<JoinClause>, pub where_clause: Option<WhereClause>,
471 pub order_by: Option<Vec<OrderByItem>>, pub group_by: Option<Vec<SqlExpression>>, pub having: Option<SqlExpression>, pub qualify: Option<SqlExpression>, pub limit: Option<usize>,
476 pub offset: Option<usize>,
477 pub ctes: Vec<CTE>, pub into_table: Option<IntoTable>, pub set_operations: Vec<(SetOperation, Box<SelectStatement>)>, pub leading_comments: Vec<Comment>, pub trailing_comment: Option<Comment>, }
485
486impl Default for SelectStatement {
487 fn default() -> Self {
488 SelectStatement {
489 distinct: false,
490 columns: Vec::new(),
491 select_items: Vec::new(),
492 from_source: None,
493 #[allow(deprecated)]
494 from_table: None,
495 #[allow(deprecated)]
496 from_subquery: None,
497 #[allow(deprecated)]
498 from_function: None,
499 #[allow(deprecated)]
500 from_alias: None,
501 joins: Vec::new(),
502 where_clause: None,
503 order_by: None,
504 group_by: None,
505 having: None,
506 qualify: None,
507 limit: None,
508 offset: None,
509 ctes: Vec::new(),
510 into_table: None,
511 set_operations: Vec::new(),
512 leading_comments: Vec::new(),
513 trailing_comment: None,
514 }
515 }
516}
517
518#[derive(Debug, Clone, PartialEq)]
520pub struct IntoTable {
521 pub name: String,
523}
524
525#[derive(Debug, Clone)]
529pub enum TableFunction {
530 Generator {
531 name: String,
532 args: Vec<SqlExpression>,
533 },
534}
535
536#[derive(Debug, Clone)]
538pub struct CTE {
539 pub name: String,
540 pub column_list: Option<Vec<String>>, pub cte_type: CTEType,
542}
543
544#[derive(Debug, Clone)]
546pub enum CTEType {
547 Standard(SelectStatement),
548 Web(WebCTESpec),
549 File(FileCTESpec),
550}
551
552#[derive(Debug, Clone)]
554pub struct WebCTESpec {
555 pub url: String,
556 pub format: Option<DataFormat>, pub headers: Vec<(String, String)>, pub cache_seconds: Option<u64>, pub method: Option<HttpMethod>, pub body: Option<String>, pub json_path: Option<String>, pub form_files: Vec<(String, String)>, pub form_fields: Vec<(String, String)>, pub template_vars: Vec<TemplateVar>, }
566
567#[derive(Debug, Clone)]
569pub struct TemplateVar {
570 pub placeholder: String, pub table_name: String, pub column: Option<String>, pub index: Option<usize>, }
575
576#[derive(Debug, Clone)]
578pub enum HttpMethod {
579 GET,
580 POST,
581 PUT,
582 DELETE,
583 PATCH,
584}
585
586#[derive(Debug, Clone)]
588pub enum DataFormat {
589 CSV,
590 JSON,
591 Auto, }
593
594#[derive(Debug, Clone)]
601pub struct FileCTESpec {
602 pub path: String,
604 pub recursive: bool,
606 pub glob: Option<String>,
608 pub max_depth: Option<usize>,
610 pub max_files: Option<usize>,
613 pub follow_links: bool,
615 pub include_hidden: bool,
617}
618
619#[derive(Debug, Clone)]
622pub struct PivotAggregate {
623 pub function: String, pub column: String, }
626
627#[derive(Debug, Clone)]
629pub enum TableSource {
630 Table(String), DerivedTable {
632 query: Box<SelectStatement>,
634 alias: String, },
636 Pivot {
639 source: Box<TableSource>, aggregate: PivotAggregate, pivot_column: String, pivot_values: Vec<String>, alias: Option<String>, },
645}
646
647#[derive(Debug, Clone, PartialEq)]
649pub enum JoinType {
650 Inner,
651 Left,
652 Right,
653 Full,
654 Cross,
655}
656
657#[derive(Debug, Clone, PartialEq)]
659pub enum JoinOperator {
660 Equal,
661 NotEqual,
662 LessThan,
663 GreaterThan,
664 LessThanOrEqual,
665 GreaterThanOrEqual,
666}
667
668#[derive(Debug, Clone)]
670pub struct SingleJoinCondition {
671 pub left_expr: SqlExpression, pub operator: JoinOperator, pub right_expr: SqlExpression, }
675
676#[derive(Debug, Clone)]
678pub struct JoinCondition {
679 pub conditions: Vec<SingleJoinCondition>, }
681
682#[derive(Debug, Clone)]
684pub struct JoinClause {
685 pub join_type: JoinType,
686 pub table: TableSource, pub alias: Option<String>, pub condition: JoinCondition, }