pub mod console;
mod migrator;
pub use migrator::{Failure, Migrator, Outcome, RollbackReport, RunReport, State, Status, TABLE};
pub async fn drop_all_tables(conn: &libsql::Connection) -> crate::Result<usize> {
let mut rows = conn
.query(
"SELECT type, name FROM sqlite_schema
WHERE type IN ('table', 'view')
AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'libsql_%'
AND name NOT LIKE '_litestream%'
ORDER BY type DESC",
(),
)
.await?;
let mut objects = Vec::new();
while let Some(row) = rows.next().await? {
objects.push((row.get::<String>(0)?, row.get::<String>(1)?));
}
drop(rows);
conn.execute("PRAGMA foreign_keys = OFF", ()).await?;
for (kind, name) in &objects {
let kind = if kind == "view" { "VIEW" } else { "TABLE" };
let name = name.replace('"', "\"\"");
conn.execute(&format!("DROP {kind} IF EXISTS \"{name}\""), ())
.await?;
}
conn.execute("PRAGMA foreign_keys = ON", ()).await?;
Ok(objects.iter().filter(|(kind, _)| kind == "table").count())
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Schema {
statements: Vec<String>,
}
impl Schema {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn execute(mut self, sql: impl Into<String>) -> Self {
self.statements.push(sql.into());
self
}
pub fn statements(&self) -> &[String] {
&self.statements
}
}
pub trait Migration: Send + Sync {
fn up(&self) -> Schema;
fn down(&self) -> Option<Schema> {
None
}
fn transactional(&self) -> bool {
true
}
}
#[derive(Clone, Copy)]
pub struct Registered {
name: &'static str,
migration: &'static dyn Migration,
}
impl Registered {
pub fn new(name: &'static str, migration: &'static dyn Migration) -> Self {
Self { name, migration }
}
pub fn from_module(module: &'static str, migration: &'static dyn Migration) -> Self {
Self::new(module.strip_prefix('m').unwrap_or(module), migration)
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn migration(&self) -> &'static dyn Migration {
self.migration
}
}
impl std::fmt::Debug for Registered {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Registered")
.field("name", &self.name)
.finish()
}
}
#[macro_export]
macro_rules! migrations {
($($module:ident),* $(,)?) => {
vec![$(
$crate::migration::Registered::from_module(stringify!($module), $module::MIGRATION)
),*]
};
}