Day 3: Migratory dirs
Just a quick one today because I am sleepy!
I need to be able to store the URLs for feeds to sync from. I considered using a config file for this (such as KDL) but I think a CLI-managed database would be nice instead. Maybe also with the option to export/import from a config file so you can move between machines. Hm… I may revisit this at some point. I know people like to be able to sync their dotfiles and have that Just Work. Maybe URLs should be in a file and everything else a DB?
Regardless, we need some sort of database to keep track of when we last synced etc. To keep things simple, I’ll use SQLite, which seems like the obvious choice. Embedding a database into a program is exactly what it was made for. So, how do we manage that?
Database migrations
If you wish to make a CLI from scratch, you must first create the database. I started writing my own database migration system using rusqlite directly before I realized that it would be a real pain, and probably a solved problem. I instead searched for an existing solution and found refinery. It seems fully featured, though I don’t love the hard requirement to use procedural macros, which can slow compile times. I’m forcing myself to not go all-in on dependency reduction early on though. Besides, reqwest et al. are much worse for that.
Like last time, I’m using directories to figure out where the data should live.
fn main() -> Result<()> {
// ---8<--- snip
let data_dir = project_dirs.data_dir();
std::fs::create_dir_all(&data_dir)?;
let db_path = data_dir.join("seance.db");
setup_db(&db_path)?;
// ---8<--- snip
}
mod embedded {
use refinery::embed_migrations;
embed_migrations!("./migrations");
}
fn setup_db(path: &Path) -> Result<()> {
let mut conn = Connection::open(path)?;
embedded::migrations::runner().run(&mut conn)?;
Ok(())
}
This works! Checking using the sqlite3 CLI, I see that it has created an (empty) table called refinery_schema_history. Séance will now use this table to keep track of what migrations need to be run. The migration files themselves will be embedded in the binary during compiliation.