diff options
| author | Mroik <mroik@delayed.space> | 2026-03-31 21:32:23 +0200 |
|---|---|---|
| committer | Mroik <mroik@delayed.space> | 2026-04-13 06:55:04 +0200 |
| commit | 8f8fd10dc2b185ca0a8e8908229c4d4bbefd70b7 (patch) | |
| tree | d86307f33b62e65bf97f41bbd7c84e22008c5f69 /src/database.rs | |
| parent | e37cb31107a33a720758e3265801e9367332ec33 (diff) | |
Add scaffolding for DB interactions
The mailing list will need to save various data to operate for things
such as the subscriber's email.
Add database interaction machanism.
Signed-off-by: Mroik <mroik@delayed.space>
Diffstat (limited to 'src/database.rs')
| -rw-r--r-- | src/database.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..a1d0a18 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,80 @@ +use anyhow::Result; +use rusqlite::{Connection, Transaction, config::DbConfig}; + +const DB_NAME: &str = "database.sqlite"; +const DB_VERSION: i64 = 0; + +struct Database { + conn: Connection, +} + +impl Database { + fn new() -> Result<Self> { + let mut init = false; + if !std::fs::exists(DB_NAME)? { + init = true; + } + + let mut db = Database { + conn: Connection::open(DB_NAME)?, + }; + if init { + db.initialize()?; + } + + db.conn.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY)?; + + Ok(db) + } + + fn initialize(&mut self) -> Result<()> { + let tx = self.conn.transaction()?; + let mut q = "CREATE TABLE version ( + version INTEGER NOT NULL, + UNIQUE (version))"; + tx.execute(q, ())?; + + q = "INSERT INTO version VALUES (?)"; + tx.execute(q, &[&DB_VERSION])?; + + q = "CREATE TABLE user ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + email TEXT NOT NULL, + UNIQUE (email))"; + tx.execute(q, ())?; + + q = "CREATE TABLE list ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + description TEXT, + UNIQUE (name))"; + tx.execute(q, ())?; + + q = "CREATE TABLE subscription ( + user_id INTEGER REFERENCES user (id), + list_id INTEGER REFERENCES list (id), + UNIQUE (user_id, list_id))"; + tx.execute(q, ())?; + + tx.commit()?; + Ok(()) + } + + fn execute<Ex>(&mut self, q: Ex) -> Result<QueryResult<Ex::T>> where Ex: DBExecutable { + let tx = self.conn.transaction()?; + let ris = q.execute(&tx)?; + tx.commit()?; + Ok(ris) + } +} + +pub trait DBExecutable { + type T; + fn execute(&self, tx: &Transaction) -> Result<QueryResult<Self::T>>; +} + +pub enum QueryResult<T> { + Empty, + Vec(Vec<T>) +} |
