1use std::fmt;
4use std::sync::atomic::{AtomicU8, Ordering};
5use std::sync::{Mutex, MutexGuard};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
9pub enum Flavor {
10 #[default]
11 MySQL,
12 PostgreSQL,
13 SQLite,
14 SQLServer,
15 CQL,
16 ClickHouse,
17 Presto,
18 Oracle,
19 Informix,
20 Doris,
21}
22
23static DEFAULT_FLAVOR: AtomicU8 = AtomicU8::new(Flavor::MySQL as u8);
24static DEFAULT_FLAVOR_LOCK: Mutex<()> = Mutex::new(());
25
26impl Flavor {
27 fn from_u8(v: u8) -> Self {
28 match v {
29 0 => Self::MySQL,
30 1 => Self::PostgreSQL,
31 2 => Self::SQLite,
32 3 => Self::SQLServer,
33 4 => Self::CQL,
34 5 => Self::ClickHouse,
35 6 => Self::Presto,
36 7 => Self::Oracle,
37 8 => Self::Informix,
38 9 => Self::Doris,
39 _ => Self::MySQL,
40 }
41 }
42
43 fn to_u8(self) -> u8 {
44 self as u8
45 }
46}
47
48pub fn default_flavor() -> Flavor {
50 Flavor::from_u8(DEFAULT_FLAVOR.load(Ordering::Relaxed))
51}
52
53pub fn set_default_flavor(flavor: Flavor) -> Flavor {
55 let old = DEFAULT_FLAVOR.swap(flavor.to_u8(), Ordering::Relaxed);
56 Flavor::from_u8(old)
57}
58
59pub struct DefaultFlavorGuard {
61 _lock: MutexGuard<'static, ()>,
62 old: Flavor,
63}
64
65impl Drop for DefaultFlavorGuard {
66 fn drop(&mut self) {
67 set_default_flavor(self.old);
68 }
69}
70
71pub fn set_default_flavor_scoped(flavor: Flavor) -> DefaultFlavorGuard {
73 let lock = DEFAULT_FLAVOR_LOCK
74 .lock()
75 .unwrap_or_else(|e| e.into_inner());
76 let old = set_default_flavor(flavor);
77 DefaultFlavorGuard { _lock: lock, old }
78}
79
80impl fmt::Display for Flavor {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let s = match self {
83 Self::MySQL => "MySQL",
84 Self::PostgreSQL => "PostgreSQL",
85 Self::SQLite => "SQLite",
86 Self::SQLServer => "SQLServer",
87 Self::CQL => "CQL",
88 Self::ClickHouse => "ClickHouse",
89 Self::Presto => "Presto",
90 Self::Oracle => "Oracle",
91 Self::Informix => "Informix",
92 Self::Doris => "Doris",
93 };
94 f.write_str(s)
95 }
96}
97
98#[derive(Debug, thiserror::Error, PartialEq, Eq)]
99pub enum InterpolateError {
100 #[error("sql_builder: interpolation for this flavor is not implemented")]
101 NotImplemented,
102 #[error("sql_builder: not enough args when interpolating")]
103 MissingArgs,
104 #[error("sql_builder: unsupported args when interpolating")]
105 UnsupportedArgs,
106 #[error("{0}")]
107 ValuerError(#[from] crate::valuer::ValuerError),
108}
109
110impl Flavor {
111 pub fn quote(self, name: &str) -> String {
113 match self {
114 Self::MySQL | Self::ClickHouse | Self::Doris => format!("`{name}`"),
115 Self::PostgreSQL
116 | Self::SQLServer
117 | Self::SQLite
118 | Self::Presto
119 | Self::Oracle
120 | Self::Informix => {
121 format!("\"{name}\"")
122 }
123 Self::CQL => format!("'{name}'"),
124 }
125 }
126
127 pub fn prepare_insert_ignore(self) -> &'static str {
129 match self {
130 Flavor::MySQL | Flavor::Oracle => "INSERT IGNORE",
131 Flavor::PostgreSQL => "INSERT",
132 Flavor::SQLite => "INSERT OR IGNORE",
133 _ => "INSERT",
134 }
135 }
136}