use eframe::egui; use egui_extras::{Column, TableBuilder}; use postgres::{Client, NoTls}; struct MyApp { client: Option, tables: Vec, selected_table: Option, loaded_table: Option, columns: Vec, rows: Vec>, error: Option, } impl Default for MyApp { fn default() -> Self { let mut app = Self { client: None, tables: Vec::new(), selected_table: None, loaded_table: None, columns: Vec::new(), rows: Vec::new(), error: None, }; app.connect_and_load_tables(); app } } impl MyApp { fn connect_and_load_tables(&mut self) { let result = Client::connect( "host=localhost user=postgres password=test dbname=testdb", NoTls, ); match result { Ok(mut client) => { let rows = client.query( "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'", &[], ); match rows { Ok(rows) => { self.tables = rows.iter().map(|r| r.get(0)).collect(); } Err(e) => self.error = Some(format!("Query-Fehler: {e}")), } self.client = Some(client); } Err(e) => self.error = Some(format!("Verbindungsfehler: {e}")), } } fn load_table_data(&mut self, table: &str) { if let Some(client) = &mut self.client { let query = format!("SELECT * FROM \"{table}\" LIMIT 100"); match client.query(&query, &[]) { Ok(rows) => { self.columns = rows .first() .map(|r| r.columns().iter().map(|c| c.name().to_string()).collect()) .unwrap_or_default(); self.rows = rows .iter() .map(|r| (0..r.len()).map(|i| value_to_string(r, i)).collect()) .collect(); } Err(e) => self.error = Some(format!("Ladefehler: {e}")), } } } } impl eframe::App for MyApp { fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ui, |ui| { ui.heading("Postgres Tabellen-Browser"); if let Some(err) = &self.error { ui.colored_label(egui::Color32::RED, err); return; } egui::ComboBox::from_label("Tabelle") .selected_text(self.selected_table.clone().unwrap_or_default()) .show_ui(ui, |ui| { for table in &self.tables { ui.selectable_value(&mut self.selected_table, Some(table.clone()), table); } }); if self.selected_table != self.loaded_table { if let Some(table) = self.selected_table.clone() { self.load_table_data(&table); self.loaded_table = Some(table); } } ui.separator(); TableBuilder::new(ui) .columns(Column::auto(), self.columns.len()) .header(20.0, |mut header| { for col in &self.columns { header.col(|ui| { ui.strong(col); }); } }) .body(|mut body| { for row in &self.rows { body.row(18.0, |mut table_row| { for cell in row { table_row.col(|ui| { ui.label(cell); }); } }); } }); }); } } use postgres::Row; fn value_to_string(row: &Row, idx: usize) -> String { if let Ok(v) = row.try_get::<_, Option>(idx) { return v.unwrap_or_else(|| "NULL".into()); } if let Ok(v) = row.try_get::<_, Option>(idx) { return v.map(|x| x.to_string()).unwrap_or_else(|| "NULL".into()); } if let Ok(v) = row.try_get::<_, Option>(idx) { return v.map(|x| x.to_string()).unwrap_or_else(|| "NULL".into()); } if let Ok(v) = row.try_get::<_, Option>(idx) { return v.map(|x| x.to_string()).unwrap_or_else(|| "NULL".into()); } "?".to_string() } fn main() -> eframe::Result<()> { eframe::run_native( "Postgres Browser", eframe::NativeOptions::default(), Box::new(|_cc| Ok(Box::new(MyApp::default()))), ) }