yauth_migration/
sqlite.rs1use std::borrow::Cow;
14
15use super::collector::YAuthSchema;
16use super::types::*;
17
18pub(crate) fn sqlite_type(col_type: &ColumnType) -> Cow<'static, str> {
20 match col_type {
21 ColumnType::Uuid => Cow::Borrowed("TEXT"),
22 ColumnType::Varchar => Cow::Borrowed("TEXT"),
23 ColumnType::VarcharN(_) => Cow::Borrowed("TEXT"),
24 ColumnType::Boolean => Cow::Borrowed("INTEGER"),
25 ColumnType::DateTime => Cow::Borrowed("TEXT"),
26 ColumnType::Json => Cow::Borrowed("TEXT"),
27 ColumnType::Int => Cow::Borrowed("INTEGER"),
28 ColumnType::SmallInt => Cow::Borrowed("INTEGER"),
29 ColumnType::Text => Cow::Borrowed("TEXT"),
30 }
31}
32
33fn sqlite_on_delete(action: &OnDelete) -> &'static str {
35 match action {
36 OnDelete::Cascade => "ON DELETE CASCADE",
37 OnDelete::SetNull => "ON DELETE SET NULL",
38 OnDelete::Restrict => "ON DELETE RESTRICT",
39 OnDelete::NoAction => "ON DELETE NO ACTION",
40 }
41}
42
43pub(crate) fn sqlite_default(pg_default: &str) -> Option<Cow<'static, str>> {
45 match pg_default {
46 "gen_random_uuid()" => None,
47 "now()" => Some(Cow::Borrowed("CURRENT_TIMESTAMP")),
48 other => Some(Cow::Owned(other.to_string())),
49 }
50}
51
52fn generate_create_table(table: &TableDef) -> String {
54 let mut sql = String::new();
55 if let Some(ref desc) = table.description {
56 sql.push_str(&format!("-- {desc}\n"));
57 }
58 sql.push_str(&format!("CREATE TABLE IF NOT EXISTS {} (\n", table.name));
59
60 let col_count = table.columns.len();
61 for (i, col) in table.columns.iter().enumerate() {
62 sql.push_str(" ");
63 sql.push_str(&col.name);
64 sql.push(' ');
65 sql.push_str(&sqlite_type(&col.col_type));
66
67 if col.primary_key {
68 sql.push_str(" PRIMARY KEY");
69 if let Some(ref default) = col.default
70 && let Some(mapped) = sqlite_default(default)
71 {
72 sql.push_str(" DEFAULT ");
73 sql.push_str(&mapped);
74 }
75 if let Some(ref fk) = col.foreign_key {
76 sql.push_str(&format!(
77 " REFERENCES {}({}) {}",
78 fk.references_table,
79 fk.references_column,
80 sqlite_on_delete(&fk.on_delete)
81 ));
82 }
83 } else if let Some(ref fk) = col.foreign_key {
84 if !col.nullable {
85 sql.push_str(" NOT NULL");
86 }
87 sql.push_str(&format!(
88 " REFERENCES {}({}) {}",
89 fk.references_table,
90 fk.references_column,
91 sqlite_on_delete(&fk.on_delete)
92 ));
93 if col.unique {
94 sql.push_str(" UNIQUE");
95 }
96 } else {
97 if !col.nullable {
98 sql.push_str(" NOT NULL");
99 }
100 if col.unique {
101 sql.push_str(" UNIQUE");
102 }
103 if let Some(ref default) = col.default
104 && let Some(mapped) = sqlite_default(default)
105 {
106 sql.push_str(" DEFAULT ");
107 sql.push_str(&mapped);
108 }
109 }
110
111 if i < col_count - 1 {
112 sql.push(',');
113 }
114 sql.push('\n');
115 }
116
117 sql.push_str(");\n");
118 sql
119}
120
121pub fn generate_sqlite_ddl(schema: &YAuthSchema) -> String {
126 let mut ddl = String::from("PRAGMA foreign_keys = ON;\n\n");
127 for (i, table) in schema.tables.iter().enumerate() {
128 if i > 0 {
129 ddl.push('\n');
130 }
131 ddl.push_str(&generate_create_table(table));
132 }
133 ddl
134}
135
136pub fn generate_sqlite_drop(table: &TableDef) -> String {
138 format!("DROP TABLE IF EXISTS {};\n", table.name)
139}
140
141pub fn generate_sqlite_drops(tables: &[TableDef]) -> String {
143 let mut ddl = String::new();
144 for (i, table) in tables.iter().rev().enumerate() {
145 if i > 0 {
146 ddl.push('\n');
147 }
148 ddl.push_str(&generate_sqlite_drop(table));
149 }
150 ddl
151}