@@ -402,6 +402,71 @@ async def _delete_documents_atomically(session):
402402
403403 return result
404404
405+ async def rebuild_document_indexes (
406+ self , user_id : str , collection_id : str , document_id : str , index_types : List [str ]
407+ ) -> dict :
408+ """
409+ Rebuild specified indexes for a document
410+
411+ Args:
412+ user_id: User ID
413+ collection_id: Collection ID
414+ document_id: Document ID
415+ index_types: List of index types to rebuild ('vector', 'fulltext', 'graph')
416+
417+ Returns:
418+ dict: Success response
419+ """
420+ if len (set (index_types )) != len (index_types ):
421+ raise invalid_param ("index_types" , "duplicate index types are not allowed" )
422+
423+ logger .info (f"Rebuilding indexes for document { document_id } with types: { index_types } " )
424+
425+ # Convert index types to enum values outside transaction
426+ from aperag .db .models import DocumentIndexType
427+ index_type_enums = []
428+ for index_type in index_types :
429+ if index_type == 'vector' :
430+ index_type_enums .append (DocumentIndexType .VECTOR )
431+ elif index_type == 'fulltext' :
432+ index_type_enums .append (DocumentIndexType .FULLTEXT )
433+ elif index_type == 'graph' :
434+ index_type_enums .append (DocumentIndexType .GRAPH )
435+ else :
436+ raise invalid_param ("index_type" , f"Invalid index type: { index_type } " )
437+
438+ # Execute all operations atomically in a single transaction
439+ async def _rebuild_document_indexes_atomically (session ):
440+ # Verify document exists and user has access
441+ document = await self .db_ops .query_document (user_id , collection_id , document_id )
442+ if not document :
443+ raise DocumentNotFoundException (f"Document { document_id } not found" )
444+
445+ if document .collection_id != collection_id :
446+ raise ResourceNotFoundException (f"Document { document_id } not found in collection { collection_id } " )
447+
448+ # Verify user has access to the collection
449+ collection = await self .db_ops .query_collection (user_id , collection_id )
450+ if not collection or collection .user != user_id :
451+ raise ResourceNotFoundException (f"Collection { collection_id } not found or access denied" )
452+
453+ # Trigger index rebuild by incrementing version for selected index types
454+ await document_index_manager .rebuild_document_indexes (session , document_id , index_type_enums )
455+
456+ logger .info (f"Successfully triggered rebuild for document { document_id } indexes: { index_types } " )
457+
458+ return {
459+ "code" : "200" ,
460+ "message" : f"Index rebuild initiated for types: { ', ' .join (index_types )} "
461+ }
462+
463+ result = await self .db_ops .execute_with_transaction (_rebuild_document_indexes_atomically )
464+
465+ # Trigger index reconciliation after successful rebuild initiation
466+ _trigger_index_reconciliation ()
467+
468+ return result
469+
405470
406471# Create a global service instance for easy access
407472# This uses the global db_ops instance and doesn't require session management in views
0 commit comments