Normalize query for cache key Removes extra whitespace, lowercases keywords, but preserves string literals
(query: &str)
| 142 | /// Normalize query for cache key |
| 143 | /// Removes extra whitespace, lowercases keywords, but preserves string literals |
| 144 | pub fn normalize_query(query: &str) -> String { |
| 145 | let mut normalized = String::with_capacity(query.len()); |
| 146 | let mut in_string = false; |
| 147 | let mut string_delimiter = '\0'; |
| 148 | let chars = query.chars().peekable(); |
| 149 | |
| 150 | for ch in chars { |
| 151 | match ch { |
| 152 | '\'' | '"' if !in_string => { |
| 153 | in_string = true; |
| 154 | string_delimiter = ch; |
| 155 | normalized.push(ch); |
| 156 | } |
| 157 | ch if ch == string_delimiter && in_string => { |
| 158 | in_string = false; |
| 159 | string_delimiter = '\0'; |
| 160 | normalized.push(ch); |
| 161 | } |
| 162 | ' ' | '\t' | '\n' | '\r' if !in_string => { |
| 163 | // Collapse whitespace |
| 164 | if !normalized.ends_with(' ') && !normalized.is_empty() { |
| 165 | normalized.push(' '); |
| 166 | } |
| 167 | } |
| 168 | ch if !in_string => { |
| 169 | // Lowercase keywords outside strings |
| 170 | normalized.push(ch.to_ascii_lowercase()); |
| 171 | } |
| 172 | ch => normalized.push(ch), |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | normalized.trim().to_string() |
| 177 | } |
| 178 | } |