siderite_backends/sql/
dialect.rs1use siderite_orm::{BackendCapabilities, SqlType};
4use std::fmt::Write;
5
6pub trait Dialect: Send + Sync {
8 fn capabilities(&self) -> BackendCapabilities;
10
11 fn write_placeholder(&self, out: &mut String, index: usize);
13
14 fn write_ident(&self, out: &mut String, ident: &str) {
16 out.push('"');
17 for ch in ident.chars() {
18 if ch == '"' {
19 out.push('"');
20 }
21 out.push(ch);
22 }
23 out.push('"');
24 }
25
26 fn cast_type(&self, ty: SqlType) -> &'static str;
28
29 fn offset_requires_limit(&self) -> bool {
31 false
32 }
33
34 fn unbounded_limit(&self) -> &'static str {
37 "-1"
38 }
39
40 fn like_escape_literal(&self) -> &'static str {
43 r"'\'"
44 }
45
46 fn default_values_sql(&self) -> &'static str {
48 " DEFAULT VALUES"
49 }
50
51 fn supports_aggregate_filter(&self) -> bool {
54 true
55 }
56
57 fn evaluates_assignments_in_order(&self) -> bool {
62 false
63 }
64}
65
66#[derive(Debug, Clone, Copy, Default)]
68pub struct Postgres;
69
70impl Dialect for Postgres {
71 fn capabilities(&self) -> BackendCapabilities {
72 BackendCapabilities::postgres()
73 }
74
75 fn write_placeholder(&self, out: &mut String, index: usize) {
76 let _ = write!(out, "${index}");
78 }
79
80 fn cast_type(&self, ty: SqlType) -> &'static str {
81 match ty {
82 SqlType::SmallInt => "SMALLINT",
83 SqlType::Integer => "INTEGER",
84 SqlType::BigInt | SqlType::Duration => "BIGINT",
85 SqlType::Real => "REAL",
86 SqlType::Double => "DOUBLE PRECISION",
87 SqlType::Decimal => "NUMERIC",
88 SqlType::Bool => "BOOLEAN",
89 SqlType::Binary => "BYTEA",
90 SqlType::Date => "DATE",
91 SqlType::Time => "TIME",
92 SqlType::Timestamp => "TIMESTAMPTZ",
93 SqlType::Uuid => "UUID",
94 SqlType::Json => "JSONB",
95 _ => "TEXT",
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy, Default)]
102pub struct Sqlite;
103
104impl Dialect for Sqlite {
105 fn capabilities(&self) -> BackendCapabilities {
106 BackendCapabilities::sqlite()
107 }
108
109 fn write_placeholder(&self, out: &mut String, _index: usize) {
110 out.push('?');
111 }
112
113 fn cast_type(&self, ty: SqlType) -> &'static str {
114 match ty {
115 SqlType::SmallInt
116 | SqlType::Integer
117 | SqlType::BigInt
118 | SqlType::Duration
119 | SqlType::Bool => "INTEGER",
120 SqlType::Real | SqlType::Double => "REAL",
121 SqlType::Decimal => "NUMERIC",
122 SqlType::Binary => "BLOB",
123 _ => "TEXT",
124 }
125 }
126
127 fn offset_requires_limit(&self) -> bool {
128 true
129 }
130}
131
132#[derive(Debug, Clone, Copy, Default)]
139pub struct MySql;
140
141impl Dialect for MySql {
142 fn capabilities(&self) -> BackendCapabilities {
143 BackendCapabilities {
144 returning: false,
145 ..BackendCapabilities::mysql()
146 }
147 }
148
149 fn write_placeholder(&self, out: &mut String, _index: usize) {
150 out.push('?');
151 }
152
153 fn write_ident(&self, out: &mut String, ident: &str) {
154 out.push('`');
155 for ch in ident.chars() {
156 if ch == '`' {
157 out.push('`');
158 }
159 out.push(ch);
160 }
161 out.push('`');
162 }
163
164 fn cast_type(&self, ty: SqlType) -> &'static str {
165 match ty {
166 SqlType::SmallInt
167 | SqlType::Integer
168 | SqlType::BigInt
169 | SqlType::Duration
170 | SqlType::Bool => "SIGNED",
171 SqlType::Real => "FLOAT",
172 SqlType::Double => "DOUBLE",
173 SqlType::Decimal => "DECIMAL(38,10)",
175 SqlType::Binary => "BINARY",
176 SqlType::Date => "DATE",
177 SqlType::Time => "TIME(6)",
178 SqlType::Timestamp => "DATETIME(6)",
179 SqlType::Uuid => "CHAR(36)",
180 SqlType::Json => "JSON",
181 _ => "CHAR",
182 }
183 }
184
185 fn offset_requires_limit(&self) -> bool {
186 true
187 }
188
189 fn unbounded_limit(&self) -> &'static str {
190 "18446744073709551615"
191 }
192
193 fn like_escape_literal(&self) -> &'static str {
194 r"'\\'"
197 }
198
199 fn default_values_sql(&self) -> &'static str {
200 " () VALUES ()"
201 }
202
203 fn supports_aggregate_filter(&self) -> bool {
204 false
205 }
206
207 fn evaluates_assignments_in_order(&self) -> bool {
208 true
209 }
210}