From b12f5e8b8fa3bf87c086c202d02f36cba41dfbe5 Mon Sep 17 00:00:00 2001 From: yggverse Date: Wed, 13 Nov 2024 03:40:29 +0200 Subject: [PATCH] move profile components to separated namespace --- src/app.rs | 11 ++--- src/main.rs | 5 +- src/profile.rs | 61 ++++++++++++++++++++++-- src/profile/bookmark.rs | 18 +++++++ src/profile/bookmark/database.rs | 81 +++++++++++++++++++++++++++++++ src/profile/database.rs | 82 ++++++++++++-------------------- src/profile/database/bookmark.rs | 65 ------------------------- src/profile/database/history.rs | 65 ------------------------- src/profile/database/identity.rs | 20 -------- src/profile/history.rs | 18 +++++++ src/profile/history/database.rs | 81 +++++++++++++++++++++++++++++++ src/profile/identity.rs | 18 +++++++ src/profile/identity/database.rs | 21 ++++++++ 13 files changed, 332 insertions(+), 214 deletions(-) create mode 100644 src/profile/bookmark.rs create mode 100644 src/profile/bookmark/database.rs delete mode 100644 src/profile/database/bookmark.rs delete mode 100644 src/profile/database/history.rs delete mode 100644 src/profile/database/identity.rs create mode 100644 src/profile/history.rs create mode 100644 src/profile/history/database.rs create mode 100644 src/profile/identity.rs create mode 100644 src/profile/identity/database.rs diff --git a/src/app.rs b/src/app.rs index fa5a26d4..fc5a3873 100644 --- a/src/app.rs +++ b/src/app.rs @@ -21,10 +21,7 @@ pub struct App { impl App { // Construct - pub fn new() -> Self { - // Init profile - let profile = Rc::new(Profile::new()); - + pub fn new(profile: Rc) -> Self { // Init GTK let gobject = Application::builder() .application_id(APPLICATION_ID) @@ -44,7 +41,7 @@ impl App { let profile = profile.clone(); move |this| { // Init readable connection - match profile.database().connection().read() { + match profile.database().read() { Ok(connection) => { // Create transaction match connection.unchecked_transaction() { @@ -86,7 +83,7 @@ impl App { let profile = profile.clone(); move |_| { // Init writable connection - match profile.database().connection().write() { + match profile.database().write() { Ok(mut connection) => { // Create transaction match connection.transaction() { @@ -243,7 +240,7 @@ impl App { // Begin database migration @TODO { // Init writable connection - let mut connection = match self.profile.database().connection().try_write() { + let mut connection = match self.profile.database().try_write() { Ok(connection) => connection, Err(e) => todo!("{e}"), }; diff --git a/src/main.rs b/src/main.rs index a03c3a7c..c3c56a37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,14 @@ mod app; mod profile; use app::App; +use profile::Profile; + use gtk::glib::ExitCode; +use std::rc::Rc; fn main() -> ExitCode { match gtk::init() { - Ok(_) => App::new().run(), + Ok(_) => App::new(Rc::new(Profile::new())).run(), Err(_) => ExitCode::FAILURE, } } diff --git a/src/profile.rs b/src/profile.rs index 11c903c1..a2e95fab 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -1,10 +1,15 @@ +mod bookmark; mod database; -use database::Database; +mod history; +mod identity; use gtk::glib::user_config_dir; +use sqlite::{Connection, Transaction}; use std::{ fs::create_dir_all, path::{Path, PathBuf}, + rc::Rc, + sync::RwLock, }; const VENDOR: &str = "YGGverse"; @@ -14,7 +19,7 @@ const BRANCH: &str = "master"; const DB_NAME: &str = "profile.sqlite3"; pub struct Profile { - database: Database, + database: Rc>, config_path: PathBuf, } @@ -42,16 +47,49 @@ impl Profile { let mut database_path = config_path.clone(); database_path.push(DB_NAME); + // Init database connection + let connection = match Connection::open(database_path.as_path()) { + Ok(connection) => Rc::new(RwLock::new(connection)), + Err(reason) => panic!("{reason}"), + }; + + // Init profile components + { + // Init writable connection + let mut connection = match connection.write() { + Ok(connection) => connection, + Err(e) => todo!("{e}"), + }; + + // Init new transaction + let transaction = match connection.transaction() { + Ok(transaction) => transaction, + Err(e) => todo!("{e}"), + }; + + // Begin migration + match migrate(&transaction) { + Ok(_) => { + // Confirm changes + match transaction.commit() { + Ok(_) => {} // @TODO + Err(e) => todo!("{e}"), + } + } + Err(e) => todo!("{e}"), + } + } // unlock database + // Result Self { - database: Database::new(database_path.as_path()), + database: connection, config_path, } } // Getters - pub fn database(&self) -> &Database { + pub fn database(&self) -> &Rc> { &self.database } @@ -59,3 +97,18 @@ impl Profile { self.config_path.as_path() } } + +pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = database::init(tx) { + return Err(e.to_string()); + } + + // Delegate migration to children components + bookmark::migrate(tx)?; + history::migrate(tx)?; + identity::migrate(tx)?; + + // Success + Ok(()) +} diff --git a/src/profile/bookmark.rs b/src/profile/bookmark.rs new file mode 100644 index 00000000..ac00d38d --- /dev/null +++ b/src/profile/bookmark.rs @@ -0,0 +1,18 @@ +mod database; + +use sqlite::Transaction; + +// Tools + +pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = database::init(tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + // nothing yet.. + + // Success + Ok(()) +} diff --git a/src/profile/bookmark/database.rs b/src/profile/bookmark/database.rs new file mode 100644 index 00000000..b3e7f3b6 --- /dev/null +++ b/src/profile/bookmark/database.rs @@ -0,0 +1,81 @@ +use gtk::glib::DateTime; +use sqlite::{Error, Transaction}; + +pub struct Table { + pub id: i64, + pub profile_id: i64, + pub time: DateTime, + pub request: String, +} + +pub struct Bookmark { + // nothing yet.. +} + +pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `profile_bookmark` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `profile_id` INTEGER NOT NULL, + `time` INTEGER NOT NULL, + `request` TEXT NOT NULL + )", + [], + ) +} + +pub fn add( + tx: &Transaction, + profile_id: &i64, + time: &DateTime, + request: &str, +) -> Result { + tx.execute( + "INSERT INTO `profile_bookmark` ( + `profile_id`, + `time`, + `request` + ) VALUES (?, ?, ?)", + (profile_id, time.to_unix(), request), + ) +} + +pub fn records( + tx: &Transaction, + profile_id: &i64, + request: Option<&str>, +) -> Result, Error> { + let mut stmt = tx.prepare( + "SELECT `id`, `profile_id`, `time`, `request` + FROM `profile_bookmark` + WHERE `profile_id` = ? AND `request` LIKE ?", + )?; + + let filter = match request { + Some(value) => value, + None => "%", + }; + + let result = stmt.query_map((profile_id, filter), |row| { + Ok(Table { + id: row.get(0)?, + profile_id: row.get(1)?, + time: DateTime::from_unix_local(row.get(2)?).unwrap(), + request: row.get(3)?, + }) + })?; + + let mut records = Vec::new(); + + for record in result { + let table = record?; + records.push(table); + } + + Ok(records) +} + +pub fn delete(tx: &Transaction, id: &i64) -> Result { + tx.execute("DELETE FROM `profile_bookmark` WHERE `id` = ?", [id]) +} diff --git a/src/profile/database.rs b/src/profile/database.rs index e7b5e217..5b0d11fe 100644 --- a/src/profile/database.rs +++ b/src/profile/database.rs @@ -1,63 +1,41 @@ -mod bookmark; -mod history; -mod identity; +use sqlite::{Error, Transaction}; -use sqlite::{Connection, Error}; -use std::{ - path::Path, - rc::Rc, - sync::{RwLock, RwLockWriteGuard}, -}; - -pub struct Database { - connection: Rc>, +pub struct Table { + pub id: i64, } -impl Database { - // Constructors +pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `profile` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL + )", + [], + ) +} - /// Create new connected `Self` - pub fn new(path: &Path) -> Self { - // Init database connection - let connection = match Connection::open(path) { - Ok(connection) => Rc::new(RwLock::new(connection)), - Err(reason) => panic!("{reason}"), - }; +pub fn add(tx: &Transaction) -> Result { + tx.execute("INSERT INTO `profile` DEFAULT VALUES", []) +} - // Init profile components - match connection.write() { - Ok(writable) => { - if let Err(reason) = init(writable) { - panic!("{reason}") - } - } - Err(reason) => panic!("{reason}"), - }; +pub fn records(tx: &Transaction) -> Result, Error> { + let mut stmt = tx.prepare("SELECT `profile_id` FROM `profile`")?; + let result = stmt.query_map([], |row| Ok(Table { id: row.get(0)? }))?; - // Result - Self { connection } + let mut records = Vec::new(); + + for record in result { + let table = record?; + records.push(table); } - // Getters - - pub fn connection(&self) -> &Rc> { - &self.connection - } + Ok(records) } -// Tools - -fn init(mut connection: RwLockWriteGuard<'_, Connection>) -> Result<(), Error> { - // Begin transaction - let transaction = connection.transaction()?; - - // Init profile components - bookmark::init(&transaction)?; - history::init(&transaction)?; - identity::init(&transaction)?; - - // Apply changes - transaction.commit()?; - - Ok(()) +pub fn delete(tx: &Transaction, id: &i64) -> Result { + tx.execute("DELETE FROM `profile` WHERE `id` = ?", [id]) +} + +pub fn last_insert_id(tx: &Transaction) -> i64 { + tx.last_insert_rowid() } diff --git a/src/profile/database/bookmark.rs b/src/profile/database/bookmark.rs deleted file mode 100644 index 956bc24d..00000000 --- a/src/profile/database/bookmark.rs +++ /dev/null @@ -1,65 +0,0 @@ -use gtk::glib::DateTime; -use sqlite::{Error, Transaction}; - -pub struct Table { - pub id: i64, - pub time: DateTime, - pub request: String, -} - -pub struct Bookmark { - // nothing yet.. -} - -pub fn init(tx: &Transaction) -> Result { - tx.execute( - "CREATE TABLE IF NOT EXISTS `bookmark` - ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - `time` INTEGER NOT NULL, - `request` TEXT NOT NULL - )", - [], - ) -} - -pub fn add(tx: &Transaction, time: &DateTime, request: &str) -> Result { - tx.execute( - "INSERT INTO `bookmark` ( - `time`, - `request` - ) VALUES (?, ?)", - (time.to_unix(), request), - ) -} - -pub fn records(tx: &Transaction, request: Option<&str>) -> Result, Error> { - let mut stmt = - tx.prepare("SELECT `id`, `time`, `request` FROM `bookmark` WHERE `request` LIKE ?")?; - - let filter = match request { - Some(value) => value, - None => "%", - }; - - let result = stmt.query_map([filter], |row| { - Ok(Table { - id: row.get(0)?, - time: DateTime::from_unix_local(row.get(1)?).unwrap(), - request: row.get(2)?, - }) - })?; - - let mut records = Vec::new(); - - for record in result { - let table = record?; - records.push(table); - } - - Ok(records) -} - -pub fn delete(tx: &Transaction, id: &i64) -> Result { - tx.execute("DELETE FROM `bookmark` WHERE `id` = ?", [id]) -} diff --git a/src/profile/database/history.rs b/src/profile/database/history.rs deleted file mode 100644 index 3564b405..00000000 --- a/src/profile/database/history.rs +++ /dev/null @@ -1,65 +0,0 @@ -use gtk::glib::DateTime; -use sqlite::{Error, Transaction}; - -pub struct Table { - pub id: i64, - pub time: DateTime, - pub request: String, -} - -pub struct History { - // nothing yet.. -} - -pub fn init(tx: &Transaction) -> Result { - tx.execute( - "CREATE TABLE IF NOT EXISTS `history` - ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - `time` INTEGER NOT NULL, - `request` TEXT NOT NULL - )", - [], - ) -} - -pub fn add(tx: &Transaction, time: &DateTime, request: &str) -> Result { - tx.execute( - "INSERT INTO `history` ( - `time`, - `request` - ) VALUES (?, ?)", - (time.to_unix(), request), - ) -} - -pub fn records(tx: &Transaction, request: Option<&str>) -> Result, Error> { - let mut stmt = - tx.prepare("SELECT `id`, `time`, `request` FROM `history` WHERE `request` LIKE ?")?; - - let filter = match request { - Some(value) => value, - None => "%", - }; - - let result = stmt.query_map([filter], |row| { - Ok(Table { - id: row.get(0)?, - time: DateTime::from_unix_local(row.get(1)?).unwrap(), - request: row.get(2)?, - }) - })?; - - let mut records = Vec::new(); - - for record in result { - let table = record?; - records.push(table); - } - - Ok(records) -} - -pub fn delete(tx: &Transaction, id: &i64) -> Result { - tx.execute("DELETE FROM `history` WHERE `id` = ?", [id]) -} diff --git a/src/profile/database/identity.rs b/src/profile/database/identity.rs deleted file mode 100644 index 004892ef..00000000 --- a/src/profile/database/identity.rs +++ /dev/null @@ -1,20 +0,0 @@ -use sqlite::{Error, Transaction}; - -pub struct Table { - pub id: i64, - // pub app_id: i64, -} - -pub fn init(tx: &Transaction) -> Result { - tx.execute( - "CREATE TABLE IF NOT EXISTS `identity` - ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - `time` INTEGER NOT NULL, - `name` VARCHAR(255), - `crt` TEXT NOT NULL, - `key` TEXT NOT NULL - )", - [], - ) -} diff --git a/src/profile/history.rs b/src/profile/history.rs new file mode 100644 index 00000000..ac00d38d --- /dev/null +++ b/src/profile/history.rs @@ -0,0 +1,18 @@ +mod database; + +use sqlite::Transaction; + +// Tools + +pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = database::init(tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + // nothing yet.. + + // Success + Ok(()) +} diff --git a/src/profile/history/database.rs b/src/profile/history/database.rs new file mode 100644 index 00000000..57deb4a7 --- /dev/null +++ b/src/profile/history/database.rs @@ -0,0 +1,81 @@ +use gtk::glib::DateTime; +use sqlite::{Error, Transaction}; + +pub struct Table { + pub id: i64, + pub profile_id: i64, + pub time: DateTime, + pub request: String, +} + +pub struct History { + // nothing yet.. +} + +pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `profile_history` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `profile_id` INTEGER NOT NULL, + `time` INTEGER NOT NULL, + `request` TEXT NOT NULL + )", + [], + ) +} + +pub fn add( + tx: &Transaction, + profile_id: &i64, + time: &DateTime, + request: &str, +) -> Result { + tx.execute( + "INSERT INTO `history` ( + `profile_id`, + `time`, + `request` + ) VALUES (?, ?, ?)", + (profile_id, time.to_unix(), request), + ) +} + +pub fn records( + tx: &Transaction, + profile_id: &i64, + request: Option<&str>, +) -> Result, Error> { + let mut stmt = tx.prepare( + "SELECT `id`, `profile_id`, `time`, `request` + FROM `profile_history` + WHERE `profile_id` = ? AND `request` LIKE ?", + )?; + + let filter = match request { + Some(value) => value, + None => "%", + }; + + let result = stmt.query_map((profile_id, filter), |row| { + Ok(Table { + id: row.get(0)?, + profile_id: row.get(1)?, + time: DateTime::from_unix_local(row.get(2)?).unwrap(), + request: row.get(3)?, + }) + })?; + + let mut records = Vec::new(); + + for record in result { + let table = record?; + records.push(table); + } + + Ok(records) +} + +pub fn delete(tx: &Transaction, id: &i64) -> Result { + tx.execute("DELETE FROM `profile_history` WHERE `id` = ?", [id]) +} diff --git a/src/profile/identity.rs b/src/profile/identity.rs new file mode 100644 index 00000000..ac00d38d --- /dev/null +++ b/src/profile/identity.rs @@ -0,0 +1,18 @@ +mod database; + +use sqlite::Transaction; + +// Tools + +pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = database::init(tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + // nothing yet.. + + // Success + Ok(()) +} diff --git a/src/profile/identity/database.rs b/src/profile/identity/database.rs new file mode 100644 index 00000000..a6164ca1 --- /dev/null +++ b/src/profile/identity/database.rs @@ -0,0 +1,21 @@ +use sqlite::{Error, Transaction}; + +pub struct Table { + pub id: i64, + //pub profile_id: i64, +} + +pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `profile_identity` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `profile_id` INTEGER NOT NULL, + `time` INTEGER NOT NULL, + `name` VARCHAR(255), + `certificate` TEXT NOT NULL, + `key` TEXT NOT NULL + )", + [], + ) +}