1use crate::model::{ColumnDef, TableDef};
6
7pub fn column_sql(c: &ColumnDef, auto_pk: bool) -> String {
12 let mut parts = vec![c.name.clone(), c.ty.sql().to_string()];
13 if c.primary_key && auto_pk {
14 parts.push("PRIMARY KEY AUTOINCREMENT".into());
15 }
16 if !c.nullable {
17 parts.push("NOT NULL".into());
18 }
19 if c.unique {
20 parts.push("UNIQUE".into());
21 }
22 if let Some(d) = &c.default {
23 parts.push(format!("DEFAULT {}", d.sql()));
24 }
25 if let Some(values) = &c.check_in
26 && !values.is_empty()
27 {
28 let list = values
29 .iter()
30 .map(|v| format!("'{}'", v.replace('\'', "''")))
31 .collect::<Vec<_>>()
32 .join(", ");
33 parts.push(format!("CHECK ({} IN ({list}))", c.name));
34 }
35 parts.join(" ")
36}
37
38pub fn create_table_sql(t: &TableDef) -> String {
39 let auto = t.auto_id();
40 let mut lines: Vec<String> = t.columns.iter().map(|c| column_sql(c, auto)).collect();
41
42 if !auto {
43 let pk: Vec<String> = t.primary_key().iter().map(|c| c.name.clone()).collect();
44 if !pk.is_empty() {
45 lines.push(format!("PRIMARY KEY ({})", pk.join(", ")));
46 }
47 }
48 for c in &t.columns {
49 if let Some(fk) = &c.references {
50 let mut line = format!("FOREIGN KEY ({}) REFERENCES {}({})", c.name, fk.table, fk.column);
51 if let Some(od) = fk.on_delete {
52 line.push_str(&format!(" ON DELETE {}", od.sql()));
53 }
54 lines.push(line);
55 }
56 }
57
58 format!("CREATE TABLE {} (\n {}\n);", t.name, lines.join(",\n "))
59}
60
61pub fn index_name(table: &str, column: &str) -> String {
62 format!("idx_{table}_{column}")
63}
64
65pub fn index_sqls(t: &TableDef) -> Vec<String> {
67 t.columns
68 .iter()
69 .filter(|c| c.index)
70 .map(|c| {
71 format!(
72 "CREATE INDEX {} ON {} ({});",
73 index_name(&t.name, &c.name),
74 t.name,
75 c.name
76 )
77 })
78 .collect()
79}