slave_framework/migration/
mod.rs1pub mod console;
16mod migrator;
17
18pub use migrator::{Failure, Migrator, Outcome, RollbackReport, RunReport, State, Status, TABLE};
19
20pub async fn drop_all_tables(conn: &libsql::Connection) -> crate::Result<usize> {
23 let mut rows = conn
24 .query(
25 "SELECT type, name FROM sqlite_schema
26 WHERE type IN ('table', 'view')
27 AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'libsql_%'
28 AND name NOT LIKE '_litestream%'
29 ORDER BY type DESC",
30 (),
31 )
32 .await?;
33 let mut objects = Vec::new();
34 while let Some(row) = rows.next().await? {
35 objects.push((row.get::<String>(0)?, row.get::<String>(1)?));
36 }
37 drop(rows);
38
39 conn.execute("PRAGMA foreign_keys = OFF", ()).await?;
40 for (kind, name) in &objects {
41 let kind = if kind == "view" { "VIEW" } else { "TABLE" };
42 let name = name.replace('"', "\"\"");
43 conn.execute(&format!("DROP {kind} IF EXISTS \"{name}\""), ())
44 .await?;
45 }
46 conn.execute("PRAGMA foreign_keys = ON", ()).await?;
47 Ok(objects.iter().filter(|(kind, _)| kind == "table").count())
48}
49
50#[derive(Debug, Clone, Default, PartialEq, Eq)]
52pub struct Schema {
53 statements: Vec<String>,
54}
55
56impl Schema {
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 #[must_use]
63 pub fn execute(mut self, sql: impl Into<String>) -> Self {
64 self.statements.push(sql.into());
65 self
66 }
67
68 pub fn statements(&self) -> &[String] {
69 &self.statements
70 }
71}
72
73pub trait Migration: Send + Sync {
75 fn up(&self) -> Schema;
77
78 fn down(&self) -> Option<Schema> {
83 None
84 }
85
86 fn transactional(&self) -> bool {
91 true
92 }
93}
94
95#[derive(Clone, Copy)]
97pub struct Registered {
98 name: &'static str,
99 migration: &'static dyn Migration,
100}
101
102impl Registered {
103 pub fn new(name: &'static str, migration: &'static dyn Migration) -> Self {
104 Self { name, migration }
105 }
106
107 pub fn from_module(module: &'static str, migration: &'static dyn Migration) -> Self {
110 Self::new(module.strip_prefix('m').unwrap_or(module), migration)
111 }
112
113 pub fn name(&self) -> &'static str {
114 self.name
115 }
116
117 pub fn migration(&self) -> &'static dyn Migration {
118 self.migration
119 }
120}
121
122impl std::fmt::Debug for Registered {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 f.debug_struct("Registered")
125 .field("name", &self.name)
126 .finish()
127 }
128}
129
130#[macro_export]
136macro_rules! migrations {
137 ($($module:ident),* $(,)?) => {
138 vec![$(
139 $crate::migration::Registered::from_module(stringify!($module), $module::MIGRATION)
140 ),*]
141 };
142}