pg_query/
summary_result.rs1use std::collections::HashMap;
2use std::collections::HashSet;
3use std::iter::FromIterator;
4use std::string::String;
5
6use crate::protobuf::summary_result::Context;
7use crate::*;
8
9#[derive(Debug, PartialEq)]
23pub struct SummaryResult {
24 pub protobuf: protobuf::SummaryResult,
25 pub warnings: Vec<String>,
26 pub tables: Vec<Table>,
27 pub aliases: HashMap<String, String>,
28 pub cte_names: Vec<String>,
29 pub functions: Vec<Function>,
30 pub filter_columns: Vec<FilterColumn>,
31 pub truncated_query: String,
32 pub statement_types: Vec<String>,
33}
34
35impl SummaryResult {
36 pub fn new(protobuf: protobuf::SummaryResult, stderr: String) -> Self {
37 let warnings = stderr
38 .lines()
39 .filter_map(|l| {
40 if l.starts_with("WARNING") {
41 Some(l.trim().into())
42 } else {
43 None
44 }
45 })
46 .collect();
47 let mut tables: HashSet<Table> = HashSet::new();
48 let aliases = protobuf.aliases.clone();
49 let cte_names: HashSet<String> = HashSet::from_iter(protobuf.cte_names.to_owned());
50 let mut functions: HashSet<Function> = HashSet::new();
51 let mut filter_columns: HashSet<FilterColumn> = HashSet::new();
52 let truncated_query = protobuf.truncated_query.to_owned();
53 let statement_types = protobuf.statement_types.clone();
54
55 for table in &protobuf.tables {
56 tables.insert(Table::from(table));
57 }
58
59 for function in &protobuf.functions {
60 functions.insert(Function::from(function));
61 }
62
63 for filter_column in &protobuf.filter_columns {
64 filter_columns.insert(FilterColumn::from(filter_column));
65 }
66
67 Self {
68 protobuf,
69 warnings,
70 tables: Vec::from_iter(tables),
71 aliases,
72 cte_names: Vec::from_iter(cte_names),
73 functions: Vec::from_iter(functions),
74 filter_columns: Vec::from_iter(filter_columns),
75 truncated_query,
76 statement_types,
77 }
78 }
79
80 pub fn tables(&self) -> Vec<String> {
82 let mut tables = HashSet::new();
83 self.tables.iter().for_each(|table| {
84 tables.insert(table.name.clone());
85 });
86 Vec::from_iter(tables)
87 }
88
89 pub fn select_tables(&self) -> Vec<String> {
91 self.tables
92 .iter()
93 .filter_map(|table| match &table.context {
94 Context::Select => Some(table.name.to_string()),
95 _ => None,
96 })
97 .collect()
98 }
99
100 pub fn dml_tables(&self) -> Vec<String> {
102 self.tables
103 .iter()
104 .filter_map(|table| match &table.context {
105 Context::Dml => Some(table.name.to_string()),
106 _ => None,
107 })
108 .collect()
109 }
110
111 pub fn ddl_tables(&self) -> Vec<String> {
113 self.tables
114 .iter()
115 .filter_map(|table| match &table.context {
116 Context::Ddl => Some(table.name.to_string()),
117 _ => None,
118 })
119 .collect()
120 }
121
122 pub fn functions(&self) -> Vec<String> {
124 let mut functions = HashSet::new();
125 self.functions.iter().for_each(|f| {
126 functions.insert(f.name.to_string());
127 });
128 Vec::from_iter(functions)
129 }
130
131 pub fn ddl_functions(&self) -> Vec<String> {
133 self.functions
134 .iter()
135 .filter_map(|function| match &function.context {
136 Context::Ddl => Some(function.name.to_string()),
137 _ => None,
138 })
139 .collect()
140 }
141
142 pub fn call_functions(&self) -> Vec<String> {
144 self.functions
145 .iter()
146 .filter_map(|function| match &function.context {
147 Context::Call => Some(function.name.to_string()),
148 _ => None,
149 })
150 .collect()
151 }
152
153 pub fn statement_types(&self) -> Vec<&str> {
155 self.statement_types.iter().map(AsRef::as_ref).collect()
158 }
159}
160
161#[derive(Debug, Eq, Hash, PartialEq)]
162pub struct Table {
163 pub name: String,
164 pub schema_name: String,
165 pub table_name: String,
166 pub context: Context,
167}
168
169impl From<&protobuf::summary_result::Table> for Table {
170 fn from(v: &protobuf::summary_result::Table) -> Self {
171 Self {
172 name: v.name.to_owned(),
173 schema_name: v.schema_name.to_owned(),
174 table_name: v.table_name.to_owned(),
175 context: Context::try_from(v.context).unwrap_or(Context::None),
176 }
177 }
178}
179
180#[derive(Debug, Eq, Hash, PartialEq)]
181pub struct Function {
182 pub name: String,
183 pub function_name: String,
184 pub schema_name: Option<String>,
185 pub context: Context,
186}
187
188impl From<&protobuf::summary_result::Function> for Function {
189 fn from(v: &protobuf::summary_result::Function) -> Self {
190 let schema_name = (!v.schema_name.is_empty()).then(|| v.schema_name.to_owned());
191
192 Function {
193 name: v.name.to_owned(),
194 function_name: v.function_name.to_owned(),
195 schema_name,
196 context: Context::try_from(v.context).unwrap_or(Context::None),
197 }
198 }
199}
200
201#[derive(Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
202pub struct FilterColumn {
203 pub schema_name: Option<String>,
204 pub table_name: Option<String>,
205 pub column: String,
206}
207
208impl From<&protobuf::summary_result::FilterColumn> for FilterColumn {
209 fn from(v: &protobuf::summary_result::FilterColumn) -> Self {
210 let schema_name = (!v.schema_name.is_empty()).then(|| v.schema_name.to_owned());
211 let table_name = (!v.table_name.is_empty()).then(|| v.table_name.to_owned());
212 let column = v.column.to_owned();
213
214 Self {
215 schema_name,
216 table_name,
217 column,
218 }
219 }
220}