From 42b7d422a8ad16d2393a86bee2ead2fa7b3662fa Mon Sep 17 00:00:00 2001 From: Julian Mutter Date: Sun, 11 Feb 2024 09:35:32 +0100 Subject: [PATCH] Remove BookSheet and make it normal Sheet Simplifies code a lot --- db-migrations/0_creation.sql | 5 +-- src/main.rs | 8 ++-- src/sheet.rs | 83 +++++++----------------------------- src/sheet_dao.rs | 52 ++++++++++------------ src/ui/app.rs | 4 +- src/ui/sheet_model.rs | 9 ++-- 6 files changed, 48 insertions(+), 113 deletions(-) diff --git a/db-migrations/0_creation.sql b/db-migrations/0_creation.sql index 4e8bc6e..de61cc5 100644 --- a/db-migrations/0_creation.sql +++ b/db-migrations/0_creation.sql @@ -1,11 +1,8 @@ CREATE TABLE IF NOT EXISTS sheets (id INTEGER PRIMARY KEY AUTOINCREMENT, - last_opened INTEGER, name TEXT, composer_id INTEGER, path TEXT, file_size INTEGER, file_hash TEXT); + last_opened INTEGER, name TEXT, composer_id INTEGER, first_page INTEGER, book_id INTEGER, path TEXT, file_size INTEGER, file_hash TEXT); CREATE TABLE IF NOT EXISTS orphans (id INTEGER PRIMARY KEY AUTOINCREMENT, last_opened INTEGER, path TEXT, file_size INTEGER, file_hash TEXT); CREATE TABLE IF NOT EXISTS books (id INTEGER PRIMARY KEY AUTOINCREMENT, last_opened INTEGER, name TEXT, composer_id INTEGER, sheet_ids TEXT, path TEXT, file_size INTEGER, file_hash TEXT); -CREATE TABLE IF NOT EXISTS booksheets (id INTEGER PRIMARY KEY AUTOINCREMENT, - last_opened INTEGER, name TEXT, book_id INTEGER, first_page INTEGER, last_page INTEGER); - CREATE TABLE IF NOT EXISTS composers (id INTEGER primary key autoincrement, name TEXT); diff --git a/src/main.rs b/src/main.rs index 972da14..f31f9d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,7 +85,7 @@ impl FileValidationResult { fn validate_sheet_files(sheets: Vec, dir: impl AsRef) -> FileValidationResult { let (validated_sheets, mut invalidated_sheets): (Vec<_>, Vec<_>) = sheets .into_iter() - .partition(|sheet| sheet.validate_own_path().unwrap_or(false)); + .partition(|sheet| sheet.pdf.validate_own_path().unwrap_or(false)); let mut updated_sheets = Vec::new(); let mut unassigned_files = Vec::new(); @@ -95,15 +95,15 @@ fn validate_sheet_files(sheets: Vec, dir: impl AsRef) -> FileValida if let Some((i, _)) = invalidated_sheets .iter() .enumerate() - .find(|(_, sheet)| sheet.validate_path(&pdf_file).unwrap_or(false)) + .find(|(_, sheet)| sheet.pdf.validate_path(&pdf_file).unwrap_or(false)) { let mut sheet = invalidated_sheets.remove(i); let new_pdf = Pdf::try_from(pdf_file).unwrap(); - sheet.update_pdf_file(new_pdf); + sheet.pdf = new_pdf; updated_sheets.push(sheet); } else if !validated_sheets .iter() - .any(|sheet| sheet.pdf_path_equal(&pdf_file)) + .any(|sheet| sheet.pdf.path == pdf_file) { unassigned_files.push(pdf_file); } diff --git a/src/sheet.rs b/src/sheet.rs index 9f92a3b..be62852 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -1,16 +1,12 @@ use std::{ cmp::Ordering, - ffi::{OsStr, OsString}, fs, path::{Path, PathBuf}, }; use chrono::{DateTime, NaiveDateTime, Utc}; -use sqlx::database; use strum_macros::{EnumDiscriminants, EnumIter}; -use crate::{database::Database, sheet_dao}; - pub trait PdfSheet { fn get_pdf(&self) -> &Pdf; } @@ -20,31 +16,24 @@ pub struct Sheet { pub id: i64, pub last_opened: I64DateTime, pub kind: SheetKind, + pub pdf: Pdf, } #[derive(Debug, Clone, PartialEq, Eq, EnumDiscriminants)] #[strum_discriminants(derive(EnumIter))] pub enum SheetKind { Sheet { - pdf: Pdf, name: String, composer_id: i64, + first_page: i64, + book_id: Option, }, - Orphan { - pdf: Pdf, - }, + Orphan, Book { - pdf: Pdf, name: String, composer_id: i64, sheet_ids: Vec, }, - BookSheet { - name: String, - book_id: i64, - first_page: i64, - last_page: i64, - }, } impl PartialOrd for Sheet { @@ -60,62 +49,17 @@ impl Ord for Sheet { } impl Sheet { - pub async fn open_file(&self, database: &Database) { - let path = match &self.kind { - SheetKind::Sheet { pdf, .. } => pdf.path.clone(), - SheetKind::Orphan { pdf } => pdf.path.clone(), - SheetKind::Book { pdf, .. } => pdf.path.clone(), - SheetKind::BookSheet { book_id, .. } => sheet_dao::find_path_of_book(database, book_id) - .await - .unwrap(), - }; + pub fn open_file(&self) { + let path = &self.pdf.path; + // TODO: open on first_page opener::open(path).unwrap(); } - pub fn update_pdf_file(&mut self, new_pdf: Pdf) -> std::io::Result<()> { - match &mut self.kind { - SheetKind::Sheet { pdf, .. } => *pdf = new_pdf, - SheetKind::Orphan { pdf, .. } => *pdf = new_pdf, - SheetKind::Book { pdf, .. } => *pdf = new_pdf, - SheetKind::BookSheet { .. } => {} // TODO: find better solution! - }; - Ok(()) - } - - pub fn pdf_path_equal(&self, path: impl AsRef) -> bool { - match &self.kind { - SheetKind::Sheet { pdf, .. } => pdf.path == path.as_ref(), - SheetKind::Orphan { pdf, .. } => pdf.path == path.as_ref(), - SheetKind::Book { pdf, .. } => pdf.path == path.as_ref(), - SheetKind::BookSheet { .. } => false, // TODO: find better solution! + pub fn is_part_of_book(&self) -> bool { + if let SheetKind::Sheet { book_id, .. } = &self.kind { + return book_id.is_some(); } - } - - pub fn validate_own_path(&self) -> std::io::Result { - Ok(match &self.kind { - SheetKind::Sheet { pdf, .. } => pdf.validate_path(&pdf.path)?, - SheetKind::Orphan { pdf, .. } => pdf.validate_path(&pdf.path)?, - SheetKind::Book { pdf, .. } => pdf.validate_path(&pdf.path)?, - SheetKind::BookSheet { book_id, .. } => true, // TODO: better solution? - }) - } - - pub fn try_get_path(&self) -> Option<&Path> { - match &self.kind { - SheetKind::Sheet { pdf, .. } => Some(&pdf.path), - SheetKind::Orphan { pdf, .. } => Some(&pdf.path), - SheetKind::Book { pdf, .. } => Some(&pdf.path), - SheetKind::BookSheet { .. } => None, - } - } - - pub fn validate_path(&self, path: impl AsRef) -> std::io::Result { - Ok(match &self.kind { - SheetKind::Sheet { pdf, .. } => pdf.validate_path(path)?, - SheetKind::Orphan { pdf, .. } => pdf.validate_path(path)?, - SheetKind::Book { pdf, .. } => pdf.validate_path(path)?, - SheetKind::BookSheet { book_id, .. } => true, // TODO: better solution? - }) + false } } @@ -125,7 +69,6 @@ impl SheetKindDiscriminants { SheetKindDiscriminants::Sheet => "sheets", SheetKindDiscriminants::Orphan => "orphans", SheetKindDiscriminants::Book => "books", - SheetKindDiscriminants::BookSheet => "booksheets", } } } @@ -169,6 +112,10 @@ impl Pdf { self.path.file_name().unwrap().to_str().unwrap() } + pub fn validate_own_path(&self) -> std::io::Result { + self.validate_path(&self.path) + } + pub fn validate_path(&self, path: impl AsRef) -> std::io::Result { // First compare file size since it is faster than hashing let file_size = fs::metadata(path.as_ref())?.len(); diff --git a/src/sheet_dao.rs b/src/sheet_dao.rs index 064a455..7b5409b 100644 --- a/src/sheet_dao.rs +++ b/src/sheet_dao.rs @@ -35,31 +35,30 @@ pub async fn insert_file_as_orphan( Ok(Sheet { id, + pdf, last_opened: I64DateTime(last_opened), - kind: SheetKind::Orphan { pdf }, + kind: SheetKind::Orphan, }) } -pub async fn find_path_of_book(database: &Database, book_id: &i64) -> sqlx::Result { - sqlx::query("SELECT path FROM books WHERE id = $1") - .bind(book_id) - .map(|row: SqliteRow| PathBuf::try_from(row.try_get::("path").unwrap()).unwrap()) - .fetch_one(&database.connection) - .await -} +// pub async fn find_path_of_book(database: &Database, book_id: &i64) -> sqlx::Result { +// sqlx::query("SELECT path FROM books WHERE id = $1") +// .bind(book_id) +// .map(|row: SqliteRow| PathBuf::try_from(row.try_get::("path").unwrap()).unwrap()) +// .fetch_one(&database.connection) +// .await +// } pub async fn update_sheet_path(database: &Database, sheet: &Sheet) -> sqlx::Result<()> { - if let Some(path) = sheet.try_get_path() { - let sheet_kind = SheetKindDiscriminants::from(&sheet.kind); - let table = sheet_kind.get_database_table_name(); - return sqlx::query(&format!("UPDATE {} SET path = $1 WHERE id = $2", table)) - .bind(path.to_str().unwrap().to_string()) - .bind(sheet.id) - .execute(&database.connection) - .await - .map(|_| ()); - } - Ok(()) // TODO: error on else? + // TODO: when updating book or sheet of book, update all + let sheet_kind = SheetKindDiscriminants::from(&sheet.kind); + let table = sheet_kind.get_database_table_name(); + return sqlx::query(&format!("UPDATE {} SET path = $1 WHERE id = $2", table)) + .bind(sheet.pdf.path.to_str().unwrap().to_string()) + .bind(sheet.id) + .execute(&database.connection) + .await + .map(|_| ()); } pub async fn update_sheet_last_opened(database: &Database, sheet: &Sheet) -> sqlx::Result<()> { @@ -87,6 +86,7 @@ pub async fn fetch_all_sheets(database: &Database) -> sqlx::Result> { id: row.try_get("id").unwrap(), last_opened: I64DateTime::try_from(row.try_get::("last_opened").unwrap()) .unwrap(), + pdf: parse_pdf_from_row(&row).unwrap(), kind: parse_kind_from_row(kind, row).unwrap(), }) .fetch_all(&database.connection) @@ -103,23 +103,15 @@ fn parse_kind_from_row(kind: SheetKindDiscriminants, row: SqliteRow) -> sqlx::Re SheetKindDiscriminants::Sheet => SheetKind::Sheet { name: row.try_get("name")?, composer_id: row.try_get("composer_id")?, - pdf: parse_pdf_from_row(&row)?, - }, - SheetKindDiscriminants::Orphan => SheetKind::Orphan { - pdf: parse_pdf_from_row(&row)?, + first_page: row.try_get("first_page")?, + book_id: row.try_get("book_id").ok(), }, + SheetKindDiscriminants::Orphan => SheetKind::Orphan, SheetKindDiscriminants::Book => SheetKind::Book { name: row.try_get("name")?, composer_id: row.try_get("composer_id")?, - pdf: parse_pdf_from_row(&row)?, sheet_ids: sheet_ids_from_string(row.try_get("sheet_ids").unwrap()), }, - SheetKindDiscriminants::BookSheet => SheetKind::BookSheet { - name: row.try_get("name")?, - book_id: row.try_get("book_id")?, - first_page: row.try_get("first_page")?, - last_page: row.try_get("last_page")?, - }, }) } diff --git a/src/ui/app.rs b/src/ui/app.rs index ec48322..9d07e9c 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -112,8 +112,8 @@ impl AsyncComponent for AppModel { .emit(SheetListingInput::Query(query.clone())); } AppInput::SheetPressed(sheet) => { - sheet.open_file(&self.database).await; - // TODO: updating does not work + sheet.open_file(); + // TODO: updating directly does not work let mut sheet = sheet; sheet.last_opened = I64DateTime(Utc::now()); sheet_dao::update_sheet_last_opened(&self.database, &sheet) diff --git a/src/ui/sheet_model.rs b/src/ui/sheet_model.rs index c616567..3c29127 100644 --- a/src/ui/sheet_model.rs +++ b/src/ui/sheet_model.rs @@ -46,17 +46,16 @@ impl FactoryComponent for SheetModel { } } - fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender) -> Self { - let label = match &value.kind { + fn init_model(sheet: Self::Init, _index: &DynamicIndex, _sender: FactorySender) -> Self { + let label = match &sheet.kind { crate::sheet::SheetKind::Sheet { name, .. } => name, - crate::sheet::SheetKind::Orphan { pdf } => pdf.get_name(), + crate::sheet::SheetKind::Orphan {} => sheet.pdf.get_name(), crate::sheet::SheetKind::Book { name, .. } => name, - crate::sheet::SheetKind::BookSheet { name, .. } => name, }; SheetModel { label: label.to_string(), - sheet: value, + sheet, visible: true, } }