coven_database/
file_pins.rs1use crate::{sqlite::DatabaseConnection, DbError};
8use coven_foundation::{files::StagedName, id_source::FileId};
9use rusqlite::params;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct PinRequest {
14 pub id: i64,
17 pub file: FileId,
19 pub copy: Option<StagedName>,
22 pub retry: Option<crate::RetryWait>,
24}
25
26pub(crate) fn request(db: &DatabaseConnection, file: FileId) -> Result<(), DbError> {
28 db.internal_execute(
29 "INSERT INTO _coven_pin_requests(file,copy)
30 SELECT ?1,(SELECT path FROM _coven_device_files WHERE file=?1)
31 ON CONFLICT DO NOTHING",
32 params![file],
33 )?;
34 Ok(())
35}
36
37pub(crate) fn end(db: &DatabaseConnection, file: FileId) -> Result<bool, DbError> {
41 let ended =
42 db.query("DELETE FROM _coven_pin_requests WHERE file=?1 RETURNING copy", [file], |r| {
43 r.get::<_, Option<String>>(0)
44 })?;
45 release(db, ended)
46}
47
48pub(crate) fn end_request(db: &DatabaseConnection, id: i64) -> Result<bool, DbError> {
51 let ended =
52 db.query("DELETE FROM _coven_pin_requests WHERE id=?1 RETURNING copy", [id], |r| {
53 r.get::<_, Option<String>>(0)
54 })?;
55 release(db, ended)
56}
57
58fn release(db: &DatabaseConnection, mut ended: Vec<Option<String>>) -> Result<bool, DbError> {
61 let Some(copy) = ended.pop() else {
62 return Ok(false);
63 };
64 if let Some(copy) = copy {
65 crate::file_queue::release_copy(db, ©)?;
66 }
67 Ok(true)
68}
69
70pub(crate) fn drop_copy(db: &DatabaseConnection, id: i64) -> Result<(), DbError> {
74 let copy = db
75 .query("SELECT copy FROM _coven_pin_requests WHERE id=?1", [id], |r| {
76 r.get::<_, Option<String>>(0)
77 })?
78 .pop()
79 .flatten();
80 let Some(copy) = copy else {
81 return Ok(());
82 };
83 db.internal_execute("UPDATE _coven_pin_requests SET copy=NULL WHERE id=?1", [id])?;
84 crate::file_queue::release_copy(db, ©)
85}
86
87pub(crate) fn read(db: &DatabaseConnection) -> Result<Vec<PinRequest>, DbError> {
89 db.query("SELECT id,file,copy FROM _coven_pin_requests ORDER BY file", [], |r| {
90 Ok((r.get::<_, i64>(0)?, r.get::<_, FileId>(1)?, r.get::<_, Option<String>>(2)?))
91 })?
92 .into_iter()
93 .map(|(id, file, copy)| {
94 Ok(PinRequest {
95 id,
96 file,
97 copy: copy
98 .map(|copy| StagedName::parse(©).ok_or(DbError::DamagedDatabase))
99 .transpose()?,
100 retry: crate::retry::find(db, crate::RetrySubject::Pin(id))?,
101 })
102 })
103 .collect()
104}
105
106#[cfg(test)]
107#[path = "file_pins_tests.rs"]
108pub(crate) mod tests;