Skip to main content

query_forge/output/formats/
html.rs

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