Remove BookSheet and make it normal Sheet
Simplifies code a lot
This commit is contained in:
parent
d3f2375995
commit
42b7d422a8
@ -1,11 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS sheets (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
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,
|
CREATE TABLE IF NOT EXISTS orphans (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
last_opened INTEGER, path TEXT, file_size INTEGER, file_hash TEXT);
|
last_opened INTEGER, path TEXT, file_size INTEGER, file_hash TEXT);
|
||||||
CREATE TABLE IF NOT EXISTS books (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
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);
|
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);
|
CREATE TABLE IF NOT EXISTS composers (id INTEGER primary key autoincrement, name TEXT);
|
||||||
|
@ -85,7 +85,7 @@ impl FileValidationResult {
|
|||||||
fn validate_sheet_files(sheets: Vec<Sheet>, dir: impl AsRef<Path>) -> FileValidationResult {
|
fn validate_sheet_files(sheets: Vec<Sheet>, dir: impl AsRef<Path>) -> FileValidationResult {
|
||||||
let (validated_sheets, mut invalidated_sheets): (Vec<_>, Vec<_>) = sheets
|
let (validated_sheets, mut invalidated_sheets): (Vec<_>, Vec<_>) = sheets
|
||||||
.into_iter()
|
.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 updated_sheets = Vec::new();
|
||||||
let mut unassigned_files = Vec::new();
|
let mut unassigned_files = Vec::new();
|
||||||
@ -95,15 +95,15 @@ fn validate_sheet_files(sheets: Vec<Sheet>, dir: impl AsRef<Path>) -> FileValida
|
|||||||
if let Some((i, _)) = invalidated_sheets
|
if let Some((i, _)) = invalidated_sheets
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.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 mut sheet = invalidated_sheets.remove(i);
|
||||||
let new_pdf = Pdf::try_from(pdf_file).unwrap();
|
let new_pdf = Pdf::try_from(pdf_file).unwrap();
|
||||||
sheet.update_pdf_file(new_pdf);
|
sheet.pdf = new_pdf;
|
||||||
updated_sheets.push(sheet);
|
updated_sheets.push(sheet);
|
||||||
} else if !validated_sheets
|
} else if !validated_sheets
|
||||||
.iter()
|
.iter()
|
||||||
.any(|sheet| sheet.pdf_path_equal(&pdf_file))
|
.any(|sheet| sheet.pdf.path == pdf_file)
|
||||||
{
|
{
|
||||||
unassigned_files.push(pdf_file);
|
unassigned_files.push(pdf_file);
|
||||||
}
|
}
|
||||||
|
83
src/sheet.rs
83
src/sheet.rs
@ -1,16 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
ffi::{OsStr, OsString},
|
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use sqlx::database;
|
|
||||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||||
|
|
||||||
use crate::{database::Database, sheet_dao};
|
|
||||||
|
|
||||||
pub trait PdfSheet {
|
pub trait PdfSheet {
|
||||||
fn get_pdf(&self) -> &Pdf;
|
fn get_pdf(&self) -> &Pdf;
|
||||||
}
|
}
|
||||||
@ -20,31 +16,24 @@ pub struct Sheet {
|
|||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub last_opened: I64DateTime,
|
pub last_opened: I64DateTime,
|
||||||
pub kind: SheetKind,
|
pub kind: SheetKind,
|
||||||
|
pub pdf: Pdf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, EnumDiscriminants)]
|
#[derive(Debug, Clone, PartialEq, Eq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(derive(EnumIter))]
|
#[strum_discriminants(derive(EnumIter))]
|
||||||
pub enum SheetKind {
|
pub enum SheetKind {
|
||||||
Sheet {
|
Sheet {
|
||||||
pdf: Pdf,
|
|
||||||
name: String,
|
name: String,
|
||||||
composer_id: i64,
|
composer_id: i64,
|
||||||
|
first_page: i64,
|
||||||
|
book_id: Option<i64>,
|
||||||
},
|
},
|
||||||
Orphan {
|
Orphan,
|
||||||
pdf: Pdf,
|
|
||||||
},
|
|
||||||
Book {
|
Book {
|
||||||
pdf: Pdf,
|
|
||||||
name: String,
|
name: String,
|
||||||
composer_id: i64,
|
composer_id: i64,
|
||||||
sheet_ids: Vec<i64>,
|
sheet_ids: Vec<i64>,
|
||||||
},
|
},
|
||||||
BookSheet {
|
|
||||||
name: String,
|
|
||||||
book_id: i64,
|
|
||||||
first_page: i64,
|
|
||||||
last_page: i64,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Sheet {
|
impl PartialOrd for Sheet {
|
||||||
@ -60,62 +49,17 @@ impl Ord for Sheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sheet {
|
impl Sheet {
|
||||||
pub async fn open_file(&self, database: &Database) {
|
pub fn open_file(&self) {
|
||||||
let path = match &self.kind {
|
let path = &self.pdf.path;
|
||||||
SheetKind::Sheet { pdf, .. } => pdf.path.clone(),
|
// TODO: open on first_page
|
||||||
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(),
|
|
||||||
};
|
|
||||||
opener::open(path).unwrap();
|
opener::open(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_pdf_file(&mut self, new_pdf: Pdf) -> std::io::Result<()> {
|
pub fn is_part_of_book(&self) -> bool {
|
||||||
match &mut self.kind {
|
if let SheetKind::Sheet { book_id, .. } = &self.kind {
|
||||||
SheetKind::Sheet { pdf, .. } => *pdf = new_pdf,
|
return book_id.is_some();
|
||||||
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<Path>) -> 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!
|
|
||||||
}
|
}
|
||||||
}
|
false
|
||||||
|
|
||||||
pub fn validate_own_path(&self) -> std::io::Result<bool> {
|
|
||||||
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<Path>) -> std::io::Result<bool> {
|
|
||||||
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?
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +69,6 @@ impl SheetKindDiscriminants {
|
|||||||
SheetKindDiscriminants::Sheet => "sheets",
|
SheetKindDiscriminants::Sheet => "sheets",
|
||||||
SheetKindDiscriminants::Orphan => "orphans",
|
SheetKindDiscriminants::Orphan => "orphans",
|
||||||
SheetKindDiscriminants::Book => "books",
|
SheetKindDiscriminants::Book => "books",
|
||||||
SheetKindDiscriminants::BookSheet => "booksheets",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,6 +112,10 @@ impl Pdf {
|
|||||||
self.path.file_name().unwrap().to_str().unwrap()
|
self.path.file_name().unwrap().to_str().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate_own_path(&self) -> std::io::Result<bool> {
|
||||||
|
self.validate_path(&self.path)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate_path(&self, path: impl AsRef<Path>) -> std::io::Result<bool> {
|
pub fn validate_path(&self, path: impl AsRef<Path>) -> std::io::Result<bool> {
|
||||||
// First compare file size since it is faster than hashing
|
// First compare file size since it is faster than hashing
|
||||||
let file_size = fs::metadata(path.as_ref())?.len();
|
let file_size = fs::metadata(path.as_ref())?.len();
|
||||||
|
@ -35,31 +35,30 @@ pub async fn insert_file_as_orphan(
|
|||||||
|
|
||||||
Ok(Sheet {
|
Ok(Sheet {
|
||||||
id,
|
id,
|
||||||
|
pdf,
|
||||||
last_opened: I64DateTime(last_opened),
|
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<PathBuf> {
|
// pub async fn find_path_of_book(database: &Database, book_id: &i64) -> sqlx::Result<PathBuf> {
|
||||||
sqlx::query("SELECT path FROM books WHERE id = $1")
|
// sqlx::query("SELECT path FROM books WHERE id = $1")
|
||||||
.bind(book_id)
|
// .bind(book_id)
|
||||||
.map(|row: SqliteRow| PathBuf::try_from(row.try_get::<String, _>("path").unwrap()).unwrap())
|
// .map(|row: SqliteRow| PathBuf::try_from(row.try_get::<String, _>("path").unwrap()).unwrap())
|
||||||
.fetch_one(&database.connection)
|
// .fetch_one(&database.connection)
|
||||||
.await
|
// .await
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub async fn update_sheet_path(database: &Database, sheet: &Sheet) -> sqlx::Result<()> {
|
pub async fn update_sheet_path(database: &Database, sheet: &Sheet) -> sqlx::Result<()> {
|
||||||
if let Some(path) = sheet.try_get_path() {
|
// TODO: when updating book or sheet of book, update all
|
||||||
let sheet_kind = SheetKindDiscriminants::from(&sheet.kind);
|
let sheet_kind = SheetKindDiscriminants::from(&sheet.kind);
|
||||||
let table = sheet_kind.get_database_table_name();
|
let table = sheet_kind.get_database_table_name();
|
||||||
return sqlx::query(&format!("UPDATE {} SET path = $1 WHERE id = $2", table))
|
return sqlx::query(&format!("UPDATE {} SET path = $1 WHERE id = $2", table))
|
||||||
.bind(path.to_str().unwrap().to_string())
|
.bind(sheet.pdf.path.to_str().unwrap().to_string())
|
||||||
.bind(sheet.id)
|
.bind(sheet.id)
|
||||||
.execute(&database.connection)
|
.execute(&database.connection)
|
||||||
.await
|
.await
|
||||||
.map(|_| ());
|
.map(|_| ());
|
||||||
}
|
|
||||||
Ok(()) // TODO: error on else?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_sheet_last_opened(database: &Database, sheet: &Sheet) -> sqlx::Result<()> {
|
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<Vec<Sheet>> {
|
|||||||
id: row.try_get("id").unwrap(),
|
id: row.try_get("id").unwrap(),
|
||||||
last_opened: I64DateTime::try_from(row.try_get::<i64, _>("last_opened").unwrap())
|
last_opened: I64DateTime::try_from(row.try_get::<i64, _>("last_opened").unwrap())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
pdf: parse_pdf_from_row(&row).unwrap(),
|
||||||
kind: parse_kind_from_row(kind, row).unwrap(),
|
kind: parse_kind_from_row(kind, row).unwrap(),
|
||||||
})
|
})
|
||||||
.fetch_all(&database.connection)
|
.fetch_all(&database.connection)
|
||||||
@ -103,23 +103,15 @@ fn parse_kind_from_row(kind: SheetKindDiscriminants, row: SqliteRow) -> sqlx::Re
|
|||||||
SheetKindDiscriminants::Sheet => SheetKind::Sheet {
|
SheetKindDiscriminants::Sheet => SheetKind::Sheet {
|
||||||
name: row.try_get("name")?,
|
name: row.try_get("name")?,
|
||||||
composer_id: row.try_get("composer_id")?,
|
composer_id: row.try_get("composer_id")?,
|
||||||
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 {
|
|
||||||
pdf: parse_pdf_from_row(&row)?,
|
|
||||||
},
|
},
|
||||||
|
SheetKindDiscriminants::Orphan => SheetKind::Orphan,
|
||||||
SheetKindDiscriminants::Book => SheetKind::Book {
|
SheetKindDiscriminants::Book => SheetKind::Book {
|
||||||
name: row.try_get("name")?,
|
name: row.try_get("name")?,
|
||||||
composer_id: row.try_get("composer_id")?,
|
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()),
|
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")?,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,8 +112,8 @@ impl AsyncComponent for AppModel {
|
|||||||
.emit(SheetListingInput::Query(query.clone()));
|
.emit(SheetListingInput::Query(query.clone()));
|
||||||
}
|
}
|
||||||
AppInput::SheetPressed(sheet) => {
|
AppInput::SheetPressed(sheet) => {
|
||||||
sheet.open_file(&self.database).await;
|
sheet.open_file();
|
||||||
// TODO: updating does not work
|
// TODO: updating directly does not work
|
||||||
let mut sheet = sheet;
|
let mut sheet = sheet;
|
||||||
sheet.last_opened = I64DateTime(Utc::now());
|
sheet.last_opened = I64DateTime(Utc::now());
|
||||||
sheet_dao::update_sheet_last_opened(&self.database, &sheet)
|
sheet_dao::update_sheet_last_opened(&self.database, &sheet)
|
||||||
|
@ -46,17 +46,16 @@ impl FactoryComponent for SheetModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
fn init_model(sheet: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
let label = match &value.kind {
|
let label = match &sheet.kind {
|
||||||
crate::sheet::SheetKind::Sheet { name, .. } => name,
|
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::Book { name, .. } => name,
|
||||||
crate::sheet::SheetKind::BookSheet { name, .. } => name,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SheetModel {
|
SheetModel {
|
||||||
label: label.to_string(),
|
label: label.to_string(),
|
||||||
sheet: value,
|
sheet,
|
||||||
visible: true,
|
visible: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user