pinakes-core: wrap save_markdown_links in transactions for atomicity

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I44eaeda5bc1d6894137ee9a3c902cdac6a6a6964
This commit is contained in:
raf 2026-02-09 14:26:02 +03:00
commit 4ed61bc62e
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
2 changed files with 43 additions and 27 deletions

View file

@ -6047,7 +6047,7 @@ impl StorageBackend for PostgresBackend {
media_id: MediaId,
links: &[crate::model::MarkdownLink],
) -> Result<()> {
let client = self
let mut client = self
.pool
.get()
.await
@ -6055,9 +6055,14 @@ impl StorageBackend for PostgresBackend {
let media_id_str = media_id.0.to_string();
// Wrap DELETE + INSERT in transaction to ensure atomicity
let tx = client
.transaction()
.await
.map_err(|e| PinakesError::Database(e.to_string()))?;
// Delete existing links for this source
client
.execute(
tx.execute(
"DELETE FROM markdown_links WHERE source_media_id = $1",
&[&media_id_str],
)
@ -6067,8 +6072,7 @@ impl StorageBackend for PostgresBackend {
// Insert new links
for link in links {
let target_media_id = link.target_media_id.map(|id| id.0.to_string());
client
.execute(
tx.execute(
"INSERT INTO markdown_links (
id, source_media_id, target_path, target_media_id,
link_type, link_text, line_number, context, created_at
@ -6089,6 +6093,11 @@ impl StorageBackend for PostgresBackend {
.map_err(|e| PinakesError::Database(e.to_string()))?;
}
// Commit transaction - if this fails, all changes are rolled back
tx.commit()
.await
.map_err(|e| PinakesError::Database(e.to_string()))?;
Ok(())
}

View file

@ -6400,16 +6400,19 @@ impl StorageBackend for SqliteBackend {
let links: Vec<_> = links.to_vec();
tokio::task::spawn_blocking(move || {
let conn = conn.lock().unwrap();
let mut conn = conn.lock().unwrap();
// Wrap DELETE + INSERT in transaction to ensure atomicity
let tx = conn.transaction()?;
// Delete existing links for this source
conn.execute(
tx.execute(
"DELETE FROM markdown_links WHERE source_media_id = ?1",
[&media_id_str],
)?;
// Insert new links
let mut stmt = conn.prepare(
let mut stmt = tx.prepare(
"INSERT INTO markdown_links (
id, source_media_id, target_path, target_media_id,
link_type, link_text, line_number, context, created_at
@ -6430,6 +6433,10 @@ impl StorageBackend for SqliteBackend {
])?;
}
// Commit transaction - if this fails, all changes are rolled back
drop(stmt);
tx.commit()?;
Ok::<_, rusqlite::Error>(())
})
.await