fraiseql_db/dialect/
sqlite.rs1use std::borrow::Cow;
4
5use super::trait_def::{RowViewColumnType, SqlDialect, UnsupportedOperator};
6
7pub struct SqliteDialect;
11
12impl SqlDialect for SqliteDialect {
13 fn name(&self) -> &'static str {
14 "SQLite"
15 }
16
17 fn quote_identifier(&self, name: &str) -> String {
18 format!("\"{}\"", name.replace('"', "\"\""))
19 }
20
21 fn json_extract_scalar(&self, column: &str, path: &[String]) -> String {
22 let json_path = crate::path_escape::escape_sqlite_json_path(path);
23 format!("json_extract({column}, '{json_path}')")
24 }
25
26 fn placeholder(&self, _n: usize) -> String {
27 "?".to_string()
28 }
29
30 fn cast_to_numeric<'a>(&self, expr: &'a str) -> Cow<'a, str> {
31 Cow::Owned(format!("CAST({expr} AS REAL)"))
32 }
33
34 fn always_false(&self) -> &'static str {
35 "1=0"
36 }
37
38 fn always_true(&self) -> &'static str {
39 "1=1"
40 }
41
42 fn json_array_length(&self, expr: &str) -> String {
43 format!("json_array_length({expr})")
44 }
45
46 fn row_view_column_expr(
47 &self,
48 json_column: &str,
49 field_name: &str,
50 col_type: &RowViewColumnType,
51 ) -> String {
52 let sqlite_type = match col_type {
54 RowViewColumnType::Text
55 | RowViewColumnType::Uuid
56 | RowViewColumnType::Timestamptz
57 | RowViewColumnType::Date => "TEXT",
58 RowViewColumnType::Int32 | RowViewColumnType::Int64 | RowViewColumnType::Boolean => {
59 "INTEGER"
60 },
61 RowViewColumnType::Float64 => "REAL",
62 RowViewColumnType::Json => "TEXT",
63 };
64 format!("CAST(json_extract({json_column}, '$.{field_name}') AS {sqlite_type})")
65 }
66
67 fn create_row_view_ddl(
68 &self,
69 view_name: &str,
70 source_table: &str,
71 columns: &[(String, String)],
72 ) -> String {
73 let quoted_view = self.quote_identifier(view_name);
74 let quoted_table = self.quote_identifier(source_table);
75 let col_list: Vec<String> = columns
76 .iter()
77 .map(|(alias, expr)| format!("{expr} AS {}", self.quote_identifier(alias)))
78 .collect();
79 format!(
81 "DROP VIEW IF EXISTS {quoted_view};\nCREATE VIEW {quoted_view} AS\nSELECT\n {}\nFROM {quoted_table};",
82 col_list.join(",\n ")
83 )
84 }
85
86 fn array_contains_sql(&self, lhs: &str, rhs: &str) -> Result<String, UnsupportedOperator> {
87 Ok(format!("EXISTS (SELECT 1 FROM json_each({lhs}) WHERE value = json({rhs}))"))
89 }
90}