mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-23 17:28:34 +02:00
concurrent delete process
This commit is contained in:
@@ -6,6 +6,7 @@ use axum_session::Session;
|
|||||||
use axum_session_auth::AuthSession;
|
use axum_session_auth::AuthSession;
|
||||||
use axum_session_surreal::SessionSurrealPool;
|
use axum_session_surreal::SessionSurrealPool;
|
||||||
use surrealdb::{engine::any::Any, Surreal};
|
use surrealdb::{engine::any::Any, Surreal};
|
||||||
|
use tokio::join;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -16,7 +17,7 @@ use crate::{
|
|||||||
AppState,
|
AppState,
|
||||||
},
|
},
|
||||||
storage::{
|
storage::{
|
||||||
db::{delete_item, get_all_stored_items, get_item},
|
db::{delete_item, get_item},
|
||||||
types::{
|
types::{
|
||||||
file_info::FileInfo, job::Job, knowledge_entity::KnowledgeEntity,
|
file_info::FileInfo, job::Job, knowledge_entity::KnowledgeEntity,
|
||||||
knowledge_relationship::KnowledgeRelationship, text_chunk::TextChunk,
|
knowledge_relationship::KnowledgeRelationship, text_chunk::TextChunk,
|
||||||
@@ -100,62 +101,39 @@ pub async fn delete_text_content(
|
|||||||
None => return Ok(Redirect::to("/").into_response()),
|
None => return Ok(Redirect::to("/").into_response()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get TextContent from db
|
// Get and validate TextContent
|
||||||
let text_content = match get_item::<TextContent>(&state.surreal_db_client, &id)
|
let text_content = get_and_validate_text_content(&state, &id, user).await?;
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?
|
// Perform concurrent deletions
|
||||||
{
|
let deletion_tasks = join!(
|
||||||
Some(text_content) => text_content,
|
async {
|
||||||
None => {
|
if let Some(file_info) = text_content.file_info {
|
||||||
|
FileInfo::delete_by_id(&file_info.id, &state.surreal_db_client).await
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete_item::<TextContent>(&state.surreal_db_client, &text_content.id),
|
||||||
|
TextChunk::delete_by_source_id(&text_content.id, &state.surreal_db_client),
|
||||||
|
KnowledgeEntity::delete_by_source_id(&text_content.id, &state.surreal_db_client),
|
||||||
|
KnowledgeRelationship::delete_relationships_by_source_id(
|
||||||
|
&text_content.id,
|
||||||
|
&state.surreal_db_client
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle potential errors from concurrent operations
|
||||||
|
match deletion_tasks {
|
||||||
|
(Ok(_), Ok(_), Ok(_), Ok(_), Ok(_)) => (),
|
||||||
|
_ => {
|
||||||
return Err(HtmlError::new(
|
return Err(HtmlError::new(
|
||||||
AppError::NotFound("No item found".to_string()),
|
AppError::Processing("Failed to delete one or more items".to_string()),
|
||||||
state.templates,
|
state.templates.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Validate that the user is the owner
|
|
||||||
if text_content.user_id != user.id {
|
|
||||||
return Err(HtmlError::new(
|
|
||||||
AppError::Auth("You are not the owner of that content".to_string()),
|
|
||||||
state.templates,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If TextContent has file_info, delete it from db and file from disk.
|
// Render updated content
|
||||||
if text_content.file_info.is_some() {
|
|
||||||
FileInfo::delete_by_id(
|
|
||||||
&text_content.file_info.unwrap().id,
|
|
||||||
&state.surreal_db_client,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete textcontent from db
|
|
||||||
delete_item::<TextContent>(&state.surreal_db_client, &text_content.id)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
|
||||||
|
|
||||||
// Delete TextChunks
|
|
||||||
TextChunk::delete_by_source_id(&text_content.id, &state.surreal_db_client)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
|
||||||
|
|
||||||
// Delete KnowledgeEntities
|
|
||||||
KnowledgeEntity::delete_by_source_id(&text_content.id, &state.surreal_db_client)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
|
||||||
|
|
||||||
// Delete KnowledgeRelationships
|
|
||||||
KnowledgeRelationship::delete_relationships_by_source_id(
|
|
||||||
&text_content.id,
|
|
||||||
&state.surreal_db_client,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
|
||||||
|
|
||||||
// Get latest text contents after updates
|
|
||||||
let latest_text_contents = User::get_latest_text_contents(&user.id, &state.surreal_db_client)
|
let latest_text_contents = User::get_latest_text_contents(&user.id, &state.surreal_db_client)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
@@ -173,6 +151,114 @@ pub async fn delete_text_content(
|
|||||||
Ok(output.into_response())
|
Ok(output.into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to get and validate text content
|
||||||
|
async fn get_and_validate_text_content(
|
||||||
|
state: &AppState,
|
||||||
|
id: &str,
|
||||||
|
user: &User,
|
||||||
|
) -> Result<TextContent, HtmlError> {
|
||||||
|
let text_content = get_item::<TextContent>(&state.surreal_db_client, id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
HtmlError::new(
|
||||||
|
AppError::NotFound("No item found".to_string()),
|
||||||
|
state.templates.clone(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if text_content.user_id != user.id {
|
||||||
|
return Err(HtmlError::new(
|
||||||
|
AppError::Auth("You are not the owner of that content".to_string()),
|
||||||
|
state.templates.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(text_content)
|
||||||
|
}
|
||||||
|
// pub async fn delete_text_content(
|
||||||
|
// State(state): State<AppState>,
|
||||||
|
// auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
// Path(id): Path<String>,
|
||||||
|
// ) -> Result<impl IntoResponse, HtmlError> {
|
||||||
|
// let user = match &auth.current_user {
|
||||||
|
// Some(user) => user,
|
||||||
|
// None => return Ok(Redirect::to("/").into_response()),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Get TextContent from db
|
||||||
|
// let text_content = match get_item::<TextContent>(&state.surreal_db_client, &id)
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?
|
||||||
|
// {
|
||||||
|
// Some(text_content) => text_content,
|
||||||
|
// None => {
|
||||||
|
// return Err(HtmlError::new(
|
||||||
|
// AppError::NotFound("No item found".to_string()),
|
||||||
|
// state.templates,
|
||||||
|
// ))
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Validate that the user is the owner
|
||||||
|
// if text_content.user_id != user.id {
|
||||||
|
// return Err(HtmlError::new(
|
||||||
|
// AppError::Auth("You are not the owner of that content".to_string()),
|
||||||
|
// state.templates,
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // If TextContent has file_info, delete it from db and file from disk.
|
||||||
|
// if text_content.file_info.is_some() {
|
||||||
|
// FileInfo::delete_by_id(
|
||||||
|
// &text_content.file_info.unwrap().id,
|
||||||
|
// &state.surreal_db_client,
|
||||||
|
// )
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Delete textcontent from db
|
||||||
|
// delete_item::<TextContent>(&state.surreal_db_client, &text_content.id)
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||||
|
|
||||||
|
// // Delete TextChunks
|
||||||
|
// TextChunk::delete_by_source_id(&text_content.id, &state.surreal_db_client)
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
// // Delete KnowledgeEntities
|
||||||
|
// KnowledgeEntity::delete_by_source_id(&text_content.id, &state.surreal_db_client)
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
// // Delete KnowledgeRelationships
|
||||||
|
// KnowledgeRelationship::delete_relationships_by_source_id(
|
||||||
|
// &text_content.id,
|
||||||
|
// &state.surreal_db_client,
|
||||||
|
// )
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
// // Get latest text contents after updates
|
||||||
|
// let latest_text_contents = User::get_latest_text_contents(&user.id, &state.surreal_db_client)
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
// let output = render_block(
|
||||||
|
// "index/signed_in/recent_content.html",
|
||||||
|
// "latest_content_section",
|
||||||
|
// LatestTextContentData {
|
||||||
|
// user: user.clone(),
|
||||||
|
// latest_text_contents,
|
||||||
|
// },
|
||||||
|
// state.templates.clone(),
|
||||||
|
// )?;
|
||||||
|
|
||||||
|
// Ok(output.into_response())
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct ActiveJobsData {
|
pub struct ActiveJobsData {
|
||||||
active_jobs: Vec<Job>,
|
active_jobs: Vec<Job>,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{error::AppError, storage::db::SurrealDbClient, stored_object};
|
use crate::{error::AppError, storage::db::SurrealDbClient, stored_object};
|
||||||
use surrealdb::{engine::any::Any, sql::Subquery, Surreal};
|
use surrealdb::{engine::any::Any, Surreal};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ impl KnowledgeRelationship {
|
|||||||
db_client: &SurrealDbClient,
|
db_client: &SurrealDbClient,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let query = format!(
|
let query = format!(
|
||||||
"DELETE knowledge_entity -> relates_to WHERE source_id = '{}'",
|
"DELETE knowledge_entity -> relates_to WHERE source_id = `{}`",
|
||||||
source_id
|
source_id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user