1use super::{
2 Column, ColumnRef, Constraint, EnumDef, ExtensionDef, ForeignKey, FunctionDef, Index,
3 OpaqueMeta, PrimaryKey, Schema, SchemaLoadError, Table, TableOptionsMeta, TriggerDef, ViewDef,
4 names, schema_qualified_key,
5};
6use crate::column_type::ColumnType;
7use crate::dialects::Dialect;
8
9pub trait IntoTable {
11 fn into_table(dialect: &Dialect) -> Table;
12}
13
14pub struct ColumnBuilder {
15 col: Column,
16}
17
18impl ColumnBuilder {
19 fn with_reference(
20 mut self,
21 name: Option<String>,
22 table: impl Into<String>,
23 column: impl Into<String>,
24 ) -> Self {
25 self.col.references = Some(ColumnRef {
26 table: table.into(),
27 column: column.into(),
28 name,
29 on_delete: None,
30 on_update: None,
31 });
32 self
33 }
34
35 pub fn nullable(mut self) -> Self {
36 self.col.nullable = true;
37 self
38 }
39
40 pub fn not_null(mut self) -> Self {
41 self.col.nullable = false;
42 self
43 }
44
45 pub fn primary_key(mut self) -> Self {
46 self.col.primary_key = true;
47 self.col.nullable = false;
48 self
49 }
50
51 pub fn default(mut self, expr: impl Into<String>) -> Self {
52 self.col.default = Some(expr.into());
53 self
54 }
55
56 pub fn generated(mut self, expr: impl Into<String>) -> Self {
58 let expr = expr.into();
59 if !expr.trim().is_empty() {
60 self.col.generated = Some(expr);
61 }
62 self
63 }
64
65 pub fn references(self, table: impl Into<String>, column: impl Into<String>) -> Self {
66 self.with_reference(None, table, column)
67 }
68
69 pub fn references_named(
70 self,
71 name: impl Into<String>,
72 table: impl Into<String>,
73 column: impl Into<String>,
74 ) -> Self {
75 self.with_reference(Some(name.into()), table, column)
76 }
77
78 pub fn on_delete(mut self, action: impl Into<String>) -> Self {
80 if let Some(reference) = &mut self.col.references {
81 let action = action.into();
82 if !action.trim().is_empty() {
83 reference.on_delete = Some(action);
84 }
85 }
86 self
87 }
88
89 pub fn on_update(mut self, action: impl Into<String>) -> Self {
91 if let Some(reference) = &mut self.col.references {
92 let action = action.into();
93 if !action.trim().is_empty() {
94 reference.on_update = Some(action);
95 }
96 }
97 self
98 }
99
100 pub fn check(mut self, expr: impl Into<String>) -> Self {
101 self.col.check = Some(expr.into());
102 self
103 }
104
105 fn finish(self) -> Column {
106 self.col
107 }
108}
109
110pub struct TableBuilder {
111 table: Table,
112}
113
114impl TableBuilder {
115 fn push_foreign_key(
116 mut self,
117 name: String,
118 from_columns: impl IntoIterator<Item = impl Into<String>>,
119 to_table: impl Into<String>,
120 to_columns: impl IntoIterator<Item = impl Into<String>>,
121 ) -> Self {
122 self.table
123 .foreign_keys
124 .push(ForeignKey::new(name, from_columns, to_table, to_columns));
125 self
126 }
127
128 fn push_index(mut self, name: impl Into<String>, columns: &[&str], unique: bool) -> Self {
129 self.table.indexes.push(Index {
130 name: name.into(),
131 columns: columns.iter().map(|s| s.to_string()).collect(),
132 unique,
133 predicate: None,
134 opaque: OpaqueMeta::default(),
135 });
136 self
137 }
138
139 fn push_index_with(
140 mut self,
141 name: impl Into<String>,
142 columns: &[&str],
143 unique: bool,
144 f: impl FnOnce(Index) -> Index,
145 ) -> Self {
146 let index = Index {
147 name: name.into(),
148 columns: columns.iter().map(|s| s.to_string()).collect(),
149 unique,
150 predicate: None,
151 opaque: OpaqueMeta::default(),
152 };
153 self.table.indexes.push(f(index));
154 self
155 }
156
157 pub fn new(name: impl Into<String>) -> Self {
158 let name = name.into();
159 Self {
160 table: Table {
161 name,
162 schema: None,
163 primary_key: None,
164 columns: vec![],
165 foreign_keys: vec![],
166 indexes: vec![],
167 constraints: vec![],
168 triggers: vec![],
169 options: TableOptionsMeta::default(),
170 },
171 }
172 }
173
174 pub fn schema(mut self, schema: impl Into<String>) -> Self {
175 self.table.schema = Some(schema.into());
176 self
177 }
178
179 pub fn column(
180 mut self,
181 name: impl Into<String>,
182 col_type: impl Into<String>,
183 f: impl FnOnce(ColumnBuilder) -> ColumnBuilder,
184 ) -> Self {
185 let b = ColumnBuilder {
186 col: Column {
187 name: name.into(),
188 col_type: col_type.into(),
189 ..Default::default()
190 },
191 };
192 self.table.columns.push(f(b).finish());
193 self
194 }
195
196 pub fn column_from_type<T: ColumnType>(
202 mut self,
203 dialect: &Dialect,
204 name: impl Into<String>,
205 f: impl FnOnce(ColumnBuilder) -> ColumnBuilder,
206 ) -> Self {
207 let desc = T::column_desc(dialect);
208 let b = ColumnBuilder {
209 col: Column {
210 name: name.into(),
211 col_type: desc.sql_type.to_string(),
212 nullable: desc.nullable,
213 ..Default::default()
214 },
215 };
216 self.table.columns.push(f(b).finish());
217 self
218 }
219
220 pub fn id(self) -> Self {
222 self.column("id", "bigserial", |c| c.primary_key())
223 }
224
225 pub fn foreign_key(
226 self,
227 from: impl Into<String>,
228 to_table: impl Into<String>,
229 to_column: impl Into<String>,
230 ) -> Self {
231 let from = from.into();
232 let name = names::foreign_key(&self.table.name, &[from.as_str()]);
233 self.push_foreign_key(name, [from], to_table, [to_column.into()])
234 }
235
236 pub fn foreign_key_with(
238 self,
239 from: impl Into<String>,
240 to_table: impl Into<String>,
241 to_column: impl Into<String>,
242 f: impl FnOnce(ForeignKey) -> ForeignKey,
243 ) -> Self {
244 let from = from.into();
245 let name = names::foreign_key(&self.table.name, &[from.as_str()]);
246 let foreign_key = ForeignKey::single(name, from, to_table, to_column);
247 self.foreign_key_obj(f(foreign_key))
248 }
249
250 pub fn foreign_key_named(
251 self,
252 fk_name: impl Into<String>,
253 from: impl Into<String>,
254 to_table: impl Into<String>,
255 to_column: impl Into<String>,
256 ) -> Self {
257 self.push_foreign_key(fk_name.into(), [from.into()], to_table, [to_column.into()])
258 }
259
260 pub fn foreign_key_named_with(
262 self,
263 fk_name: impl Into<String>,
264 from: impl Into<String>,
265 to_table: impl Into<String>,
266 to_column: impl Into<String>,
267 f: impl FnOnce(ForeignKey) -> ForeignKey,
268 ) -> Self {
269 let foreign_key = ForeignKey::single(fk_name, from, to_table, to_column);
270 self.foreign_key_obj(f(foreign_key))
271 }
272
273 pub fn foreign_key_columns(
274 self,
275 from_columns: &[&str],
276 to_table: impl Into<String>,
277 to_columns: &[&str],
278 ) -> Self {
279 let name = names::foreign_key(&self.table.name, from_columns);
280 self.push_foreign_key(
281 name,
282 from_columns.iter().copied(),
283 to_table,
284 to_columns.iter().copied(),
285 )
286 }
287
288 pub fn foreign_key_columns_with(
290 self,
291 from_columns: &[&str],
292 to_table: impl Into<String>,
293 to_columns: &[&str],
294 f: impl FnOnce(ForeignKey) -> ForeignKey,
295 ) -> Self {
296 let name = names::foreign_key(&self.table.name, from_columns);
297 let foreign_key = ForeignKey::new(
298 name,
299 from_columns.iter().copied(),
300 to_table,
301 to_columns.iter().copied(),
302 );
303 self.foreign_key_obj(f(foreign_key))
304 }
305
306 pub fn foreign_key_named_columns(
307 self,
308 fk_name: impl Into<String>,
309 from_columns: &[&str],
310 to_table: impl Into<String>,
311 to_columns: &[&str],
312 ) -> Self {
313 self.push_foreign_key(
314 fk_name.into(),
315 from_columns.iter().copied(),
316 to_table,
317 to_columns.iter().copied(),
318 )
319 }
320
321 pub fn foreign_key_named_columns_with(
323 self,
324 fk_name: impl Into<String>,
325 from_columns: &[&str],
326 to_table: impl Into<String>,
327 to_columns: &[&str],
328 f: impl FnOnce(ForeignKey) -> ForeignKey,
329 ) -> Self {
330 let foreign_key = ForeignKey::new(
331 fk_name,
332 from_columns.iter().copied(),
333 to_table,
334 to_columns.iter().copied(),
335 );
336 self.foreign_key_obj(f(foreign_key))
337 }
338
339 pub fn foreign_key_obj(mut self, foreign_key: ForeignKey) -> Self {
341 self.table.foreign_keys.push(foreign_key);
342 self
343 }
344
345 pub fn index_columns(self, columns: &[&str]) -> Self {
346 let name = names::index(&self.table.name, columns);
347 self.push_index(name, columns, false)
348 }
349
350 pub fn index_columns_with(self, columns: &[&str], f: impl FnOnce(Index) -> Index) -> Self {
352 let name = names::index(&self.table.name, columns);
353 self.push_index_with(name, columns, false, f)
354 }
355
356 pub fn unique_index_columns(self, columns: &[&str]) -> Self {
357 let name = names::index(&self.table.name, columns);
358 self.push_index(name, columns, true)
359 }
360
361 pub fn unique_index_columns_with(
363 self,
364 columns: &[&str],
365 f: impl FnOnce(Index) -> Index,
366 ) -> Self {
367 let name = names::index(&self.table.name, columns);
368 self.push_index_with(name, columns, true, f)
369 }
370
371 pub fn index(self, name: impl Into<String>, columns: &[&str]) -> Self {
372 self.push_index(name, columns, false)
373 }
374
375 pub fn index_with(
377 self,
378 name: impl Into<String>,
379 columns: &[&str],
380 f: impl FnOnce(Index) -> Index,
381 ) -> Self {
382 self.push_index_with(name, columns, false, f)
383 }
384
385 pub fn unique_index(self, name: impl Into<String>, columns: &[&str]) -> Self {
386 self.push_index(name, columns, true)
387 }
388
389 pub fn unique_index_with(
391 self,
392 name: impl Into<String>,
393 columns: &[&str],
394 f: impl FnOnce(Index) -> Index,
395 ) -> Self {
396 self.push_index_with(name, columns, true, f)
397 }
398
399 pub fn check(mut self, name: impl Into<String>, expression: impl Into<String>) -> Self {
400 self.table.constraints.push(Constraint::Check {
401 name: name.into(),
402 expression: expression.into(),
403 });
404 self
405 }
406
407 pub fn check_expr(self, expression: impl Into<String>) -> Self {
408 let name = names::table_check(&self.table.name);
409 self.check(name, expression)
410 }
411
412 pub fn unique(mut self, name: impl Into<String>, columns: &[&str]) -> Self {
413 self.table.constraints.push(Constraint::Unique {
414 name: name.into(),
415 columns: columns.iter().map(|s| s.to_string()).collect(),
416 });
417 self
418 }
419
420 pub fn unique_columns(self, columns: &[&str]) -> Self {
421 let name = names::unique(&self.table.name, columns);
422 self.unique(name, columns)
423 }
424
425 pub fn primary_key(mut self, name: impl Into<String>, columns: &[&str]) -> Self {
426 self.table.primary_key = Some(PrimaryKey {
427 name: name.into(),
428 columns: columns.iter().map(|s| s.to_string()).collect(),
429 });
430 self
431 }
432
433 pub fn primary_key_columns(self, columns: &[&str]) -> Self {
434 let name = names::primary_key(&self.table.name);
435 self.primary_key(name, columns)
436 }
437
438 pub fn trigger(self, trigger: TriggerDef) -> Self {
439 let mut this = self;
440 this.table.triggers.push(trigger);
441 this
442 }
443
444 pub fn build(mut self) -> Table {
445 if self.table.primary_key.is_none() {
446 let columns: Vec<String> = self
447 .table
448 .columns
449 .iter()
450 .filter(|column| column.primary_key)
451 .map(|column| column.name.clone())
452 .collect();
453 if !columns.is_empty() {
454 self.table.primary_key = Some(PrimaryKey {
455 name: names::primary_key(&self.table.name),
456 columns,
457 });
458 }
459 }
460 if let Some(pk) = &self.table.primary_key {
461 for column in &mut self.table.columns {
462 column.primary_key = pk.columns.iter().any(|name| name == &column.name);
463 if column.primary_key {
464 column.nullable = false;
465 }
466 }
467 }
468 self.table
469 }
470}
471
472pub struct SchemaBuilder {
473 dialect: Dialect,
474 state: Schema,
475}
476
477impl SchemaBuilder {
478 fn insert_extension(mut self, name: impl Into<String>, version: Option<String>) -> Self {
479 let name = name.into();
480 self.state.extensions.insert(
481 name.clone(),
482 ExtensionDef {
483 name,
484 schema: None,
485 version,
486 opaque: OpaqueMeta::default(),
487 },
488 );
489 self
490 }
491
492 pub fn new(dialect: Dialect) -> Self {
493 Self {
494 dialect,
495 state: Schema::default(),
496 }
497 }
498
499 pub fn table<T: IntoTable>(mut self) -> Self {
501 let t = T::into_table(&self.dialect);
502 let key = schema_qualified_key(&t.name, t.schema.as_deref());
503 self.state.tables.insert(key, t);
504 self
505 }
506
507 pub fn table_def(mut self, table: Table) -> Self {
509 let key = schema_qualified_key(&table.name, table.schema.as_deref());
510 self.state.tables.insert(key, table);
511 self
512 }
513
514 pub fn extension(self, name: impl Into<String>) -> Self {
515 self.insert_extension(name, None)
516 }
517
518 pub fn extension_versioned(self, name: impl Into<String>, version: impl Into<String>) -> Self {
519 self.insert_extension(name, Some(version.into()))
520 }
521
522 pub fn extension_def(mut self, extension: ExtensionDef) -> Self {
524 let key = schema_qualified_key(&extension.name, extension.schema.as_deref());
525 self.state.extensions.insert(key, extension);
526 self
527 }
528
529 pub fn view(mut self, name: impl Into<String>, definition: impl Into<String>) -> Self {
530 let name = name.into();
531 self.state.views.insert(
532 name.clone(),
533 ViewDef {
534 name,
535 schema: None,
536 definition: definition.into(),
537 opaque: OpaqueMeta::default(),
538 },
539 );
540 self
541 }
542
543 pub fn view_def(mut self, view: ViewDef) -> Self {
545 let key = schema_qualified_key(&view.name, view.schema.as_deref());
546 self.state.views.insert(key, view);
547 self
548 }
549
550 pub fn function(mut self, f: FunctionDef) -> Self {
551 let key = schema_qualified_key(&f.name, f.schema.as_deref());
552 self.state.functions.insert(key, f);
553 self
554 }
555
556 pub fn enum_type(mut self, name: impl Into<String>, values: &[&str]) -> Self {
557 let name = name.into();
558 self.state.enums.insert(
559 name.clone(),
560 EnumDef {
561 name,
562 schema: None,
563 values: values.iter().map(|s| s.to_string()).collect(),
564 opaque: OpaqueMeta::default(),
565 },
566 );
567 self
568 }
569
570 pub fn enum_def(mut self, enum_def: EnumDef) -> Self {
572 let key = schema_qualified_key(&enum_def.name, enum_def.schema.as_deref());
573 self.state.enums.insert(key, enum_def);
574 self
575 }
576
577 pub fn build(self) -> Result<Schema, SchemaLoadError> {
580 let dialect = self.dialect;
581 self.build_raw().prepare_loaded(dialect)
582 }
583
584 pub(crate) fn build_raw(self) -> Schema {
590 self.state
591 }
592}