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 = format!("CREATE TABLE IF NOT EXISTS {} (\n", table.name);
55
56 let col_count = table.columns.len();
57 for (i, col) in table.columns.iter().enumerate() {
58 sql.push_str(" ");
59 sql.push_str(&col.name);
60 sql.push(' ');
61 sql.push_str(&sqlite_type(&col.col_type));
62
63 if col.primary_key {
64 sql.push_str(" PRIMARY KEY");
65 if let Some(ref default) = col.default
66 && let Some(mapped) = sqlite_default(default)
67 {
68 sql.push_str(" DEFAULT ");
69 sql.push_str(&mapped);
70 }
71 if let Some(ref fk) = col.foreign_key {
72 sql.push_str(&format!(
73 " REFERENCES {}({}) {}",
74 fk.references_table,
75 fk.references_column,
76 sqlite_on_delete(&fk.on_delete)
77 ));
78 }
79 } else if let Some(ref fk) = col.foreign_key {
80 if !col.nullable {
81 sql.push_str(" NOT NULL");
82 }
83 sql.push_str(&format!(
84 " REFERENCES {}({}) {}",
85 fk.references_table,
86 fk.references_column,
87 sqlite_on_delete(&fk.on_delete)
88 ));
89 if col.unique {
90 sql.push_str(" UNIQUE");
91 }
92 } else {
93 if !col.nullable {
94 sql.push_str(" NOT NULL");
95 }
96 if col.unique {
97 sql.push_str(" UNIQUE");
98 }
99 if let Some(ref default) = col.default
100 && let Some(mapped) = sqlite_default(default)
101 {
102 sql.push_str(" DEFAULT ");
103 sql.push_str(&mapped);
104 }
105 }
106
107 if i < col_count - 1 {
108 sql.push(',');
109 }
110 sql.push('\n');
111 }
112
113 sql.push_str(");\n");
114 sql
115}
116
117pub fn generate_sqlite_ddl(schema: &YAuthSchema) -> String {
122 let mut ddl = String::from("PRAGMA foreign_keys = ON;\n\n");
123 for (i, table) in schema.tables.iter().enumerate() {
124 if i > 0 {
125 ddl.push('\n');
126 }
127 ddl.push_str(&generate_create_table(table));
128 }
129 ddl
130}
131
132pub fn generate_sqlite_drop(table: &TableDef) -> String {
134 format!("DROP TABLE IF EXISTS {};\n", table.name)
135}
136
137pub fn generate_sqlite_drops(tables: &[TableDef]) -> String {
139 let mut ddl = String::new();
140 for (i, table) in tables.iter().rev().enumerate() {
141 if i > 0 {
142 ddl.push('\n');
143 }
144 ddl.push_str(&generate_sqlite_drop(table));
145 }
146 ddl
147}