1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use std::{path::{PathBuf, Path}, collections::HashMap, io::Error, fs::read_to_string};

use sha2::{Sha256, Digest};

#[derive(Debug)]
pub struct Migration {
  pub id: String,
  pub path: PathBuf
}

impl Migration {
  pub fn migrate_path(&self) -> PathBuf {
    self.path.join("migrate.sql")
  }

  pub fn revert_path(&self) -> PathBuf {
    self.path.join("revert.sql")
  }

  pub fn migrate_sql(&self) -> anyhow::Result<String> {
    Ok(read_to_string(self.migrate_path())?)
  }

  pub fn revert_sql(&self) -> anyhow::Result<String> {
    Ok(read_to_string(self.revert_path())?)
  }

  pub fn migrate_hash(&self) -> anyhow::Result<String> {
    let contents = self.migrate_sql()?;
    let mut hasher = Sha256::new();
    hasher.update(contents);
    Ok(hex::encode(hasher.finalize()))
  }
}

pub struct MigrationRegistry {
  pub db: HashMap<String, Migration>
}

impl MigrationRegistry {
  pub fn load(dir: &Path) -> Result<Self, Error> {
    let db: HashMap<String, Migration> = dir.read_dir()?.into_iter().filter_map(|entry| {
      let entry = entry.ok()?;
      if entry.file_type().ok()?.is_dir() {
        let id = entry.path().file_name()?.to_str()?.to_owned();
        Some((id.clone(), Migration {
          id,
          path: entry.path()
        }))
      } else {
        None
      }
    }).collect();
    Ok(Self {
      db
    })
  }
}