use crate::utils::pgwire::{PgwireLite, Value};
pub struct QueryResultColumn {
pub name: String,
}
pub struct QueryResultRow {
pub values: Vec<String>,
}
pub enum QueryResult {
Data {
columns: Vec<QueryResultColumn>,
rows: Vec<QueryResultRow>,
notices: Vec<String>,
},
Command(String),
Empty,
}
pub fn execute_query(query: &str, client: &mut PgwireLite) -> Result<QueryResult, String> {
match client.query(query) {
Ok(result) => {
let columns: Vec<QueryResultColumn> = result
.column_names
.iter()
.map(|name| QueryResultColumn { name: name.clone() })
.collect();
let rows: Vec<QueryResultRow> = result
.rows
.iter()
.map(|row_map| {
let values: Vec<String> = columns
.iter()
.map(|col| match row_map.get(&col.name) {
Some(Value::String(s)) => s.clone(),
Some(Value::Null) => "NULL".to_string(),
Some(Value::Bool(b)) => b.to_string(),
Some(Value::Integer(i)) => i.to_string(),
Some(Value::Float(f)) => f.to_string(),
Some(_) => "UNKNOWN_TYPE".to_string(),
None => "NULL".to_string(),
})
.collect();
QueryResultRow { values }
})
.collect();
let notices: Vec<String> = result
.notices
.iter()
.map(|notice| {
let mut notice_text = notice
.fields
.get("message")
.cloned()
.unwrap_or_else(|| "Unknown notice".to_string());
if let Some(detail) = notice.fields.get("detail") {
notice_text.push_str("\nDETAIL: ");
notice_text.push_str(detail);
}
if let Some(hint) = notice.fields.get("hint") {
notice_text.push_str("\nHINT: ");
notice_text.push_str(hint);
}
notice_text
})
.collect();
if !rows.is_empty() || !notices.is_empty() {
Ok(QueryResult::Data {
columns,
rows,
notices,
})
} else if result.row_count > 0 {
let command_message = format!(
"Command completed successfully (affected {} rows)",
result.row_count
);
Ok(QueryResult::Command(command_message))
} else {
Ok(QueryResult::Empty)
}
}
Err(e) => Err(format!("Query execution failed: {}", e)),
}
}