1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
26pub enum Dialect {
27 #[default]
31 SQLite,
32
33 PostgreSQL,
37
38 MySQL,
42}
43
44impl Dialect {
45 #[inline]
50 #[must_use]
51 pub const fn uses_numbered_placeholders(&self) -> bool {
52 matches!(self, Dialect::PostgreSQL)
53 }
54
55 #[must_use]
73 pub fn parse(s: &str) -> Option<Self> {
74 if s.eq_ignore_ascii_case("sqlite")
76 || s.eq_ignore_ascii_case("turso")
77 || s.eq_ignore_ascii_case("libsql")
78 {
79 Some(Dialect::SQLite)
80 } else if s.eq_ignore_ascii_case("postgresql")
81 || s.eq_ignore_ascii_case("postgres")
82 || s.eq_ignore_ascii_case("pg")
83 {
84 Some(Dialect::PostgreSQL)
85 } else if s.eq_ignore_ascii_case("mysql") {
86 Some(Dialect::MySQL)
87 } else {
88 None
89 }
90 }
91
92 #[must_use]
96 pub const fn table_prefix(&self) -> &'static str {
97 match self {
98 Dialect::SQLite => "#[SQLiteTable",
99 Dialect::PostgreSQL => "#[PostgresTable",
100 Dialect::MySQL => "#[MySQLTable",
101 }
102 }
103
104 #[must_use]
106 pub const fn index_prefix(&self) -> &'static str {
107 match self {
108 Dialect::SQLite => "#[SQLiteIndex",
109 Dialect::PostgreSQL => "#[PostgresIndex",
110 Dialect::MySQL => "#[MySQLIndex",
111 }
112 }
113
114 #[must_use]
116 pub const fn schema_derive(&self) -> &'static str {
117 match self {
118 Dialect::SQLite => "#[derive(SQLiteSchema)]",
119 Dialect::PostgreSQL => "#[derive(PostgresSchema)]",
120 Dialect::MySQL => "#[derive(MySQLSchema)]",
121 }
122 }
123
124 #[must_use]
126 pub const fn as_str(&self) -> &'static str {
127 match self {
128 Dialect::SQLite => "sqlite",
129 Dialect::PostgreSQL => "postgresql",
130 Dialect::MySQL => "mysql",
131 }
132 }
133}
134
135impl core::fmt::Display for Dialect {
136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 f.write_str(self.as_str())
138 }
139}
140
141impl core::str::FromStr for Dialect {
142 type Err = DialectParseError;
143
144 fn from_str(s: &str) -> Result<Self, Self::Err> {
145 Dialect::parse(s).ok_or(DialectParseError)
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
151pub struct DialectParseError;
152
153impl core::fmt::Display for DialectParseError {
154 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
155 f.write_str("unknown dialect")
156 }
157}
158
159#[cfg(feature = "std")]
160impl std::error::Error for DialectParseError {}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_dialect_parse() {
168 assert_eq!(Dialect::parse("sqlite"), Some(Dialect::SQLite));
169 assert_eq!(Dialect::parse("SQLite"), Some(Dialect::SQLite));
170 assert_eq!(Dialect::parse("turso"), Some(Dialect::SQLite));
171 assert_eq!(Dialect::parse("libsql"), Some(Dialect::SQLite));
172
173 assert_eq!(Dialect::parse("postgresql"), Some(Dialect::PostgreSQL));
174 assert_eq!(Dialect::parse("postgres"), Some(Dialect::PostgreSQL));
175 assert_eq!(Dialect::parse("pg"), Some(Dialect::PostgreSQL));
176 assert_eq!(Dialect::parse("PG"), Some(Dialect::PostgreSQL));
177
178 assert_eq!(Dialect::parse("mysql"), Some(Dialect::MySQL));
179 assert_eq!(Dialect::parse("MySQL"), Some(Dialect::MySQL));
180
181 assert_eq!(Dialect::parse("unknown"), None);
182 assert_eq!(Dialect::parse(""), None);
183 }
184
185 #[test]
186 fn test_dialect_placeholders() {
187 assert!(!Dialect::SQLite.uses_numbered_placeholders());
188 assert!(Dialect::PostgreSQL.uses_numbered_placeholders());
189 assert!(!Dialect::MySQL.uses_numbered_placeholders());
190 }
191
192 #[test]
193 fn test_dialect_display() {
194 assert_eq!(format!("{}", Dialect::SQLite), "sqlite");
195 assert_eq!(format!("{}", Dialect::PostgreSQL), "postgresql");
196 assert_eq!(format!("{}", Dialect::MySQL), "mysql");
197 }
198}