drizzle_types/sqlite/ddl/
index.rs1use crate::alloc_prelude::*;
8
9#[cfg(feature = "serde")]
10use crate::serde_helpers::{cow_from_string, cow_option_from_string};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
20pub enum IndexOrigin {
21 #[default]
23 Manual,
24 Auto,
26}
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
36pub struct IndexColumnDef {
37 pub value: &'static str,
39 #[cfg_attr(feature = "serde", serde(default))]
41 pub is_expression: bool,
42}
43
44impl IndexColumnDef {
45 #[must_use]
47 pub const fn new(value: &'static str) -> Self {
48 Self {
49 value,
50 is_expression: false,
51 }
52 }
53
54 #[must_use]
56 pub const fn expression(value: &'static str) -> Self {
57 Self {
58 value,
59 is_expression: true,
60 }
61 }
62
63 #[must_use]
65 pub const fn into_column(self) -> IndexColumn {
66 IndexColumn {
67 value: Cow::Borrowed(self.value),
68 is_expression: self.is_expression,
69 }
70 }
71}
72
73#[derive(Clone, Debug, PartialEq, Eq)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
77pub struct IndexColumn {
78 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
80 pub value: Cow<'static, str>,
81 #[cfg_attr(feature = "serde", serde(default))]
83 pub is_expression: bool,
84}
85
86impl IndexColumn {
87 #[must_use]
89 pub fn new(value: impl Into<Cow<'static, str>>) -> Self {
90 Self {
91 value: value.into(),
92 is_expression: false,
93 }
94 }
95
96 #[must_use]
98 pub fn expression(value: impl Into<Cow<'static, str>>) -> Self {
99 Self {
100 value: value.into(),
101 is_expression: true,
102 }
103 }
104}
105
106impl IndexColumn {
107 #[must_use]
109 pub fn to_sql(&self) -> String {
110 if self.is_expression {
111 format!("({})", self.value)
112 } else {
113 format!("`{}`", self.value)
114 }
115 }
116}
117
118impl From<IndexColumnDef> for IndexColumn {
119 fn from(def: IndexColumnDef) -> Self {
120 def.into_column()
121 }
122}
123
124#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
141pub struct IndexDef {
142 pub table: &'static str,
144 pub name: &'static str,
146 pub columns: &'static [IndexColumnDef],
148 pub is_unique: bool,
150 pub where_clause: Option<&'static str>,
152 pub origin: IndexOrigin,
154}
155
156impl IndexDef {
157 #[must_use]
159 pub const fn new(table: &'static str, name: &'static str) -> Self {
160 Self {
161 table,
162 name,
163 columns: &[],
164 is_unique: false,
165 where_clause: None,
166 origin: IndexOrigin::Manual,
167 }
168 }
169
170 #[must_use]
172 pub const fn unique(self) -> Self {
173 Self {
174 is_unique: true,
175 ..self
176 }
177 }
178
179 #[must_use]
181 pub const fn columns(self, columns: &'static [IndexColumnDef]) -> Self {
182 Self { columns, ..self }
183 }
184
185 #[must_use]
187 pub const fn where_clause(self, clause: &'static str) -> Self {
188 Self {
189 where_clause: Some(clause),
190 ..self
191 }
192 }
193
194 #[must_use]
196 pub const fn auto_origin(self) -> Self {
197 Self {
198 origin: IndexOrigin::Auto,
199 ..self
200 }
201 }
202
203 #[must_use]
205 pub fn into_index(self) -> Index {
206 Index {
207 table: Cow::Borrowed(self.table),
208 name: Cow::Borrowed(self.name),
209 columns: self.columns.iter().map(|c| IndexColumn::from(*c)).collect(),
210 is_unique: self.is_unique,
211 where_clause: self.where_clause.map(Cow::Borrowed),
212 origin: self.origin,
213 }
214 }
215}
216
217impl Default for IndexDef {
218 fn default() -> Self {
219 Self::new("", "")
220 }
221}
222
223#[derive(Clone, Debug, PartialEq, Eq)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
231pub struct Index {
232 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
234 pub table: Cow<'static, str>,
235
236 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
238 pub name: Cow<'static, str>,
239
240 pub columns: Vec<IndexColumn>,
242
243 #[cfg_attr(feature = "serde", serde(default))]
245 pub is_unique: bool,
246
247 #[cfg_attr(
249 feature = "serde",
250 serde(
251 default,
252 skip_serializing_if = "Option::is_none",
253 rename = "where",
254 deserialize_with = "cow_option_from_string"
255 )
256 )]
257 pub where_clause: Option<Cow<'static, str>>,
258
259 #[cfg_attr(feature = "serde", serde(default))]
261 pub origin: IndexOrigin,
262}
263
264impl Index {
265 #[must_use]
267 pub fn new(
268 table: impl Into<Cow<'static, str>>,
269 name: impl Into<Cow<'static, str>>,
270 columns: Vec<IndexColumn>,
271 ) -> Self {
272 Self {
273 table: table.into(),
274 name: name.into(),
275 columns,
276 is_unique: false,
277 where_clause: None,
278 origin: IndexOrigin::Manual,
279 }
280 }
281
282 #[must_use]
284 pub fn unique(mut self) -> Self {
285 self.is_unique = true;
286 self
287 }
288
289 #[inline]
291 #[must_use]
292 pub fn name(&self) -> &str {
293 &self.name
294 }
295
296 #[inline]
298 #[must_use]
299 pub fn table(&self) -> &str {
300 &self.table
301 }
302}
303
304impl Default for Index {
305 fn default() -> Self {
306 Self::new("", "", vec![])
307 }
308}
309
310impl From<IndexDef> for Index {
311 fn from(def: IndexDef) -> Self {
312 def.into_index()
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_const_index_def() {
322 const COLS: &[IndexColumnDef] = &[
323 IndexColumnDef::new("email"),
324 IndexColumnDef::new("created_at"),
325 ];
326
327 const IDX: IndexDef = IndexDef::new("users", "idx_users_email")
328 .unique()
329 .columns(COLS);
330
331 assert_eq!(IDX.name, "idx_users_email");
332 assert_eq!(IDX.table, "users");
333 assert!(IDX.is_unique);
334 assert_eq!(IDX.columns.len(), 2);
335 }
336
337 #[test]
338 fn test_expression_column() {
339 const COLS: &[IndexColumnDef] = &[IndexColumnDef::expression("lower(email)")];
340
341 const IDX: IndexDef = IndexDef::new("users", "idx_email_lower").columns(COLS);
342
343 assert!(IDX.columns[0].is_expression);
344 }
345
346 #[test]
347 fn test_index_def_to_index() {
348 const COLS: &[IndexColumnDef] = &[IndexColumnDef::new("email")];
349 const DEF: IndexDef = IndexDef::new("users", "idx_email").unique().columns(COLS);
350
351 let idx = DEF.into_index();
352 assert_eq!(idx.name(), "idx_email");
353 assert!(idx.is_unique);
354 assert_eq!(idx.columns.len(), 1);
355 }
356
357 #[test]
358 fn test_into_index() {
359 const COLS: &[IndexColumnDef] = &[IndexColumnDef::new("email")];
360 const DEF: IndexDef = IndexDef::new("users", "idx_email").unique().columns(COLS);
361 let idx = DEF.into_index();
362
363 assert_eq!(idx.name, Cow::Borrowed("idx_email"));
364 assert!(idx.is_unique);
365 }
366}