scooby/postgres/statements/create_table/
column_definition.rs

1use std::fmt::{self, Display, Formatter};
2
3use crate::postgres::general::{Column, Condition, Expression, TableName};
4use crate::tools::joined;
5
6use super::column_constraints::*;
7
8#[derive(Debug, Clone)]
9pub struct ColumnDefinition {
10    name: String,
11    type_: String,
12    constraints: Vec<ColumnConstraint>,
13}
14
15impl Display for ColumnDefinition {
16    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
17        write!(f, "{} {}", self.name, self.type_)?;
18
19        if !self.constraints.is_empty() {
20            write!(f, " {}", joined(&self.constraints, " "))?
21        }
22
23        Ok(())
24    }
25}
26
27impl<N, P, U, D, R, C> From<ColumnDefinitionBuilder<N, P, U, D, R, C>> for ColumnDefinition
28where
29    N: NullabilityConstraint,
30    P: PrimaryKeyConstraint,
31    U: UniqueConstraint,
32    D: DefaultConstraint,
33    R: ReferencesConstraint,
34    C: CheckConstraint,
35{
36    fn from(builder: ColumnDefinitionBuilder<N, P, U, D, R, C>) -> Self {
37        let mut constraints = Vec::new();
38
39        if let Some(constraint) = builder.nullability.into_column_constraint() {
40            constraints.push(constraint);
41        }
42
43        if let Some(constraint) = builder.primary_key.into_column_constraint() {
44            constraints.push(constraint);
45        }
46
47        if let Some(constraint) = builder.unique.into_column_constraint() {
48            constraints.push(constraint);
49        }
50
51        if let Some(constraint) = builder.default.into_column_constraint() {
52            constraints.push(constraint);
53        }
54
55        if let Some(constraint) = builder.references.into_column_constraint() {
56            constraints.push(constraint);
57        }
58
59        if let Some(constraint) = builder.check.into_column_constraint() {
60            constraints.push(constraint);
61        }
62
63        ColumnDefinition {
64            name: builder.name,
65            type_: builder.type_,
66            constraints,
67        }
68    }
69}
70
71impl<T, U> From<(T, U)> for ColumnDefinition
72where
73    T: Into<String>,
74    U: Into<String>,
75{
76    fn from((name, type_): (T, U)) -> Self {
77        ColumnDefinition {
78            name: name.into(),
79            type_: type_.into(),
80            constraints: Vec::new(),
81        }
82    }
83}
84
85/* A super-flexible and type-safe builder of column definitions */
86
87#[derive(Debug)]
88pub struct ColumnDefinitionBuilder<
89    N = NoConstraint,
90    P = NoConstraint,
91    U = NoConstraint,
92    D = NoConstraint,
93    R = NoConstraint,
94    C = NoConstraint,
95> where
96    N: NullabilityConstraint,
97    P: PrimaryKeyConstraint,
98    U: UniqueConstraint,
99    D: DefaultConstraint,
100    R: ReferencesConstraint,
101    C: CheckConstraint,
102{
103    name: String,
104    type_: String,
105    nullability: N,
106    primary_key: P,
107    unique: U,
108    default: D,
109    references: R,
110    check: C,
111}
112
113impl ColumnDefinitionBuilder {
114    fn new(name: String, type_: String) -> ColumnDefinitionBuilder {
115        ColumnDefinitionBuilder {
116            name,
117            type_,
118            nullability: NoConstraint,
119            primary_key: NoConstraint,
120            unique: NoConstraint,
121            default: NoConstraint,
122            references: NoConstraint,
123            check: NoConstraint,
124        }
125    }
126}
127
128impl<P, U, D, R, C> ColumnDefinitionBuilder<NoConstraint, P, U, D, R, C>
129where
130    P: PrimaryKeyConstraint,
131    U: UniqueConstraint,
132    D: DefaultConstraint,
133    R: ReferencesConstraint,
134    C: CheckConstraint,
135{
136    pub fn null(self) -> ColumnDefinitionBuilder<IsNull, P, U, D, R, C> {
137        ColumnDefinitionBuilder {
138            name: self.name,
139            type_: self.type_,
140            nullability: IsNull,
141            primary_key: self.primary_key,
142            unique: self.unique,
143            default: self.default,
144            references: self.references,
145            check: self.check,
146        }
147    }
148
149    pub fn not_null(self) -> ColumnDefinitionBuilder<IsNotNull, P, U, D, R, C> {
150        ColumnDefinitionBuilder {
151            name: self.name,
152            type_: self.type_,
153            nullability: IsNotNull,
154            primary_key: self.primary_key,
155            unique: self.unique,
156            default: self.default,
157            references: self.references,
158            check: self.check,
159        }
160    }
161}
162
163impl<N, U, D, R, C> ColumnDefinitionBuilder<N, NoConstraint, U, D, R, C>
164where
165    N: NullabilityConstraint,
166    U: UniqueConstraint,
167    D: DefaultConstraint,
168    R: ReferencesConstraint,
169    C: CheckConstraint,
170{
171    pub fn primary_key(self) -> ColumnDefinitionBuilder<N, IsPrimaryKey, U, D, R, C> {
172        ColumnDefinitionBuilder {
173            name: self.name,
174            type_: self.type_,
175            nullability: self.nullability,
176            primary_key: IsPrimaryKey,
177            unique: self.unique,
178            default: self.default,
179            references: self.references,
180            check: self.check,
181        }
182    }
183}
184
185impl<N, P, D, R, C> ColumnDefinitionBuilder<N, P, NoConstraint, D, R, C>
186where
187    N: NullabilityConstraint,
188    P: PrimaryKeyConstraint,
189    D: DefaultConstraint,
190    R: ReferencesConstraint,
191    C: CheckConstraint,
192{
193    pub fn unique(self) -> ColumnDefinitionBuilder<N, P, IsUnique, D, R, C> {
194        ColumnDefinitionBuilder {
195            name: self.name,
196            type_: self.type_,
197            nullability: self.nullability,
198            primary_key: self.primary_key,
199            unique: IsUnique,
200            default: self.default,
201            references: self.references,
202            check: self.check,
203        }
204    }
205}
206
207impl<N, P, U, R, C> ColumnDefinitionBuilder<N, P, U, NoConstraint, R, C>
208where
209    N: NullabilityConstraint,
210    P: PrimaryKeyConstraint,
211    U: UniqueConstraint,
212    R: ReferencesConstraint,
213    C: CheckConstraint,
214{
215    pub fn default(
216        self,
217        expr: impl Into<Expression>,
218    ) -> ColumnDefinitionBuilder<N, P, U, HasDefault, R, C> {
219        ColumnDefinitionBuilder {
220            name: self.name,
221            type_: self.type_,
222            nullability: self.nullability,
223            primary_key: self.primary_key,
224            unique: self.unique,
225            default: HasDefault(expr.into()),
226            references: self.references,
227            check: self.check,
228        }
229    }
230}
231
232impl<N, P, U, D, C> ColumnDefinitionBuilder<N, P, U, D, NoConstraint, C>
233where
234    N: NullabilityConstraint,
235    P: PrimaryKeyConstraint,
236    U: UniqueConstraint,
237    D: DefaultConstraint,
238    C: CheckConstraint,
239{
240    pub fn references(
241        self,
242        table_name: impl Into<TableName>,
243        column: impl Into<Column>,
244    ) -> ColumnDefinitionBuilder<N, P, U, D, References, C> {
245        ColumnDefinitionBuilder {
246            name: self.name,
247            type_: self.type_,
248            nullability: self.nullability,
249            primary_key: self.primary_key,
250            unique: self.unique,
251            default: self.default,
252            references: References(table_name.into(), column.into()),
253            check: self.check,
254        }
255    }
256}
257
258impl<N, P, U, D, R> ColumnDefinitionBuilder<N, P, U, D, R, NoConstraint>
259where
260    N: NullabilityConstraint,
261    P: PrimaryKeyConstraint,
262    U: UniqueConstraint,
263    D: DefaultConstraint,
264    R: ReferencesConstraint,
265{
266    pub fn check(
267        self,
268        cond: impl Into<Condition>,
269    ) -> ColumnDefinitionBuilder<N, P, U, D, R, Check> {
270        ColumnDefinitionBuilder {
271            name: self.name,
272            type_: self.type_,
273            nullability: self.nullability,
274            primary_key: self.primary_key,
275            unique: self.unique,
276            default: self.default,
277            references: self.references,
278            check: Check(cond.into()),
279        }
280    }
281}
282
283impl<T, U> From<(T, U)> for ColumnDefinitionBuilder
284where
285    T: Into<String>,
286    U: Into<String>,
287{
288    fn from((name, type_): (T, U)) -> Self {
289        ColumnDefinitionBuilder::new(name.into(), type_.into())
290    }
291}
292
293pub trait ColumnDefinitionable: Into<ColumnDefinitionBuilder> {
294    fn null(self) -> ColumnDefinitionBuilder<IsNull>;
295    fn not_null(self) -> ColumnDefinitionBuilder<IsNotNull>;
296    fn primary_key(self) -> ColumnDefinitionBuilder<NoConstraint, IsPrimaryKey>;
297    fn unique(self) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, IsUnique>;
298    fn default(
299        self,
300        expr: impl Into<Expression>,
301    ) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, NoConstraint, HasDefault>;
302    fn references(
303        self,
304        table_name: impl Into<TableName>,
305        column: impl Into<Column>,
306    ) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, NoConstraint, NoConstraint, References>;
307    fn check(
308        self,
309        cond: impl Into<Condition>,
310    ) -> ColumnDefinitionBuilder<
311        NoConstraint,
312        NoConstraint,
313        NoConstraint,
314        NoConstraint,
315        NoConstraint,
316        Check,
317    >;
318}
319
320impl<T, U> ColumnDefinitionable for (T, U)
321where
322    T: Into<String>,
323    U: Into<String>,
324{
325    fn null(self) -> ColumnDefinitionBuilder<IsNull> {
326        ColumnDefinitionBuilder::from(self).null()
327    }
328
329    fn not_null(self) -> ColumnDefinitionBuilder<IsNotNull> {
330        ColumnDefinitionBuilder::from(self).not_null()
331    }
332
333    fn primary_key(self) -> ColumnDefinitionBuilder<NoConstraint, IsPrimaryKey> {
334        ColumnDefinitionBuilder::from(self).primary_key()
335    }
336
337    fn unique(self) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, IsUnique> {
338        ColumnDefinitionBuilder::from(self).unique()
339    }
340
341    fn default(
342        self,
343        expr: impl Into<Expression>,
344    ) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, NoConstraint, HasDefault> {
345        ColumnDefinitionBuilder::from(self).default(expr)
346    }
347
348    fn references(
349        self,
350        table_name: impl Into<TableName>,
351        column: impl Into<Column>,
352    ) -> ColumnDefinitionBuilder<NoConstraint, NoConstraint, NoConstraint, NoConstraint, References>
353    {
354        ColumnDefinitionBuilder::from(self).references(table_name, column)
355    }
356
357    fn check(
358        self,
359        expr: impl Into<Condition>,
360    ) -> ColumnDefinitionBuilder<
361        NoConstraint,
362        NoConstraint,
363        NoConstraint,
364        NoConstraint,
365        NoConstraint,
366        Check,
367    > {
368        ColumnDefinitionBuilder::from(self).check(expr)
369    }
370}