1use crate::{
4 ast,
5 expr::Identifier,
6 hierarchy::Path,
7 sql::visitor::{TableWithJoins, Visitor},
8 visitor::Visited,
9};
10use colored::Colorize;
11use itertools::Itertools;
12use std::{
13 collections::BTreeMap,
14 fmt,
15 iter::Iterator,
16 ops::{Deref, DerefMut},
17};
18
19#[derive(Clone, Debug, Hash, PartialEq, Eq)]
21pub struct QueryNames<'a>(BTreeMap<(&'a ast::Query, ast::ObjectName), Option<&'a ast::Query>>);
22
23impl<'a> QueryNames<'a> {
24 pub fn new() -> Self {
26 QueryNames(BTreeMap::new())
27 }
28
29 pub fn set(&mut self, name: ast::ObjectName, referred: &'a ast::Query) -> &mut Self {
31 for ((_, n), r) in self.iter_mut() {
32 if (*n == name) && r.is_none() {
33 *r = Some(referred);
34 }
35 }
36 self
37 }
38
39 pub fn name_referred(
41 &self,
42 query: &'a ast::Query,
43 ) -> impl Iterator<Item = (&ast::ObjectName, &'a ast::Query)> {
44 self.iter()
45 .filter_map(move |((q, n), r)| if *q == query { Some((n, (*r)?)) } else { None })
46 }
47}
48
49impl<'a> Deref for QueryNames<'a> {
50 type Target = BTreeMap<(&'a ast::Query, ast::ObjectName), Option<&'a ast::Query>>;
51
52 fn deref(&self) -> &Self::Target {
53 &self.0
54 }
55}
56
57impl<'a> DerefMut for QueryNames<'a> {
58 fn deref_mut(&mut self) -> &mut Self::Target {
59 &mut self.0
60 }
61}
62
63impl<'a> IntoIterator for QueryNames<'a> {
64 type Item =
65 <BTreeMap<(&'a ast::Query, ast::ObjectName), Option<&'a ast::Query>> as IntoIterator>::Item;
66 type IntoIter = <BTreeMap<(&'a ast::Query, ast::ObjectName), Option<&'a ast::Query>> as IntoIterator>::IntoIter;
67
68 fn into_iter(self) -> Self::IntoIter {
69 self.0.into_iter()
70 }
71}
72
73impl<'a> fmt::Display for QueryNames<'a> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(
76 f,
77 "Query Names\n{}",
78 self.0
79 .iter()
80 .map(|((q, n), r)| match r {
81 Some(r) => format!(
82 "{} | {} -> {}",
83 format!("{q}").blue(),
84 format!("{n}").red(),
85 format!("{r}").green()
86 ),
87 None => format!(
88 "{} | {} -> {}",
89 format!("{q}").blue(),
90 format!("{n}").red(),
91 format!("?").bold().green()
92 ),
93 })
94 .join(",\n")
95 )
96 }
97}
98
99#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
101pub struct IntoQueryNamesVisitor;
102
103fn names_from_set_expr<'a>(set_expr: &'a ast::SetExpr) -> Vec<&'a ast::ObjectName> {
104 match set_expr {
105 ast::SetExpr::Select(select) => select
106 .from
107 .iter()
108 .flat_map(|table_with_joins| TableWithJoins::new(table_with_joins).names())
109 .collect(),
110 ast::SetExpr::SetOperation { left, right, .. } => names_from_set_expr(left.as_ref())
111 .into_iter()
112 .chain(names_from_set_expr(right.as_ref()))
113 .collect(),
114 _ => todo!(),
115 }
116}
117
118impl<'a> Visitor<'a, QueryNames<'a>> for IntoQueryNamesVisitor {
119 fn query(
120 &self,
121 query: &'a ast::Query,
122 dependencies: Visited<'a, ast::Query, QueryNames<'a>>,
123 ) -> QueryNames<'a> {
124 let mut query_names = QueryNames::new();
125 for (_, dependency) in dependencies {
127 query_names.extend(dependency);
128 }
129 for name in names_from_set_expr(query.body.as_ref()) {
131 query_names.insert((query, name.clone()), None);
132 }
133 if let Some(with) = &query.with {
135 for cte in &with.cte_tables {
136 query_names.set(
137 ast::ObjectName(vec![cte.alias.name.clone()]),
138 cte.query.as_ref(),
139 );
140 }
141 }
142 query_names
143 }
144}
145
146impl Path for ast::ObjectName {
148 fn path(self) -> Vec<String> {
149 self.0.path()
150 }
151}
152
153impl From<&ast::ObjectName> for Identifier {
155 fn from(value: &ast::ObjectName) -> Self {
156 value.0.iter().map(|i| i.value.clone()).collect()
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use colored::Colorize;
163
164 use super::*;
165 use crate::{sql::relation, visitor::Acceptor as _};
166
167 #[test]
168 fn test_query_names() {
169 let query_1 = relation::parse("select * from table_1").unwrap();
170 let query_2 = relation::parse("select * from table_2").unwrap();
171 let query_3 = relation::parse("select * from table_3").unwrap();
172 let query_4 = relation::parse("select * from table_4").unwrap();
173 let name_1 = ast::ObjectName(vec!["name_1".into()]);
174 let name_2 = ast::ObjectName(vec!["name_2".into()]);
175 let name_3 = ast::ObjectName(vec!["name_3".into()]);
176 println!("query_1 = {}", query_1.to_string().blue());
177 let mut query_names_1 = QueryNames::new();
178 let mut query_names_2 = QueryNames::new();
179 let mut query_names_3 = QueryNames::new();
180 query_names_2.insert((&query_1, name_1), None);
181 query_names_2.insert((&query_1, name_2), Some(&query_2));
182 query_names_3.insert((&query_1, name_3.clone()), Some(&query_3));
183 query_names_3.insert((&query_2, name_3.clone()), None);
184 query_names_3.insert((&query_3, name_3.clone()), None);
185 query_names_1.extend(query_names_2);
186 query_names_1.extend(query_names_3);
187 println!("BEFORE: {query_names_1}");
188 query_names_1.set(name_3.clone(), &query_4);
189 println!("AFTER: {query_names_1}");
190 }
191
192 const COMPLEX_QUERY: &str = "
193 with view_1 as (select * from schema.table_1),
194 view_2 as (select * from view_1)
195 select 2*a, b+1 from (select view_2.c as a, right.d as b from (select * from view_2) LEFT OUTER JOIN schema.table_2 as right ON view_1.id = table_2.id);
196 select * from table_1;
197 ";
198
199 #[test]
200 fn test_query_names_visitor() {
201 let query = relation::parse(COMPLEX_QUERY).unwrap();
202 println!("Query = {}", query.to_string().blue());
203 let visitor = IntoQueryNamesVisitor;
204 let query_names = query.accept(visitor);
205 println!("{}", query_names);
206 }
207}