Skip to main content

premix_core/
dialect.rs

1use sqlx::Database;
2
3// Chapter 18: Multi-Database Support
4// We define a trait that encapsulates all the requirements for a database to work with Premix.
5/// A trait that encapsulates all the requirements for a database to work with Premix.
6///
7/// Implementing this trait allows Premix to generate correct SQL syntax and handle
8/// database-specific behaviors like placeholder styles and identifier quoting.
9pub trait SqlDialect: Database + sqlx::database::HasStatementCache + Sized + Send + Sync
10where
11    Self::Connection: Send,
12{
13    /// Returns the placeholder for the `n`-th parameter in a query (e.g., "?" or "$1").
14    fn placeholder(n: usize) -> String;
15    /// Returns the SQL fragment for an auto-incrementing Primary Key.
16    fn auto_increment_pk() -> &'static str;
17    /// Returns the number of rows affected by a query result.
18    fn rows_affected(res: &Self::QueryResult) -> u64;
19    /// Returns the ID of the last inserted row.
20    fn last_insert_id(res: &Self::QueryResult) -> i64;
21    /// Returns true if the database supports the `RETURNING` clause.
22    fn supports_returning() -> bool {
23        false
24    }
25
26    /// Returns the SQL function code for getting the current timestamp.
27    fn current_timestamp_fn() -> &'static str {
28        "CURRENT_TIMESTAMP"
29    }
30    /// Returns the native SQL type for 32-bit integers.
31    fn int_type() -> &'static str {
32        "INTEGER"
33    }
34    /// Returns the native SQL type for 64-bit integers.
35    fn bigint_type() -> &'static str {
36        "BIGINT"
37    }
38    /// Returns the native SQL type for text strings.
39    fn text_type() -> &'static str {
40        "TEXT"
41    }
42    /// Returns the native SQL type for booleans.
43    fn bool_type() -> &'static str {
44        "BOOLEAN"
45    }
46    /// Returns the native SQL type for floating-point numbers.
47    fn float_type() -> &'static str {
48        "REAL"
49    }
50    /// Returns the native SQL type for binary data.
51    fn blob_type() -> &'static str {
52        "BLOB"
53    }
54
55    /// Quotes an identifier (table/column name) to prevent SQL injection.
56    fn quote_identifier(ident: &str) -> String {
57        format!("`{}`", ident.replace('`', "``"))
58    }
59}
60
61#[cfg(feature = "sqlite")]
62impl SqlDialect for sqlx::Sqlite {
63    fn placeholder(_n: usize) -> String {
64        "?".to_string()
65    }
66    fn auto_increment_pk() -> &'static str {
67        "INTEGER PRIMARY KEY"
68    }
69    fn bigint_type() -> &'static str {
70        "INTEGER"
71    }
72    fn blob_type() -> &'static str {
73        "BLOB"
74    }
75    fn rows_affected(res: &sqlx::sqlite::SqliteQueryResult) -> u64 {
76        res.rows_affected()
77    }
78    fn last_insert_id(res: &sqlx::sqlite::SqliteQueryResult) -> i64 {
79        res.last_insert_rowid()
80    }
81    fn supports_returning() -> bool {
82        false
83    }
84}
85
86#[cfg(feature = "postgres")]
87impl SqlDialect for sqlx::Postgres {
88    fn placeholder(n: usize) -> String {
89        format!("${}", n)
90    }
91    fn auto_increment_pk() -> &'static str {
92        "SERIAL PRIMARY KEY"
93    }
94    fn int_type() -> &'static str {
95        "INTEGER"
96    }
97    fn bigint_type() -> &'static str {
98        "BIGINT"
99    }
100    fn text_type() -> &'static str {
101        "TEXT"
102    }
103    fn bool_type() -> &'static str {
104        "BOOLEAN"
105    }
106    fn float_type() -> &'static str {
107        "DOUBLE PRECISION"
108    }
109    fn blob_type() -> &'static str {
110        "BYTEA"
111    }
112    fn rows_affected(res: &sqlx::postgres::PgQueryResult) -> u64 {
113        res.rows_affected()
114    }
115    fn last_insert_id(_res: &sqlx::postgres::PgQueryResult) -> i64 {
116        0
117    }
118    fn supports_returning() -> bool {
119        true
120    }
121    fn quote_identifier(ident: &str) -> String {
122        format!("\"{}\"", ident.replace('"', "\"\""))
123    }
124}
125
126#[cfg(feature = "mysql")]
127impl SqlDialect for sqlx::MySql {
128    fn placeholder(_n: usize) -> String {
129        "?".to_string()
130    }
131    fn auto_increment_pk() -> &'static str {
132        "INTEGER AUTO_INCREMENT PRIMARY KEY"
133    }
134    fn bigint_type() -> &'static str {
135        "BIGINT"
136    }
137    fn blob_type() -> &'static str {
138        "LONGBLOB"
139    }
140    fn rows_affected(res: &sqlx::mysql::MySqlQueryResult) -> u64 {
141        res.rows_affected()
142    }
143    fn last_insert_id(res: &sqlx::mysql::MySqlQueryResult) -> i64 {
144        res.last_insert_id() as i64
145    }
146    fn supports_returning() -> bool {
147        false
148    }
149}