lib_migrations_core/
store.rs1use crate::Result;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct MigrationRecord {
6 pub version: u64,
7 pub name: String,
8 pub applied_at: u64, }
10
11pub trait MigrationStore {
24 fn init(&mut self) -> Result<()>;
26
27 fn applied(&self) -> Result<Vec<MigrationRecord>>;
29
30 fn is_applied(&self, version: u64) -> Result<bool> {
32 Ok(self.applied()?.iter().any(|r| r.version == version))
33 }
34
35 fn current_version(&self) -> Result<u64> {
37 Ok(self.applied()?.last().map(|r| r.version).unwrap_or(0))
38 }
39
40 fn mark_applied(&mut self, version: u64, name: &str) -> Result<()>;
42
43 fn mark_rolled_back(&mut self, version: u64) -> Result<()>;
45}
46
47#[derive(Debug, Default)]
49pub struct MemoryStore {
50 records: Vec<MigrationRecord>,
51}
52
53impl MemoryStore {
54 pub fn new() -> Self {
55 Self::default()
56 }
57}
58
59impl MigrationStore for MemoryStore {
60 fn init(&mut self) -> Result<()> {
61 Ok(())
62 }
63
64 fn applied(&self) -> Result<Vec<MigrationRecord>> {
65 let mut records = self.records.clone();
66 records.sort_by_key(|r| r.version);
67 Ok(records)
68 }
69
70 fn mark_applied(&mut self, version: u64, name: &str) -> Result<()> {
71 let now = std::time::SystemTime::now()
72 .duration_since(std::time::UNIX_EPOCH)
73 .map(|d| d.as_secs())
74 .unwrap_or(0);
75
76 self.records.push(MigrationRecord {
77 version,
78 name: name.to_string(),
79 applied_at: now,
80 });
81 Ok(())
82 }
83
84 fn mark_rolled_back(&mut self, version: u64) -> Result<()> {
85 self.records.retain(|r| r.version != version);
86 Ok(())
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_memory_store() {
96 let mut store = MemoryStore::new();
97 store.init().unwrap();
98
99 assert_eq!(store.current_version().unwrap(), 0);
100 assert!(!store.is_applied(1).unwrap());
101
102 store.mark_applied(1, "first").unwrap();
103 assert!(store.is_applied(1).unwrap());
104 assert_eq!(store.current_version().unwrap(), 1);
105
106 store.mark_applied(2, "second").unwrap();
107 assert_eq!(store.current_version().unwrap(), 2);
108
109 let applied = store.applied().unwrap();
110 assert_eq!(applied.len(), 2);
111 assert_eq!(applied[0].version, 1);
112 assert_eq!(applied[1].version, 2);
113
114 store.mark_rolled_back(2).unwrap();
115 assert_eq!(store.current_version().unwrap(), 1);
116 assert!(!store.is_applied(2).unwrap());
117 }
118}