1use crate::{BackendEventLog, Error, FolderEventLog, Result};
3use sos_core::{
4 events::{
5 patch::{FolderDiff, Patch},
6 EventLog, EventLogType, EventRecord,
7 },
8 AccountId, VaultId,
9};
10use sos_database::{
11 entity::{
12 AccountEntity, AccountRow, FolderEntity, FolderRecord, FolderRow,
13 },
14 open_memory, EventLogOwner,
15};
16use sos_filesystem::FolderEventLog as FsFolderEventLog;
17use sos_reducers::FolderReducer;
18use sos_vault::Vault;
19use tempfile::NamedTempFile;
20
21pub async fn compact_folder(
23 account_id: &AccountId,
24 folder_id: &VaultId,
25 event_log: &mut FolderEventLog,
26) -> Result<()> {
27 match event_log {
28 BackendEventLog::Database(event_log) => {
29 let events = FolderReducer::new()
31 .reduce(event_log)
32 .await?
33 .compact()
34 .await?;
35
36 let client = open_memory().await?;
39
40 let temp_name = "compact_temp";
43 let account_row =
44 AccountRow::new_insert(account_id, temp_name.to_owned())?;
45 let mut vault = Vault::default();
46 *vault.header_mut().id_mut() = *folder_id;
47 let folder_row = FolderRow::new_insert(&vault).await?;
48 let db_folder_id = *folder_id;
49
50 let folder_row = client
51 .conn(move |conn| {
52 let account_entity = AccountEntity::new(&conn);
53 let folder_entity = FolderEntity::new(&conn);
54 let account_id = account_entity.insert(&account_row)?;
55 folder_entity.insert_folder(account_id, &folder_row)?;
56 folder_entity.find_one(&db_folder_id)
57 })
58 .await
59 .map_err(sos_database::Error::from)?;
60 let folder_record = FolderRecord::from_row(folder_row).await?;
61
62 let mut temp_event_log = event_log.with_new_client(
64 client,
65 Some(EventLogOwner::Folder(*account_id, folder_record)),
66 );
67 temp_event_log.apply(events.as_slice()).await?;
68
69 let mut records = Vec::new();
70 for event in &events {
71 records.push(EventRecord::encode_event(event).await?);
72 }
73
74 let checkpoint = temp_event_log
75 .tree()
76 .proof(&[temp_event_log.tree().len() - 1])?;
77
78 let diff = FolderDiff::new(Patch::new(records), checkpoint, None);
79 event_log.replace_all_events(&diff).await?;
80
81 Ok(())
82 }
83 BackendEventLog::FileSystem(event_log) => {
84 let events = FolderReducer::new()
86 .reduce(event_log)
87 .await?
88 .compact()
89 .await?;
90
91 let temp = NamedTempFile::new()?;
93 let mut temp_event_log = FsFolderEventLog::<Error>::new_folder(
94 temp.path(),
95 *account_id,
96 EventLogType::Folder(*folder_id),
97 )
98 .await?;
99 temp_event_log.apply(events.as_slice()).await?;
100
101 let mut records = Vec::new();
102 for event in &events {
103 records.push(EventRecord::encode_event(event).await?);
104 }
105
106 let diff = FolderDiff::new(
107 Patch::new(records),
108 temp_event_log
109 .tree()
110 .proof(&[temp_event_log.tree().len() - 1])?,
111 None,
112 );
113
114 event_log.replace_all_events(&diff).await?;
115
116 temp.close()?;
117
118 Ok(())
119 }
120 }
121}