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:
parent
9afe4a4f6a
commit
4ed61bc62e
2 changed files with 43 additions and 27 deletions
|
|
@ -6047,7 +6047,7 @@ impl StorageBackend for PostgresBackend {
|
||||||
media_id: MediaId,
|
media_id: MediaId,
|
||||||
links: &[crate::model::MarkdownLink],
|
links: &[crate::model::MarkdownLink],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let client = self
|
let mut client = self
|
||||||
.pool
|
.pool
|
||||||
.get()
|
.get()
|
||||||
.await
|
.await
|
||||||
|
|
@ -6055,40 +6055,49 @@ impl StorageBackend for PostgresBackend {
|
||||||
|
|
||||||
let media_id_str = media_id.0.to_string();
|
let media_id_str = media_id.0.to_string();
|
||||||
|
|
||||||
// Delete existing links for this source
|
// Wrap DELETE + INSERT in transaction to ensure atomicity
|
||||||
client
|
let tx = client
|
||||||
.execute(
|
.transaction()
|
||||||
"DELETE FROM markdown_links WHERE source_media_id = $1",
|
|
||||||
&[&media_id_str],
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| PinakesError::Database(e.to_string()))?;
|
.map_err(|e| PinakesError::Database(e.to_string()))?;
|
||||||
|
|
||||||
|
// Delete existing links for this source
|
||||||
|
tx.execute(
|
||||||
|
"DELETE FROM markdown_links WHERE source_media_id = $1",
|
||||||
|
&[&media_id_str],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| PinakesError::Database(e.to_string()))?;
|
||||||
|
|
||||||
// Insert new links
|
// Insert new links
|
||||||
for link in links {
|
for link in links {
|
||||||
let target_media_id = link.target_media_id.map(|id| id.0.to_string());
|
let target_media_id = link.target_media_id.map(|id| id.0.to_string());
|
||||||
client
|
tx.execute(
|
||||||
.execute(
|
"INSERT INTO markdown_links (
|
||||||
"INSERT INTO markdown_links (
|
|
||||||
id, source_media_id, target_path, target_media_id,
|
id, source_media_id, target_path, target_media_id,
|
||||||
link_type, link_text, line_number, context, created_at
|
link_type, link_text, line_number, context, created_at
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
&[
|
&[
|
||||||
&link.id.to_string(),
|
&link.id.to_string(),
|
||||||
&media_id_str,
|
&media_id_str,
|
||||||
&link.target_path,
|
&link.target_path,
|
||||||
&target_media_id,
|
&target_media_id,
|
||||||
&link.link_type.to_string(),
|
&link.link_type.to_string(),
|
||||||
&link.link_text,
|
&link.link_text,
|
||||||
&link.line_number,
|
&link.line_number,
|
||||||
&link.context,
|
&link.context,
|
||||||
&link.created_at,
|
&link.created_at,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| PinakesError::Database(e.to_string()))?;
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6400,16 +6400,19 @@ impl StorageBackend for SqliteBackend {
|
||||||
let links: Vec<_> = links.to_vec();
|
let links: Vec<_> = links.to_vec();
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
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
|
// Delete existing links for this source
|
||||||
conn.execute(
|
tx.execute(
|
||||||
"DELETE FROM markdown_links WHERE source_media_id = ?1",
|
"DELETE FROM markdown_links WHERE source_media_id = ?1",
|
||||||
[&media_id_str],
|
[&media_id_str],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Insert new links
|
// Insert new links
|
||||||
let mut stmt = conn.prepare(
|
let mut stmt = tx.prepare(
|
||||||
"INSERT INTO markdown_links (
|
"INSERT INTO markdown_links (
|
||||||
id, source_media_id, target_path, target_media_id,
|
id, source_media_id, target_path, target_media_id,
|
||||||
link_type, link_text, line_number, context, created_at
|
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>(())
|
Ok::<_, rusqlite::Error>(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue