caco3_web/
sql.rs

1mod private {
2    pub trait Sealed {}
3
4    impl<T> Sealed for T where T: AsRef<str> {}
5}
6
7pub trait SqlTrimBoxed: private::Sealed {
8    fn sql_trim_boxed(&self) -> Box<str>;
9}
10
11fn keep_sql_line(line: &str) -> Option<&str> {
12    let trimmed = line.trim();
13    // We do not remove C-style block comments.
14    let is_comment_line = || trimmed.starts_with("--");
15    let is_blank_line = || trimmed.is_empty();
16    let skip = is_comment_line() || is_blank_line();
17    let keep = !skip;
18    keep.then_some(line)
19}
20
21fn sql_trim_boxed(query: &str) -> Box<str> {
22    query
23        .lines()
24        .flat_map(keep_sql_line)
25        .collect::<Vec<_>>()
26        .join("\n")
27        .into_boxed_str()
28}
29
30impl<T: AsRef<str>> SqlTrimBoxed for T {
31    fn sql_trim_boxed(&self) -> Box<str> {
32        sql_trim_boxed(self.as_ref())
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use indoc::indoc;
39
40    use super::*;
41
42    #[test]
43    fn sql_trim_boxed() {
44        let query = indoc! {r#"
45            -- This is comment
46            SELECT * FROM users;
47        "#};
48        let actual = query.sql_trim_boxed();
49        let expect = "SELECT * FROM users;";
50        assert_eq!(actual.as_ref().trim(), expect);
51
52        let query = indoc! {r#"
53            -- PREPARE data_request__update_fsm_state(bigint, fsm_state, timestamptz) AS
54            UPDATE data_request
55            SET fsm_state     = $2,
56                -- Also comment here
57                modified_date = $3
58            WHERE data_request_id = $1;
59            -- Comment after sql
60        "#};
61        let actual = query.sql_trim_boxed();
62        let expect = indoc! {r#"
63            UPDATE data_request
64            SET fsm_state     = $2,
65                modified_date = $3
66            WHERE data_request_id = $1;
67        "#};
68        assert_eq!(actual.as_ref().trim(), expect.trim());
69    }
70}