1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
use crate::{QueryResult, QueryValue}; use crate::value::display_value; use super::utils::escape_xml_text; pub fn render_html(result: &QueryResult) -> String { let mut output = String::from( "<!DOCTYPE html>\n\ <html>\n\ <head><meta charset=\"UTF-8\"><title>Query Result</title></head>\n\ <body>\n\ <table>\n\ <thead>\n\ <tr>\n", ); for column in &result.columns { output.push_str(" <th>"); output.push_str(&escape_xml_text(column)); output.push_str("</th>\n"); } output.push_str("</tr>\n</thead>\n<tbody>\n"); for row in &result.rows { output.push_str("<tr>\n"); for column_index in 0..result.columns.len() { let value = row.get(column_index).unwrap_or(&QueryValue::Null); output.push_str(" <td>"); output.push_str(&escape_xml_text(&display_value(value))); output.push_str("</td>\n"); } output.push_str("</tr>\n"); } output.push_str("</tbody>\n</table>\n</body>\n</html>"); output } #[cfg(test)] mod tests { use super::render_html; use crate::{QueryResult, QueryValue}; #[test] fn renders_html_with_title() { let html = render_html(&QueryResult { columns: vec!["product".to_owned()], rows: vec![vec![QueryValue::Text("Keyboard".to_owned())]], }); assert!(html.contains("<title>Query Result</title>")); } }