1use rusticx_core::column::ColumnType;
2
3pub trait SqlDialect: Send + Sync {
5 fn placeholder(&self, index: usize) -> String;
7
8 fn quote_ident(&self, name: &str) -> String;
10
11 fn sql_type(&self, col_type: &ColumnType) -> String;
13
14 fn supports_returning(&self) -> bool;
16
17 fn upsert_syntax(&self) -> UpsertSyntax;
19}
20
21#[derive(Debug, Clone, Copy)]
22pub enum UpsertSyntax {
23 OnConflict,
25 InsertIgnore,
27 None,
29}
30
31pub struct PostgresDialect;
34
35impl SqlDialect for PostgresDialect {
36 fn placeholder(&self, index: usize) -> String {
37 format!("${index}")
38 }
39
40 fn quote_ident(&self, name: &str) -> String {
41 format!("\"{name}\"")
42 }
43
44 fn sql_type(&self, col_type: &ColumnType) -> String {
45 match col_type {
46 ColumnType::Bool => "BOOLEAN".into(),
47 ColumnType::SmallInt => "SMALLINT".into(),
48 ColumnType::Int => "INTEGER".into(),
49 ColumnType::BigInt => "BIGINT".into(),
50 ColumnType::Float => "REAL".into(),
51 ColumnType::Double => "DOUBLE PRECISION".into(),
52 ColumnType::Decimal { precision, scale } => format!("DECIMAL({precision},{scale})"),
53 ColumnType::Text => "TEXT".into(),
54 ColumnType::Varchar(n) => format!("VARCHAR({n})"),
55 ColumnType::Char(n) => format!("CHAR({n})"),
56 ColumnType::Bytes => "BYTEA".into(),
57 ColumnType::Uuid => "UUID".into(),
58 ColumnType::Timestamp => "TIMESTAMP".into(),
59 ColumnType::TimestampTz => "TIMESTAMPTZ".into(),
60 ColumnType::Date => "DATE".into(),
61 ColumnType::Time => "TIME".into(),
62 ColumnType::Json => "JSON".into(),
63 ColumnType::Jsonb => "JSONB".into(),
64 ColumnType::Array(inner) => format!("{}[]", self.sql_type(inner)),
65 ColumnType::Dynamic => "JSONB".into(),
66 }
67 }
68
69 fn supports_returning(&self) -> bool {
70 true
71 }
72
73 fn upsert_syntax(&self) -> UpsertSyntax {
74 UpsertSyntax::OnConflict
75 }
76}
77
78pub struct MysqlDialect;
81
82impl SqlDialect for MysqlDialect {
83 fn placeholder(&self, _index: usize) -> String {
84 "?".into()
85 }
86
87 fn quote_ident(&self, name: &str) -> String {
88 format!("`{name}`")
89 }
90
91 fn sql_type(&self, col_type: &ColumnType) -> String {
92 match col_type {
93 ColumnType::Bool => "TINYINT(1)".into(),
94 ColumnType::SmallInt => "SMALLINT".into(),
95 ColumnType::Int => "INT".into(),
96 ColumnType::BigInt => "BIGINT".into(),
97 ColumnType::Float => "FLOAT".into(),
98 ColumnType::Double => "DOUBLE".into(),
99 ColumnType::Decimal { precision, scale } => format!("DECIMAL({precision},{scale})"),
100 ColumnType::Text => "TEXT".into(),
101 ColumnType::Varchar(n) => format!("VARCHAR({n})"),
102 ColumnType::Char(n) => format!("CHAR({n})"),
103 ColumnType::Bytes => "BLOB".into(),
104 ColumnType::Uuid => "CHAR(36)".into(),
105 ColumnType::Timestamp | ColumnType::TimestampTz => "DATETIME(6)".into(),
106 ColumnType::Date => "DATE".into(),
107 ColumnType::Time => "TIME".into(),
108 ColumnType::Json | ColumnType::Jsonb => "JSON".into(),
109 ColumnType::Array(_) => "JSON".into(), ColumnType::Dynamic => "JSON".into(),
111 }
112 }
113
114 fn supports_returning(&self) -> bool {
115 false
116 }
117
118 fn upsert_syntax(&self) -> UpsertSyntax {
119 UpsertSyntax::InsertIgnore
120 }
121}