1use std::collections::HashMap;
2
3use sql_fun_core::IVec;
4
5use crate::{
6 sem::{
7 AnalysisError, AstAndContextPair, DeleteStatement, InsertStatement, ParseContext,
8 SelectStatement, SemAst, UpdateStatement, analyze_delete_statement,
9 analyze_insert_statement, analyze_select, analyze_update_statement,
10 create_table::{ColumnDefinition, ColumnName},
11 },
12 syn::{ListOpt, Opt, ScanToken},
13};
14
15pub type CteName = String;
17
18#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
20pub enum CteStatement {
21 Select(Box<SelectStatement>),
23 Insert(InsertStatement),
25 Update(UpdateStatement),
27 Delete(DeleteStatement),
29}
30
31impl CteStatement {
32 fn analyze_syn<TParseContext>(
33 context: TParseContext,
34 syn: crate::syn::CommonTableExpr,
35 tokens: &IVec<ScanToken>,
36 ) -> Result<(CteStatement, TParseContext), AnalysisError>
37 where
38 TParseContext: ParseContext,
39 {
40 let query = syn.get_ctequery();
41
42 if let Some(select) = query.as_select_stmt().as_inner() {
43 let AstAndContextPair(sem, new_context) = analyze_select(context, select, tokens)?;
44 let SemAst::SelectStatement(s) = sem else {
45 AnalysisError::raise_unexpected_none("SemAst::SelectStatement")?
46 };
47 Ok((CteStatement::Select(Box::new(s)), new_context))
48 } else if let Some(insert) = query.as_insert_stmt().as_inner() {
49 let (sem, new_context) = analyze_insert_statement(context, &None, insert)?;
50 let SemAst::InsertStatement(s) = sem else {
51 AnalysisError::raise_unexpected_none("SemAst::InsertStatement")?
52 };
53 Ok((CteStatement::Insert(s), new_context))
54 } else if let Some(update) = query.as_update_stmt().as_inner() {
55 let (sem, new_context) = analyze_update_statement(context, &None, update)?;
56 let SemAst::UpdateStatement(s) = sem else {
57 AnalysisError::raise_unexpected_none("SemAst::UpdateStatement")?
58 };
59 Ok((CteStatement::Update(s), new_context))
60 } else if let Some(delete) = query.as_delete_stmt().as_inner() {
61 let (sem, new_context) = analyze_delete_statement(context, &None, delete)?;
62 let SemAst::DeleteStatement(s) = sem else {
63 AnalysisError::raise_unexpected_none("SemAst::DeleteStatement")?
64 };
65 Ok((CteStatement::Delete(s), new_context))
66 } else {
67 AnalysisError::raise_unexpected_none("common_table_expr.query")?
68 }
69 }
70
71 pub fn get_column<TParseContext>(
73 &self,
74 _context: &TParseContext,
75 _name: &ColumnName,
76 ) -> Option<ColumnDefinition>
77 where
78 TParseContext: ParseContext,
79 {
80 todo!()
81 }
82
83 pub fn get_column_at<TParseContext>(
85 &self,
86 _context: &TParseContext,
87 _index: usize,
88 ) -> Option<&ColumnDefinition>
89 where
90 TParseContext: ParseContext,
91 {
92 todo!()
93 }
94
95 pub fn get_column_def_with_skip_count<TParseContext>(
97 &self,
98 _context: &TParseContext,
99 _name: &ColumnName,
100 _skip_count: usize,
101 ) -> Option<&ColumnDefinition>
102 where
103 TParseContext: ParseContext,
104 {
105 todo!()
106 }
107
108 pub(crate) fn has_column(&self, _column: &ColumnName) -> bool {
110 todo!()
111 }
112}
113
114#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
116pub struct WithClause(HashMap<CteName, CteStatement>);
117
118impl std::hash::Hash for WithClause {
119 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
120 for (k, v) in &self.0 {
121 k.hash(state);
122 v.hash(state);
123 }
124 }
125}
126
127impl WithClause {
128 #[must_use]
130 pub fn get(&self, name: &CteName) -> Option<&CteStatement> {
131 self.0.get(name)
132 }
133
134 pub fn insert(&mut self, name: &CteName, statement: CteStatement) {
136 self.0.insert(name.clone(), statement);
137 }
138
139 pub fn analyze<TParseContext>(
141 mut context: TParseContext,
142 syn: crate::syn::WithClauseOpt,
143 tokens: &IVec<ScanToken>,
144 ) -> Result<(WithClause, TParseContext), AnalysisError>
145 where
146 TParseContext: ParseContext,
147 {
148 let mut with = WithClause::default();
149 let Some(ctes) = syn.get_ctes().as_inner() else {
150 return Ok((with, context));
151 };
152
153 for cte in ctes {
154 let Some(table_expr) = cte.as_common_table_expr().as_inner() else {
155 AnalysisError::raise_unexpected_none("cte.as_common_table_expr")?
156 };
157 let name = table_expr.get_ctename();
158 let (cte, new_context) = CteStatement::analyze_syn(context, table_expr, tokens)?;
159 with.insert(&name, cte);
160 context = new_context;
161 }
162 Ok((with, context))
163 }
164}