table_extractor/parser/
mysql.rs

1use crate::error::Result;
2use crate::{Parser, Table};
3
4pub struct MySqlParser;
5
6impl Parser for MySqlParser {
7    fn parse(&self, input: &str) -> Result<Table> {
8        let lines: Vec<&str> = input.lines().collect();
9
10        if lines.is_empty() {
11            return Ok(Table::new(vec![], vec![]));
12        }
13
14        let mut headers = Vec::new();
15        let mut rows = Vec::new();
16
17        for line in lines {
18            let trimmed = line.trim();
19
20            // Skip empty lines and border lines (starting with +)
21            if trimmed.is_empty() || trimmed.starts_with('+') {
22                continue;
23            }
24
25            // Parse data lines (starting and ending with |)
26            if trimmed.starts_with('|') && trimmed.ends_with('|') {
27                let cells = parse_mysql_row(trimmed);
28
29                if headers.is_empty() {
30                    headers = cells;
31                } else {
32                    rows.push(cells);
33                }
34            }
35        }
36
37        Table::new_validated(headers, rows)
38    }
39}
40
41fn parse_mysql_row(line: &str) -> Vec<String> {
42    // Remove leading and trailing pipes
43    let trimmed = line.trim().trim_start_matches('|').trim_end_matches('|');
44
45    // Estimate column count for pre-allocation
46    let estimated_cols = trimmed.chars().filter(|&c| c == '|').count() + 1;
47    let mut cells = Vec::with_capacity(estimated_cols);
48
49    // Split by | and trim each cell
50    // Pre-allocation reduces allocations for large tables
51    for cell in trimmed.split('|') {
52        cells.push(cell.trim().to_string());
53    }
54
55    cells
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_parse_mysql() {
64        let input = r#"+----+----------------------------+
65| id | name                       |
66+----+----------------------------+
67|  1 | Preston Carlton's Company  |
68|  2 | Fawzia Masud's Company     |
69+----+----------------------------+"#;
70
71        let parser = MySqlParser;
72        let table = parser.parse(input).unwrap();
73
74        assert_eq!(table.headers(), &["id", "name"]);
75        assert_eq!(table.rows().len(), 2);
76        assert_eq!(table.rows()[0], vec!["1", "Preston Carlton's Company"]);
77        assert_eq!(table.rows()[1], vec!["2", "Fawzia Masud's Company"]);
78    }
79}