1use 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 GeneratedType {
21 #[default]
23 Stored,
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28pub struct GeneratedDef {
29 pub expression: &'static str,
31 pub gen_type: GeneratedType,
33}
34
35impl GeneratedDef {
36 #[must_use]
38 pub const fn stored(expression: &'static str) -> Self {
39 Self {
40 expression,
41 gen_type: GeneratedType::Stored,
42 }
43 }
44
45 #[must_use]
47 pub const fn into_generated(self) -> Generated {
48 Generated {
49 expression: Cow::Borrowed(self.expression),
50 gen_type: self.gen_type,
51 }
52 }
53}
54
55#[derive(Clone, Debug, PartialEq, Eq)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
59pub struct Generated {
60 #[cfg_attr(
62 feature = "serde",
63 serde(rename = "as", deserialize_with = "cow_from_string")
64 )]
65 pub expression: Cow<'static, str>,
66 #[cfg_attr(feature = "serde", serde(rename = "type"))]
68 pub gen_type: GeneratedType,
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
77#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
78#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
79pub enum IdentityType {
80 #[default]
82 Always,
83 ByDefault,
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
89pub struct IdentityDef {
90 pub name: &'static str,
92 pub schema: Option<&'static str>,
94 pub type_: IdentityType,
96 pub increment: Option<&'static str>,
98 pub min_value: Option<&'static str>,
100 pub max_value: Option<&'static str>,
102 pub start_with: Option<&'static str>,
104 pub cache: Option<i32>,
106 pub cycle: bool,
108}
109
110impl IdentityDef {
111 #[must_use]
113 pub const fn new(name: &'static str, type_: IdentityType) -> Self {
114 Self {
115 name,
116 schema: None,
117 type_,
118 increment: None,
119 min_value: None,
120 max_value: None,
121 start_with: None,
122 cache: None,
123 cycle: false,
124 }
125 }
126
127 #[must_use]
129 pub const fn schema(self, schema: &'static str) -> Self {
130 Self {
131 schema: Some(schema),
132 ..self
133 }
134 }
135
136 #[must_use]
138 pub const fn increment(self, value: &'static str) -> Self {
139 Self {
140 increment: Some(value),
141 ..self
142 }
143 }
144
145 #[must_use]
147 pub const fn min_value(self, value: &'static str) -> Self {
148 Self {
149 min_value: Some(value),
150 ..self
151 }
152 }
153
154 #[must_use]
156 pub const fn max_value(self, value: &'static str) -> Self {
157 Self {
158 max_value: Some(value),
159 ..self
160 }
161 }
162
163 #[must_use]
165 pub const fn start_with(self, value: &'static str) -> Self {
166 Self {
167 start_with: Some(value),
168 ..self
169 }
170 }
171
172 #[must_use]
174 pub const fn cache(self, value: i32) -> Self {
175 Self {
176 cache: Some(value),
177 ..self
178 }
179 }
180
181 #[must_use]
183 pub const fn cycle(self) -> Self {
184 Self {
185 cycle: true,
186 ..self
187 }
188 }
189
190 #[must_use]
192 pub const fn into_identity(self) -> Identity {
193 Identity {
194 name: Cow::Borrowed(self.name),
195 schema: match self.schema {
196 Some(s) => Some(Cow::Borrowed(s)),
197 None => None,
198 },
199 type_: self.type_,
200 increment: match self.increment {
201 Some(s) => Some(Cow::Borrowed(s)),
202 None => None,
203 },
204 min_value: match self.min_value {
205 Some(s) => Some(Cow::Borrowed(s)),
206 None => None,
207 },
208 max_value: match self.max_value {
209 Some(s) => Some(Cow::Borrowed(s)),
210 None => None,
211 },
212 start_with: match self.start_with {
213 Some(s) => Some(Cow::Borrowed(s)),
214 None => None,
215 },
216 cache: self.cache,
217 cycle: if self.cycle { Some(true) } else { None },
218 }
219 }
220}
221
222#[derive(Clone, Debug, PartialEq, Eq)]
224#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
225#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
226pub struct Identity {
227 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
229 pub name: Cow<'static, str>,
230
231 #[cfg_attr(
233 feature = "serde",
234 serde(
235 skip_serializing_if = "Option::is_none",
236 deserialize_with = "cow_option_from_string"
237 )
238 )]
239 pub schema: Option<Cow<'static, str>>,
240
241 #[cfg_attr(feature = "serde", serde(rename = "type"))]
243 pub type_: IdentityType,
244
245 #[cfg_attr(
247 feature = "serde",
248 serde(
249 skip_serializing_if = "Option::is_none",
250 deserialize_with = "cow_option_from_string"
251 )
252 )]
253 pub increment: Option<Cow<'static, str>>,
254
255 #[cfg_attr(
257 feature = "serde",
258 serde(
259 skip_serializing_if = "Option::is_none",
260 deserialize_with = "cow_option_from_string"
261 )
262 )]
263 pub min_value: Option<Cow<'static, str>>,
264
265 #[cfg_attr(
267 feature = "serde",
268 serde(
269 skip_serializing_if = "Option::is_none",
270 deserialize_with = "cow_option_from_string"
271 )
272 )]
273 pub max_value: Option<Cow<'static, str>>,
274
275 #[cfg_attr(
277 feature = "serde",
278 serde(
279 skip_serializing_if = "Option::is_none",
280 deserialize_with = "cow_option_from_string"
281 )
282 )]
283 pub start_with: Option<Cow<'static, str>>,
284
285 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
287 pub cache: Option<i32>,
288
289 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
291 pub cycle: Option<bool>,
292}
293
294impl Identity {
295 #[must_use]
297 pub fn always(name: impl Into<Cow<'static, str>>) -> Self {
298 Self {
299 name: name.into(),
300 schema: None,
301 type_: IdentityType::Always,
302 increment: None,
303 min_value: None,
304 max_value: None,
305 start_with: None,
306 cache: None,
307 cycle: None,
308 }
309 }
310
311 #[must_use]
313 pub fn by_default(name: impl Into<Cow<'static, str>>) -> Self {
314 Self {
315 name: name.into(),
316 schema: None,
317 type_: IdentityType::ByDefault,
318 increment: None,
319 min_value: None,
320 max_value: None,
321 start_with: None,
322 cache: None,
323 cycle: None,
324 }
325 }
326
327 #[must_use]
329 pub fn schema(mut self, schema: impl Into<Cow<'static, str>>) -> Self {
330 self.schema = Some(schema.into());
331 self
332 }
333}
334
335#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
341pub struct ColumnDef {
342 pub schema: &'static str,
344 pub table: &'static str,
346 pub name: &'static str,
348 pub sql_type: &'static str,
350 pub type_schema: Option<&'static str>,
352 pub not_null: bool,
354 pub default: Option<&'static str>,
356 pub generated: Option<GeneratedDef>,
358 pub identity: Option<IdentityDef>,
360 pub dimensions: Option<i32>,
362 pub collate: Option<&'static str>,
366}
367
368impl ColumnDef {
369 #[must_use]
371 pub const fn new(
372 schema: &'static str,
373 table: &'static str,
374 name: &'static str,
375 sql_type: &'static str,
376 ) -> Self {
377 Self {
378 schema,
379 table,
380 name,
381 sql_type,
382 type_schema: None,
383 not_null: false,
384 default: None,
385 generated: None,
386 identity: None,
387 dimensions: None,
388 collate: None,
389 }
390 }
391
392 #[must_use]
394 pub const fn type_schema(self, schema: &'static str) -> Self {
395 Self {
396 type_schema: Some(schema),
397 ..self
398 }
399 }
400
401 #[must_use]
403 pub const fn not_null(self) -> Self {
404 Self {
405 not_null: true,
406 ..self
407 }
408 }
409
410 #[must_use]
412 pub const fn default_value(self, value: &'static str) -> Self {
413 Self {
414 default: Some(value),
415 ..self
416 }
417 }
418
419 #[must_use]
421 pub const fn generated_stored(self, expression: &'static str) -> Self {
422 Self {
423 generated: Some(GeneratedDef::stored(expression)),
424 ..self
425 }
426 }
427
428 #[must_use]
430 pub const fn identity(self, identity: IdentityDef) -> Self {
431 Self {
432 identity: Some(identity),
433 ..self
434 }
435 }
436
437 #[must_use]
439 pub const fn dimensions(self, dims: i32) -> Self {
440 Self {
441 dimensions: Some(dims),
442 ..self
443 }
444 }
445
446 #[must_use]
452 pub const fn collate(self, name: &'static str) -> Self {
453 Self {
454 collate: Some(name),
455 ..self
456 }
457 }
458
459 #[must_use]
464 pub const fn into_column(self) -> Column {
465 Column {
466 schema: Cow::Borrowed(self.schema),
467 table: Cow::Borrowed(self.table),
468 name: Cow::Borrowed(self.name),
469 sql_type: Cow::Borrowed(self.sql_type),
470 type_schema: match self.type_schema {
471 Some(s) => Some(Cow::Borrowed(s)),
472 None => None,
473 },
474 not_null: self.not_null,
475 default: match self.default {
476 Some(s) => Some(Cow::Borrowed(s)),
477 None => None,
478 },
479 generated: match self.generated {
480 Some(g) => Some(g.into_generated()),
481 None => None,
482 },
483 identity: match self.identity {
484 Some(i) => Some(i.into_identity()),
485 None => None,
486 },
487 dimensions: self.dimensions,
488 collate: match self.collate {
489 Some(s) => Some(Cow::Borrowed(s)),
490 None => None,
491 },
492 ordinal_position: None,
493 }
494 }
495}
496
497impl Default for ColumnDef {
498 fn default() -> Self {
499 Self::new("public", "", "", "")
500 }
501}
502
503#[derive(Clone, Debug, PartialEq, Eq)]
509#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
510#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
511pub struct Column {
512 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
514 pub schema: Cow<'static, str>,
515
516 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
518 pub table: Cow<'static, str>,
519
520 #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
522 pub name: Cow<'static, str>,
523
524 #[cfg_attr(
526 feature = "serde",
527 serde(rename = "type", deserialize_with = "cow_from_string")
528 )]
529 pub sql_type: Cow<'static, str>,
530
531 #[cfg_attr(
533 feature = "serde",
534 serde(
535 default,
536 skip_serializing_if = "Option::is_none",
537 deserialize_with = "cow_option_from_string"
538 )
539 )]
540 pub type_schema: Option<Cow<'static, str>>,
541
542 #[cfg_attr(feature = "serde", serde(default))]
544 pub not_null: bool,
545
546 #[cfg_attr(
548 feature = "serde",
549 serde(default, deserialize_with = "cow_option_from_string")
550 )]
551 pub default: Option<Cow<'static, str>>,
552
553 #[cfg_attr(feature = "serde", serde(default))]
555 pub generated: Option<Generated>,
556
557 #[cfg_attr(feature = "serde", serde(default))]
559 pub identity: Option<Identity>,
560
561 #[cfg_attr(feature = "serde", serde(default))]
563 pub dimensions: Option<i32>,
564
565 #[cfg_attr(
568 feature = "serde",
569 serde(default, deserialize_with = "cow_option_from_string")
570 )]
571 pub collate: Option<Cow<'static, str>>,
572
573 #[cfg_attr(
577 feature = "serde",
578 serde(default, skip_serializing_if = "Option::is_none")
579 )]
580 pub ordinal_position: Option<i32>,
581}
582
583impl Column {
584 #[must_use]
586 pub fn new(
587 schema: impl Into<Cow<'static, str>>,
588 table: impl Into<Cow<'static, str>>,
589 name: impl Into<Cow<'static, str>>,
590 sql_type: impl Into<Cow<'static, str>>,
591 ) -> Self {
592 Self {
593 schema: schema.into(),
594 table: table.into(),
595 name: name.into(),
596 sql_type: sql_type.into(),
597 type_schema: None,
598 not_null: false,
599 default: None,
600 generated: None,
601 identity: None,
602 dimensions: None,
603 collate: None,
604 ordinal_position: None,
605 }
606 }
607
608 #[must_use]
610 pub const fn not_null(mut self) -> Self {
611 self.not_null = true;
612 self
613 }
614
615 #[must_use]
617 pub fn default_value(mut self, value: impl Into<Cow<'static, str>>) -> Self {
618 self.default = Some(value.into());
619 self
620 }
621
622 #[must_use]
624 pub fn identity(mut self, identity: Identity) -> Self {
625 self.identity = Some(identity);
626 self
627 }
628
629 #[inline]
631 #[must_use]
632 pub fn schema(&self) -> &str {
633 &self.schema
634 }
635
636 #[inline]
638 #[must_use]
639 pub fn table(&self) -> &str {
640 &self.table
641 }
642
643 #[inline]
645 #[must_use]
646 pub fn name(&self) -> &str {
647 &self.name
648 }
649
650 #[inline]
652 #[must_use]
653 pub fn sql_type(&self) -> &str {
654 &self.sql_type
655 }
656}
657
658impl Default for Column {
659 fn default() -> Self {
660 Self::new("public", "", "", "")
661 }
662}
663
664impl From<ColumnDef> for Column {
665 fn from(def: ColumnDef) -> Self {
666 def.into_column()
667 }
668}
669
670#[cfg(test)]
671mod tests {
672 use super::*;
673
674 #[test]
675 fn test_const_column_def() {
676 const COLDEF: ColumnDef = ColumnDef::new("public", "users", "id", "INTEGER").not_null();
677
678 assert_eq!(COLDEF.schema, "public");
679 assert_eq!(COLDEF.name, "id");
680 assert_eq!(COLDEF.table, "users");
681 assert_eq!(COLDEF.sql_type, "INTEGER");
682 const {
683 assert!(COLDEF.not_null);
684 }
685
686 let col: Column = COLDEF.into_column();
687
688 assert_eq!(col.schema, Cow::Borrowed("public"));
689 assert_eq!(col.name, Cow::Borrowed("id"));
690 assert_eq!(col.table, Cow::Borrowed("users"));
691 assert_eq!(col.sql_type, Cow::Borrowed("INTEGER"));
692 assert!(col.not_null);
693 }
694
695 #[test]
696 fn test_identity_column() {
697 const IDENTITY_DEF: IdentityDef = IdentityDef::new("users_id_seq", IdentityType::Always)
698 .increment("1")
699 .start_with("1");
700
701 const COL: ColumnDef =
702 ColumnDef::new("public", "users", "id", "INTEGER").identity(IDENTITY_DEF);
703
704 assert!(COL.identity.is_some());
705 }
706
707 #[cfg(feature = "serde")]
708 #[test]
709 fn test_serde_roundtrip() {
710 let col = Column::new("public", "users", "id", "INTEGER");
711 let json = serde_json::to_string(&col).unwrap();
712 let parsed: Column = serde_json::from_str(&json).unwrap();
713 assert_eq!(parsed.name(), "id");
714 }
715}