qail_core/transpiler/
traits.rs1pub const RESERVED_WORDS: &[&str] = &[
5 "order", "group", "user", "table", "select", "from", "where", "join",
6 "left", "right", "inner", "outer", "on", "and", "or", "not", "null",
7 "true", "false", "limit", "offset", "as", "in", "is", "like", "between",
8 "having", "union", "all", "distinct", "case", "when", "then", "else", "end",
9 "create", "alter", "drop", "insert", "update", "delete", "index", "key",
10 "primary", "foreign", "references", "default", "constraint", "check",
11];
12
13pub fn escape_identifier(name: &str) -> String {
17 if name.contains('.') {
19 return name
20 .split('.')
21 .map(|part| escape_single_identifier(part))
22 .collect::<Vec<_>>()
23 .join(".");
24 }
25 escape_single_identifier(name)
26}
27
28fn escape_single_identifier(name: &str) -> String {
30 let lower = name.to_lowercase();
31 let needs_escaping = RESERVED_WORDS.contains(&lower.as_str())
32 || name.chars().any(|c| !c.is_alphanumeric() && c != '_')
33 || name.chars().next().map(|c| c.is_numeric()).unwrap_or(false);
34
35 if needs_escaping {
36 format!("\"{}\"", name.replace('"', "\"\""))
37 } else {
38 name.to_string()
39 }
40}
41
42pub trait SqlGenerator {
44 fn quote_identifier(&self, name: &str) -> String;
46 fn placeholder(&self, index: usize) -> String;
48 fn fuzzy_operator(&self) -> &str;
50 fn bool_literal(&self, val: bool) -> String;
52 fn string_concat(&self, parts: &[&str]) -> String;
54 fn limit_offset(&self, limit: Option<usize>, offset: Option<usize>) -> String;
56 fn json_access(&self, col: &str, path: &[&str]) -> String {
60 let mut parts = vec![self.quote_identifier(col)];
61 for key in path {
62 parts.push(self.quote_identifier(key));
63 }
64 parts.join(".")
65 }
66 fn json_contains(&self, col: &str, value: &str) -> String {
69 format!("{} @> {}", col, value)
70 }
71 fn json_key_exists(&self, col: &str, key: &str) -> String {
74 format!("{} ? {}", col, key)
75 }
76
77 fn json_exists(&self, col: &str, path: &str) -> String {
79 format!("JSON_EXISTS({}, '{}')", col, path)
80 }
81
82 fn json_query(&self, col: &str, path: &str) -> String {
84 format!("JSON_QUERY({}, '{}')", col, path)
85 }
86
87 fn json_value(&self, col: &str, path: &str) -> String {
89 format!("JSON_VALUE({}, '{}')", col, path)
90 }
91}