1pub trait Dialect: Send + Sync + 'static {
9 const AUTO_PK: &'static str;
14
15 const INSERT_IGNORE: &'static str;
20
21 const CONFLICT_NOTHING: &'static str;
26
27 const COLLATE_NOCASE: &'static str;
32
33 const EPOCH_NOW: &'static str;
38
39 fn ilike(col: &str) -> String;
44
45 fn epoch_from_col(col: &str) -> String;
53}
54
55pub struct Sqlite;
57
58impl Dialect for Sqlite {
59 const AUTO_PK: &'static str = "INTEGER PRIMARY KEY AUTOINCREMENT";
60 const INSERT_IGNORE: &'static str = "INSERT OR IGNORE";
61 const CONFLICT_NOTHING: &'static str = "";
62 const COLLATE_NOCASE: &'static str = "COLLATE NOCASE";
63 const EPOCH_NOW: &'static str = "unixepoch('now')";
64
65 fn ilike(col: &str) -> String {
66 format!("{col} COLLATE NOCASE")
67 }
68
69 fn epoch_from_col(col: &str) -> String {
70 format!("COALESCE(CAST(strftime('%s', {col}) AS INTEGER), 0)")
71 }
72}
73
74pub struct Postgres;
76
77impl Dialect for Postgres {
78 const AUTO_PK: &'static str = "BIGSERIAL PRIMARY KEY";
79 const INSERT_IGNORE: &'static str = "INSERT";
80 const CONFLICT_NOTHING: &'static str = "ON CONFLICT DO NOTHING";
81 const COLLATE_NOCASE: &'static str = "";
82 const EPOCH_NOW: &'static str = "EXTRACT(EPOCH FROM NOW())::BIGINT";
83
84 fn ilike(col: &str) -> String {
85 format!("LOWER({col})")
86 }
87
88 fn epoch_from_col(col: &str) -> String {
89 format!("COALESCE(CAST(EXTRACT(EPOCH FROM {col}) AS BIGINT), 0)")
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[cfg(feature = "sqlite")]
98 mod sqlite {
99 use super::*;
100
101 #[test]
102 fn auto_pk() {
103 assert_eq!(Sqlite::AUTO_PK, "INTEGER PRIMARY KEY AUTOINCREMENT");
104 }
105
106 #[test]
107 fn insert_ignore() {
108 assert_eq!(Sqlite::INSERT_IGNORE, "INSERT OR IGNORE");
109 assert_eq!(Sqlite::CONFLICT_NOTHING, "");
110 }
111
112 #[test]
113 fn epoch_now() {
114 assert_eq!(Sqlite::EPOCH_NOW, "unixepoch('now')");
115 }
116
117 #[test]
118 fn epoch_from_col() {
119 assert_eq!(
120 Sqlite::epoch_from_col("created_at"),
121 "COALESCE(CAST(strftime('%s', created_at) AS INTEGER), 0)"
122 );
123 }
124
125 #[test]
126 fn ilike() {
127 assert_eq!(Sqlite::ilike("name"), "name COLLATE NOCASE");
128 }
129 }
130
131 #[cfg(feature = "postgres")]
132 mod postgres {
133 use super::*;
134
135 #[test]
136 fn auto_pk() {
137 assert_eq!(Postgres::AUTO_PK, "BIGSERIAL PRIMARY KEY");
138 }
139
140 #[test]
141 fn insert_ignore() {
142 assert_eq!(Postgres::INSERT_IGNORE, "INSERT");
143 assert_eq!(Postgres::CONFLICT_NOTHING, "ON CONFLICT DO NOTHING");
144 }
145
146 #[test]
147 fn epoch_now() {
148 assert_eq!(Postgres::EPOCH_NOW, "EXTRACT(EPOCH FROM NOW())::BIGINT");
149 }
150
151 #[test]
152 fn epoch_from_col() {
153 assert_eq!(
154 Postgres::epoch_from_col("created_at"),
155 "COALESCE(CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT), 0)"
156 );
157 }
158
159 #[test]
160 fn ilike() {
161 assert_eq!(Postgres::ilike("name"), "LOWER(name)");
162 }
163 }
164}