toolu_orm_cli/migrate/
baseline.rs1use std::path::Path;
5
6use toolu_orm_connection::DbConnection;
7use toolu_orm_core::dialect::Dialect;
8use toolu_orm_core::journal::{Journal, JournalEntry};
9
10use super::error::MigrateError;
11use super::store::{ensure_migrations_table, get_applied_migrations, record_migration};
12use super::transaction::{begin, commit, rollback_after};
13
14pub async fn mark_applied(
32 conn: &impl DbConnection,
33 migrations_dir: &str,
34 names: &[&str],
35 dialect: Dialect,
36) -> Result<u32, MigrateError> {
37 let journal = read_journal(migrations_dir)?;
38
39 let unknown: Vec<&str> = names
40 .iter()
41 .copied()
42 .filter(|name| !journal.entries.iter().any(|entry| entry.name == *name))
43 .collect();
44 if !unknown.is_empty() {
45 return Err(MigrateError::NotInJournal(unknown.join(", ")));
46 }
47
48 let selected: Vec<&JournalEntry> = journal
51 .entries
52 .iter()
53 .filter(|entry| names.contains(&entry.name.as_str()))
54 .collect();
55
56 record_all(conn, &selected, dialect).await
57}
58
59pub async fn mark_applied_through(
71 conn: &impl DbConnection,
72 migrations_dir: &str,
73 last_name: &str,
74 dialect: Dialect,
75) -> Result<u32, MigrateError> {
76 let journal = read_journal(migrations_dir)?;
77
78 let position = journal
79 .entries
80 .iter()
81 .position(|entry| entry.name == last_name)
82 .ok_or_else(|| MigrateError::NotInJournal(last_name.to_owned()))?;
83
84 let selected: Vec<&JournalEntry> = journal.entries.iter().take(position + 1).collect();
85
86 record_all(conn, &selected, dialect).await
87}
88
89fn read_journal(migrations_dir: &str) -> Result<Journal, MigrateError> {
90 let journal_path = Path::new(migrations_dir).join("_journal.json");
91 let journal_path_str = journal_path.to_str().ok_or_else(|| {
92 MigrateError::ReadFile(format!("{} is not valid UTF-8", journal_path.display()))
93 })?;
94 Journal::read_from_path(journal_path_str).map_err(|e| MigrateError::ReadFile(format!("{e}")))
95}
96
97async fn record_all(
105 conn: &impl DbConnection,
106 entries: &[&JournalEntry],
107 dialect: Dialect,
108) -> Result<u32, MigrateError> {
109 ensure_migrations_table(conn, dialect).await?;
110
111 begin(conn).await?;
112
113 let mut count: u32 = 0;
114 let result = async {
115 let applied = get_applied_migrations(conn).await?;
116 for entry in entries {
117 if applied.contains(&entry.name) {
118 continue;
119 }
120 record_migration(conn, &entry.name, &entry.hash, dialect).await?;
121 count += 1;
122 }
123 Ok(())
124 }
125 .await;
126
127 if let Err(e) = result {
128 return Err(rollback_after(conn, e).await);
129 }
130
131 commit(conn).await?;
132 Ok(count)
133}