use rusqlite::{OptionalExtension, params}; use serde::Deserialize; use crate::{ domain::{Entry, FolderId, Manifest}, storage::{PendingMaterialization, StateStore}, }; #[derive(Deserialize)] #[serde(untagged)] enum StoredMaterializationEntries { Single(Entry), Batch(Vec), } struct ParsedPendingEntries { entries: Vec, is_legacy_single_entry: bool, } fn parse_pending_entries(entries: &str) -> anyhow::Result { match serde_json::from_str(entries)? { StoredMaterializationEntries::Single(entry) => Ok(ParsedPendingEntries { entries: vec![entry], is_legacy_single_entry: true, }), StoredMaterializationEntries::Batch(entries) => Ok(ParsedPendingEntries { entries, is_legacy_single_entry: false, }), } } impl StateStore { pub fn save_pending_materialization( &self, folder_id: FolderId, entries: &[Entry], resulting_manifest: &Manifest, ) -> anyhow::Result<()> { self.connection.execute( "INSERT INTO pending_materializations (folder_id, entry, resulting_manifest) VALUES (?1, ?2, ?3) ON CONFLICT(folder_id) DO UPDATE SET entry = excluded.entry, resulting_manifest = excluded.resulting_manifest", params![folder_id.to_string(), serde_json::to_string(entries)?, serde_json::to_string(resulting_manifest)?], )?; Ok(()) } pub fn pending_materialization( &self, folder_id: FolderId, ) -> anyhow::Result> { self.connection.query_row( "SELECT entry, resulting_manifest FROM pending_materializations WHERE folder_id = ?1", params![folder_id.to_string()], |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)), ) .optional()? .map(|(entries, manifest)| { let parsed_entries = parse_pending_entries(&entries)?; Ok(PendingMaterialization { entries: parsed_entries.entries, resulting_manifest: serde_json::from_str(&manifest)?, is_legacy_single_entry: parsed_entries.is_legacy_single_entry, }) }) .transpose() } pub fn clear_pending_materialization(&self, folder_id: FolderId) -> anyhow::Result<()> { self.connection.execute( "DELETE FROM pending_materializations WHERE folder_id = ?1", params![folder_id.to_string()], )?; Ok(()) } }