From 3dffcb029ab41fba56816a9d6fca54c6769b1f91 Mon Sep 17 00:00:00 2001 From: yggverse Date: Sun, 6 Oct 2024 18:20:36 +0300 Subject: [PATCH] draft database features --- src/app/browser.rs | 14 ++-- src/app/browser/window.rs | 92 +++++++++++++++++++++++++- src/app/browser/window/database.rs | 64 ++++++++++++++++++ src/app/browser/window/tab.rs | 83 +++++++++++++++++++++-- src/app/browser/window/tab/database.rs | 66 ++++++++++++++++++ 5 files changed, 305 insertions(+), 14 deletions(-) create mode 100644 src/app/browser/window/database.rs create mode 100644 src/app/browser/window/tab/database.rs diff --git a/src/app/browser.rs b/src/app/browser.rs index 5b52d6d3..c972bc09 100644 --- a/src/app/browser.rs +++ b/src/app/browser.rs @@ -24,7 +24,7 @@ pub struct Browser { database: Arc, // Components // header: Arc
, - // window: Arc, + window: Arc, widget: Arc, } @@ -88,6 +88,7 @@ impl Browser { )); let window = Arc::new(Window::new( + profile_database_connection.clone(), action_tab_page_navigation_base.clone(), action_tab_page_navigation_history_back.clone(), action_tab_page_navigation_history_forward.clone(), @@ -221,7 +222,7 @@ impl Browser { database, widget, // header, - // window, + window, } } @@ -235,8 +236,7 @@ impl Browser { // Delegate clean action to childs // @TODO // self.header.clean(record.id); - // self.window.clean(record.id); - + self.window.clean(tx, &record.id); self.widget.clean(tx, &record.id); } Err(e) => todo!("{e}"), @@ -254,8 +254,7 @@ impl Browser { // Delegate restore action to childs // @TODO // self.header.restore(record.id); - // self.window.restore(record.id); - + self.window.restore(tx, &record.id); self.widget.restore(tx, &record.id); } } @@ -271,8 +270,7 @@ impl Browser { // @TODO // self.header.save(id); - // self.window.save(id); - + self.window.save(tx, &id); self.widget.save(tx, &id); } Err(e) => todo!("{e}"), diff --git a/src/app/browser/window.rs b/src/app/browser/window.rs index 3abd73cd..ddbd7dfa 100644 --- a/src/app/browser/window.rs +++ b/src/app/browser/window.rs @@ -1,14 +1,18 @@ +mod database; mod tab; mod widget; +use database::Database; +use sqlite::{Connection, Transaction}; use tab::Tab; use widget::Widget; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use gtk::{gio::SimpleAction, glib::GString, Box}; pub struct Window { + database: Arc, tab: Arc, widget: Arc, } @@ -16,14 +20,42 @@ pub struct Window { impl Window { // Construct pub fn new( + // Extras + profile_database_connection: Arc>, + // Actions action_tab_page_navigation_base: Arc, action_tab_page_navigation_history_back: Arc, action_tab_page_navigation_history_forward: Arc, action_tab_page_navigation_reload: Arc, action_update: Arc, ) -> Self { + // Init database + let database = { + // Init writable database connection + let mut connection = match profile_database_connection.write() { + Ok(connection) => connection, + Err(e) => todo!("{e}"), + }; + + // Init new transaction + let transaction = match connection.transaction() { + Ok(transaction) => transaction, + Err(e) => todo!("{e}"), + }; + + // Init database structure + match Database::init(&transaction) { + Ok(database) => match transaction.commit() { + Ok(_) => Arc::new(database), + Err(e) => todo!("{e}"), + }, + Err(e) => todo!("{e}"), + } + }; + // Init components let tab = Arc::new(Tab::new( + profile_database_connection, action_tab_page_navigation_base, action_tab_page_navigation_history_back, action_tab_page_navigation_history_forward, @@ -37,7 +69,11 @@ impl Window { let widget = Arc::new(Widget::new(tab.gobject())); // Init struct - Self { tab, widget } + Self { + database, + tab, + widget, + } } // Actions @@ -77,6 +113,58 @@ impl Window { self.tab.update(); } + pub fn clean(&self, tx: &Transaction, app_browser_id: &i64) { + match self.database.records(tx, app_browser_id) { + Ok(records) => { + for record in records { + match self.database.delete(tx, &record.id) { + Ok(_) => { + // Delegate clean action to childs + // @TODO + self.tab.clean(tx, &record.id); + + // self.widget.clean(tx, &record.id); + } + Err(e) => todo!("{e}"), + } + } + } + Err(e) => todo!("{e}"), + } + } + + pub fn restore(&self, tx: &Transaction, app_browser_id: &i64) { + match self.database.records(tx, app_browser_id) { + Ok(records) => { + for record in records { + // Delegate restore action to childs + // @TODO + // self.header.restore(record.id); + // self.window.restore(record.id); + + // self.widget.restore(tx, &record.id); + } + } + Err(e) => todo!("{e}"), + } + } + + pub fn save(&self, tx: &Transaction, app_browser_id: &i64) { + match self.database.add(tx, app_browser_id) { + Ok(_) => { + // Delegate save action to childs + let id = self.database.last_insert_id(tx); + + // @TODO + // self.header.save(id); + // self.window.save(id); + + // self.widget.save(tx, &id); + } + Err(e) => todo!("{e}"), + } + } + // Getters pub fn tab_page_title(&self) -> Option { self.tab.page_title() diff --git a/src/app/browser/window/database.rs b/src/app/browser/window/database.rs new file mode 100644 index 00000000..141fe6a5 --- /dev/null +++ b/src/app/browser/window/database.rs @@ -0,0 +1,64 @@ +use sqlite::{Error, Transaction}; + +pub struct Table { + pub id: i64, + // pub app_browser_id: i64, not in use +} + +pub struct Database { + // nothing yet.. +} + +impl Database { + pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `app_browser_window` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `app_browser_id` INTEGER NOT NULL + )", + [], + )?; + + Ok(Self {}) + } + + pub fn add(&self, tx: &Transaction, app_browser_id: &i64) -> Result { + tx.execute( + "INSERT INTO `app_browser_window` (`app_browser_id`) VALUES (?)", + [app_browser_id], + ) + } + + pub fn records(&self, tx: &Transaction, app_browser_id: &i64) -> Result, Error> { + let mut stmt = tx.prepare( + "SELECT `id`, + `app_browser_id` FROM `app_browser_window` + WHERE `app_browser_id` = ?", + )?; + + let result = stmt.query_map([app_browser_id], |row| { + Ok(Table { + id: row.get(0)?, + // app_browser_id: row.get(1)?, not in use + }) + })?; + + let mut records = Vec::new(); + + for record in result { + let table = record?; + records.push(table); + } + + Ok(records) + } + + pub fn delete(&self, tx: &Transaction, id: &i64) -> Result { + tx.execute("DELETE FROM `app_browser_window` WHERE `id` = ?", [id]) + } + + pub fn last_insert_id(&self, tx: &Transaction) -> i64 { + tx.last_insert_rowid() + } +} diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index b8fde11b..987791e8 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -1,9 +1,12 @@ +mod database; mod label; mod page; mod widget; +use database::Database; use label::Label; use page::Page; +use sqlite::{Connection, Transaction}; use widget::Widget; use gtk::{ @@ -13,7 +16,11 @@ use gtk::{ GestureClick, Notebook, }; -use std::{cell::RefCell, collections::HashMap, sync::Arc}; +use std::{ + cell::RefCell, + collections::HashMap, + sync::{Arc, RwLock}, +}; // Common struct for HashMap index struct TabItem { @@ -23,7 +30,9 @@ struct TabItem { // Main pub struct Tab { - // Keep action links in memory to not require them on every tab append + // Extras + database: Arc, + // Actions action_tab_page_navigation_base: Arc, action_tab_page_navigation_history_back: Arc, action_tab_page_navigation_history_forward: Arc, @@ -38,14 +47,42 @@ pub struct Tab { impl Tab { // Construct pub fn new( + // Extras + profile_database_connection: Arc>, + // Actions action_tab_page_navigation_base: Arc, action_tab_page_navigation_history_back: Arc, action_tab_page_navigation_history_forward: Arc, action_tab_page_navigation_reload: Arc, action_update: Arc, ) -> Self { + // Init database + let database = { + // Init writable database connection + let mut connection = match profile_database_connection.write() { + Ok(connection) => connection, + Err(e) => todo!("{e}"), + }; + + // Init new transaction + let transaction = match connection.transaction() { + Ok(transaction) => transaction, + Err(e) => todo!("{e}"), + }; + + // Init database structure + match Database::init(&transaction) { + Ok(database) => match transaction.commit() { + Ok(_) => Arc::new(database), + Err(e) => todo!("{e}"), + }, + Err(e) => todo!("{e}"), + } + }; + // Return non activated struct Self { + database, // Define action links action_tab_page_navigation_base, action_tab_page_navigation_history_back, @@ -196,6 +233,46 @@ impl Tab { } } + pub fn clean(&self, tx: &Transaction, app_browser_window_id: &i64) { + match self.database.records(tx, app_browser_window_id) { + Ok(records) => { + for record in records { + match self.database.delete(tx, &record.id) { + Ok(_) => { + // Delegate clean action to childs + // nothing yet.. + } + Err(e) => todo!("{e}"), + } + } + } + Err(e) => todo!("{e}"), + } + } + + pub fn restore(&self, tx: &Transaction, app_browser_window_id: &i64) { + match self.database.records(tx, app_browser_window_id) { + Ok(records) => { + for record in records { + // Delegate restore action to childs + // nothing yet.. + } + } + Err(e) => todo!("{e}"), + } + } + + pub fn save(&self, tx: &Transaction, app_browser_window_id: &i64) { + match self.database.add(tx, app_browser_window_id) { + Ok(_) => { + // Delegate save action to childs + // let id = self.database.last_insert_id(tx); + // nothing yet.. + } + Err(e) => todo!("{e}"), + } + } + // Getters pub fn page_title(&self) -> Option { if let Some(id) = self.widget.current_name() { @@ -203,7 +280,6 @@ impl Tab { return item.page.title(); } } - None } @@ -214,7 +290,6 @@ impl Tab { return item.page.description(); } } - None } diff --git a/src/app/browser/window/tab/database.rs b/src/app/browser/window/tab/database.rs new file mode 100644 index 00000000..b2c70f4e --- /dev/null +++ b/src/app/browser/window/tab/database.rs @@ -0,0 +1,66 @@ +use sqlite::{Error, Transaction}; + +pub struct Table { + pub id: i64, + // pub app_browser_window_id: i64, not in use +} + +pub struct Database { + // nothing yet.. +} + +impl Database { + pub fn init(tx: &Transaction) -> Result { + tx.execute( + "CREATE TABLE IF NOT EXISTS `app_browser_window_tab` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `app_browser_window_id` INTEGER NOT NULL + )", + [], + )?; + + Ok(Self {}) + } + + pub fn add(&self, tx: &Transaction, app_browser_window_id: &i64) -> Result { + tx.execute( + "INSERT INTO `app_browser_window_tab` (`app_browser_window_id`) VALUES (?)", + [app_browser_window_id], + ) + } + + pub fn records( + &self, + tx: &Transaction, + app_browser_window_id: &i64, + ) -> Result, Error> { + let mut stmt = tx.prepare("SELECT `id`, + `app_browser_window_id` FROM `app_browser_window_tab` + WHERE `app_browser_window_id` = ?")?; + + let result = stmt.query_map([app_browser_window_id], |row| { + Ok(Table { + id: row.get(0)?, + // app_browser_window_id: row.get(1)?, not in use + }) + })?; + + let mut records = Vec::new(); + + for record in result { + let table = record?; + records.push(table); + } + + Ok(records) + } + + pub fn delete(&self, tx: &Transaction, id: &i64) -> Result { + tx.execute("DELETE FROM `app_browser_window_tab` WHERE `id` = ?", [id]) + } + + pub fn last_insert_id(&self, tx: &Transaction) -> i64 { + tx.last_insert_rowid() + } +}