move profile components to separated namespace

This commit is contained in:
yggverse 2024-11-13 03:40:29 +02:00
parent 61010e0a42
commit b12f5e8b8f
13 changed files with 332 additions and 214 deletions

View File

@ -21,10 +21,7 @@ pub struct App {
impl App { impl App {
// Construct // Construct
pub fn new() -> Self { pub fn new(profile: Rc<Profile>) -> Self {
// Init profile
let profile = Rc::new(Profile::new());
// Init GTK // Init GTK
let gobject = Application::builder() let gobject = Application::builder()
.application_id(APPLICATION_ID) .application_id(APPLICATION_ID)
@ -44,7 +41,7 @@ impl App {
let profile = profile.clone(); let profile = profile.clone();
move |this| { move |this| {
// Init readable connection // Init readable connection
match profile.database().connection().read() { match profile.database().read() {
Ok(connection) => { Ok(connection) => {
// Create transaction // Create transaction
match connection.unchecked_transaction() { match connection.unchecked_transaction() {
@ -86,7 +83,7 @@ impl App {
let profile = profile.clone(); let profile = profile.clone();
move |_| { move |_| {
// Init writable connection // Init writable connection
match profile.database().connection().write() { match profile.database().write() {
Ok(mut connection) => { Ok(mut connection) => {
// Create transaction // Create transaction
match connection.transaction() { match connection.transaction() {
@ -243,7 +240,7 @@ impl App {
// Begin database migration @TODO // Begin database migration @TODO
{ {
// Init writable connection // 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, Ok(connection) => connection,
Err(e) => todo!("{e}"), Err(e) => todo!("{e}"),
}; };

View File

@ -2,11 +2,14 @@ mod app;
mod profile; mod profile;
use app::App; use app::App;
use profile::Profile;
use gtk::glib::ExitCode; use gtk::glib::ExitCode;
use std::rc::Rc;
fn main() -> ExitCode { fn main() -> ExitCode {
match gtk::init() { match gtk::init() {
Ok(_) => App::new().run(), Ok(_) => App::new(Rc::new(Profile::new())).run(),
Err(_) => ExitCode::FAILURE, Err(_) => ExitCode::FAILURE,
} }
} }

View File

@ -1,10 +1,15 @@
mod bookmark;
mod database; mod database;
use database::Database; mod history;
mod identity;
use gtk::glib::user_config_dir; use gtk::glib::user_config_dir;
use sqlite::{Connection, Transaction};
use std::{ use std::{
fs::create_dir_all, fs::create_dir_all,
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc,
sync::RwLock,
}; };
const VENDOR: &str = "YGGverse"; const VENDOR: &str = "YGGverse";
@ -14,7 +19,7 @@ const BRANCH: &str = "master";
const DB_NAME: &str = "profile.sqlite3"; const DB_NAME: &str = "profile.sqlite3";
pub struct Profile { pub struct Profile {
database: Database, database: Rc<RwLock<Connection>>,
config_path: PathBuf, config_path: PathBuf,
} }
@ -42,16 +47,49 @@ impl Profile {
let mut database_path = config_path.clone(); let mut database_path = config_path.clone();
database_path.push(DB_NAME); 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 // Result
Self { Self {
database: Database::new(database_path.as_path()), database: connection,
config_path, config_path,
} }
} }
// Getters // Getters
pub fn database(&self) -> &Database { pub fn database(&self) -> &Rc<RwLock<Connection>> {
&self.database &self.database
} }
@ -59,3 +97,18 @@ impl Profile {
self.config_path.as_path() 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(())
}

18
src/profile/bookmark.rs Normal file
View File

@ -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(())
}

View File

@ -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<usize, Error> {
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<usize, Error> {
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<Vec<Table>, 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<usize, Error> {
tx.execute("DELETE FROM `profile_bookmark` WHERE `id` = ?", [id])
}

View File

@ -1,63 +1,41 @@
mod bookmark; use sqlite::{Error, Transaction};
mod history;
mod identity;
use sqlite::{Connection, Error}; pub struct Table {
use std::{ pub id: i64,
path::Path,
rc::Rc,
sync::{RwLock, RwLockWriteGuard},
};
pub struct Database {
connection: Rc<RwLock<Connection>>,
} }
impl Database { pub fn init(tx: &Transaction) -> Result<usize, Error> {
// Constructors tx.execute(
"CREATE TABLE IF NOT EXISTS `profile`
(
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
)",
[],
)
}
/// Create new connected `Self` pub fn add(tx: &Transaction) -> Result<usize, Error> {
pub fn new(path: &Path) -> Self { tx.execute("INSERT INTO `profile` DEFAULT VALUES", [])
// Init database connection }
let connection = match Connection::open(path) {
Ok(connection) => Rc::new(RwLock::new(connection)),
Err(reason) => panic!("{reason}"),
};
// Init profile components pub fn records(tx: &Transaction) -> Result<Vec<Table>, Error> {
match connection.write() { let mut stmt = tx.prepare("SELECT `profile_id` FROM `profile`")?;
Ok(writable) => { let result = stmt.query_map([], |row| Ok(Table { id: row.get(0)? }))?;
if let Err(reason) = init(writable) {
panic!("{reason}")
}
}
Err(reason) => panic!("{reason}"),
};
// Result let mut records = Vec::new();
Self { connection }
for record in result {
let table = record?;
records.push(table);
} }
// Getters Ok(records)
pub fn connection(&self) -> &Rc<RwLock<Connection>> {
&self.connection
}
} }
// Tools pub fn delete(tx: &Transaction, id: &i64) -> Result<usize, Error> {
tx.execute("DELETE FROM `profile` WHERE `id` = ?", [id])
fn init(mut connection: RwLockWriteGuard<'_, Connection>) -> Result<(), Error> { }
// Begin transaction
let transaction = connection.transaction()?; pub fn last_insert_id(tx: &Transaction) -> i64 {
tx.last_insert_rowid()
// Init profile components
bookmark::init(&transaction)?;
history::init(&transaction)?;
identity::init(&transaction)?;
// Apply changes
transaction.commit()?;
Ok(())
} }

View File

@ -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<usize, Error> {
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<usize, Error> {
tx.execute(
"INSERT INTO `bookmark` (
`time`,
`request`
) VALUES (?, ?)",
(time.to_unix(), request),
)
}
pub fn records(tx: &Transaction, request: Option<&str>) -> Result<Vec<Table>, 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<usize, Error> {
tx.execute("DELETE FROM `bookmark` WHERE `id` = ?", [id])
}

View File

@ -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<usize, Error> {
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<usize, Error> {
tx.execute(
"INSERT INTO `history` (
`time`,
`request`
) VALUES (?, ?)",
(time.to_unix(), request),
)
}
pub fn records(tx: &Transaction, request: Option<&str>) -> Result<Vec<Table>, 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<usize, Error> {
tx.execute("DELETE FROM `history` WHERE `id` = ?", [id])
}

View File

@ -1,20 +0,0 @@
use sqlite::{Error, Transaction};
pub struct Table {
pub id: i64,
// pub app_id: i64,
}
pub fn init(tx: &Transaction) -> Result<usize, Error> {
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
)",
[],
)
}

18
src/profile/history.rs Normal file
View File

@ -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(())
}

View File

@ -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<usize, Error> {
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<usize, Error> {
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<Vec<Table>, 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<usize, Error> {
tx.execute("DELETE FROM `profile_history` WHERE `id` = ?", [id])
}

18
src/profile/identity.rs Normal file
View File

@ -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(())
}

View File

@ -0,0 +1,21 @@
use sqlite::{Error, Transaction};
pub struct Table {
pub id: i64,
//pub profile_id: i64,
}
pub fn init(tx: &Transaction) -> Result<usize, Error> {
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
)",
[],
)
}