141 lines
4.6 KiB
Rust
141 lines
4.6 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use strum::{EnumMessage, IntoEnumIterator};
|
|
use strum_macros::{EnumDiscriminants, EnumIter, EnumString};
|
|
|
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
|
use sqlx::{sqlite::SqliteRow, Row, SqlitePool};
|
|
|
|
use crate::{
|
|
database::Database,
|
|
sheet::{I64DateTime, Pdf, Sheet, SheetKind, SheetKindDiscriminants},
|
|
};
|
|
|
|
pub async fn insert_file_as_orphan(
|
|
database: &Database,
|
|
file: impl AsRef<Path>,
|
|
) -> sqlx::Result<Sheet> {
|
|
let pdf = Pdf::try_from(file.as_ref().to_path_buf()).unwrap();
|
|
let last_opened = DateTime::<Utc>::default();
|
|
|
|
let result = sqlx::query(
|
|
"
|
|
INSERT INTO orphans (path, file_size, file_hash, last_opened)
|
|
VALUES ($1, $2, $3, $4)
|
|
",
|
|
)
|
|
.bind(pdf.path.to_str().unwrap().to_string())
|
|
.bind(pdf.file_size as i32)
|
|
.bind(pdf.file_hash.clone())
|
|
.bind(last_opened.timestamp())
|
|
.execute(&database.connection)
|
|
.await
|
|
.unwrap();
|
|
|
|
let id = result.last_insert_rowid();
|
|
|
|
Ok(Sheet {
|
|
id,
|
|
last_opened: I64DateTime(last_opened),
|
|
kind: SheetKind::Orphan { pdf },
|
|
})
|
|
}
|
|
|
|
pub async fn find_path_of_book(database: &Database, book_id: &i64) -> sqlx::Result<PathBuf> {
|
|
sqlx::query("SELECT path FROM books WHERE id = $1")
|
|
.bind(book_id)
|
|
.map(|row: SqliteRow| PathBuf::try_from(row.try_get::<String, _>("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?
|
|
}
|
|
|
|
pub async fn update_sheet_last_opened(database: &Database, sheet: &Sheet) -> sqlx::Result<()> {
|
|
let sheet_kind = SheetKindDiscriminants::from(&sheet.kind);
|
|
let table = sheet_kind.get_database_table_name();
|
|
sqlx::query(&format!(
|
|
"UPDATE {} SET last_opened = $1 WHERE id = $2",
|
|
table
|
|
))
|
|
.bind(i64::from(&sheet.last_opened))
|
|
.bind(sheet.id)
|
|
.execute(&database.connection)
|
|
.await
|
|
.map(|_| ())
|
|
}
|
|
|
|
pub async fn fetch_all_sheets(database: &Database) -> sqlx::Result<Vec<Sheet>> {
|
|
let mut sheets: Vec<Sheet> = Vec::new();
|
|
|
|
for kind in SheetKindDiscriminants::iter() {
|
|
let table = kind.get_database_table_name();
|
|
|
|
let mut sheets_of_kind = sqlx::query(&format!("SELECT * FROM {}", table))
|
|
.map(|row: SqliteRow| Sheet {
|
|
id: row.try_get("id").unwrap(),
|
|
last_opened: I64DateTime::try_from(row.try_get::<i64, _>("last_opened").unwrap())
|
|
.unwrap(),
|
|
kind: parse_kind_from_row(kind, row).unwrap(),
|
|
})
|
|
.fetch_all(&database.connection)
|
|
.await?;
|
|
|
|
sheets.append(&mut sheets_of_kind);
|
|
}
|
|
|
|
Ok(sheets)
|
|
}
|
|
|
|
fn parse_kind_from_row(kind: SheetKindDiscriminants, row: SqliteRow) -> sqlx::Result<SheetKind> {
|
|
Ok(match kind {
|
|
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)?,
|
|
},
|
|
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")?,
|
|
},
|
|
})
|
|
}
|
|
|
|
fn sheet_ids_from_string(s: String) -> Vec<i64> {
|
|
s.trim()
|
|
.split(",")
|
|
.map(|s| i64::from_str_radix(s, 10).unwrap())
|
|
.collect()
|
|
}
|
|
|
|
fn parse_pdf_from_row(row: &SqliteRow) -> sqlx::Result<Pdf> {
|
|
// TODO: use get instead of try_get???
|
|
Ok(Pdf {
|
|
path: PathBuf::from(row.try_get::<String, _>("path").unwrap()),
|
|
file_size: row.try_get::<i64, _>("file_size")? as u64,
|
|
file_hash: row.try_get("file_hash")?,
|
|
})
|
|
}
|