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 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}