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