midas_core/sequel/
sqlite.rs1use std::fs;
2use std::path::Path;
3
4use indoc::indoc;
5use rusqlite::Connection;
6
7use super::{
8 AnyhowResult,
9 Driver as SequelDriver,
10 VecSerial,
11};
12
13pub struct Sqlite {
15 conn: Connection,
17 file_url: String,
19}
20
21impl Sqlite {
23 pub fn new(file_url: &str) -> AnyhowResult<Self> {
33 log::trace!("Opening SQLite database connection: {file_url}");
34
35 let file_url = file_url
38 .replace("file://", "")
39 .replace("file:", "")
40 .replace("sqlite://", "")
41 .replace("sqlite:", "");
42
43 let file_url: &str = if file_url.starts_with("/") {
46 &file_url.to_string()
47 } else {
48 &format!("./{}", file_url)
49 };
50
51 let conn = Connection::open(file_url)?;
53 let mut db: Sqlite = Sqlite {
54 conn,
55 file_url: file_url.to_string(),
56 };
57
58 db.ensure_midas_schema()?;
60 Ok(db)
61 }
62}
63
64impl SequelDriver for Sqlite {
66 fn ensure_midas_schema(&mut self) -> AnyhowResult<()> {
69 let payload = indoc! {"
70 CREATE TABLE IF NOT EXISTS __schema_migrations (
71 id INTEGER PRIMARY KEY AUTOINCREMENT,
72 migration BIGINT
73 );
74 "};
75 self.conn.execute(payload, ())?;
76 Ok(())
77 }
78
79 fn drop_migration_table(&mut self) -> AnyhowResult<()> {
81 let payload = "DROP TABLE __schema_migrations";
82 self.conn.execute(payload, ())?;
83 Ok(())
84 }
85
86 fn drop_database(&mut self, _: &str) -> AnyhowResult<()> {
88 let path = Path::new(&self.file_url);
91 if path.exists() {
92 fs::remove_file(path)?;
93 }
94
95 Connection::open(path)?;
97 Ok(())
98 }
99
100 fn count_migrations(&mut self) -> AnyhowResult<i64> {
102 log::trace!("Retrieving migrations count");
103 let payload = "SELECT COUNT(*) as count FROM __schema_migrations";
104 let mut stmt = self.conn.prepare(payload)?;
105 let result = stmt.query_row((), |row| row.get(0))?;
106 Ok(result)
107 }
108
109 fn get_completed_migrations(&mut self) -> AnyhowResult<VecSerial> {
111 log::trace!("Retrieving all completed migrations");
112 let payload = "SELECT migration FROM __schema_migrations ORDER BY id ASC";
113 let mut stmt = self.conn.prepare(payload)?;
114 let it = stmt.query_map((), |row| row.get(0))?;
115 let result = it.map(|r| r.unwrap()).collect::<VecSerial>();
116 Ok(result)
117 }
118
119 fn get_last_completed_migration(&mut self) -> AnyhowResult<i64> {
121 log::trace!("Checking and retrieving the last migration stored on migrations table");
122 let payload = "SELECT migration FROM __schema_migrations ORDER BY id DESC LIMIT 1";
123 let mut stmt = self.conn.prepare(payload)?;
124 let result = stmt.query_row((), |row| row.get(0))?;
125 Ok(result)
126 }
127
128 fn add_completed_migration(&mut self, migration_number: i64) -> AnyhowResult<()> {
130 log::trace!("Adding migration to migrations table");
131 let payload = "INSERT INTO __schema_migrations (migration) VALUES ($1)";
132 self.conn.execute(payload, [&migration_number])?;
133 Ok(())
134 }
135
136 fn delete_completed_migration(&mut self, migration_number: i64) -> AnyhowResult<()> {
138 log::trace!("Removing a migration in the migrations table");
139 let payload = "DELETE FROM __schema_migrations WHERE migration = $1";
140 self.conn.execute(payload, [&migration_number])?;
141 Ok(())
142 }
143
144 fn delete_last_completed_migration(&mut self) -> AnyhowResult<()> {
146 let payload = "DELETE FROM __schema_migrations WHERE id=(SELECT MAX(id) FROM __schema_migrations);";
147 self.conn.execute(payload, ())?;
148 Ok(())
149 }
150
151 fn migrate(&mut self, query: &str, _migration_number: i64) -> AnyhowResult<()> {
153 self.conn.execute(query, ())?;
154 Ok(())
155 }
156
157 fn db_name(&self) -> &str {
159 "sqlite"
160 }
161}