From f58533003b173eff766c26ef19713e92fa612412 Mon Sep 17 00:00:00 2001 From: Johnny Date: Mon, 12 Jan 2026 23:18:04 +0800 Subject: [PATCH] fix: clean up memo_relation and attachments when deleting memo Fixes #5472 Move cleanup logic to store.DeleteMemo to ensure data consistency: - Delete memo_relation records where memo is source (MemoID) or target (RelatedMemoID) - Delete attachments linked to the memo (including S3/local files) This prevents stale COMMENT records in memo_relation after deleting a memo that has comments. --- server/router/api/v1/memo_service.go | 25 ++++--------------------- store/memo.go | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index db6dd141e..16f5ad165 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -497,23 +497,7 @@ func (s *APIV1Service) DeleteMemo(ctx context.Context, request *v1pb.DeleteMemoR } } - if err = s.Store.DeleteMemo(ctx, &store.DeleteMemo{ID: memo.ID}); err != nil { - return nil, status.Errorf(codes.Internal, "failed to delete memo") - } - - // Delete memo relation - if err := s.Store.DeleteMemoRelation(ctx, &store.DeleteMemoRelation{MemoID: &memo.ID}); err != nil { - return nil, status.Errorf(codes.Internal, "failed to delete memo relations") - } - - // Delete related attachments. - for _, attachment := range attachments { - if err := s.Store.DeleteAttachment(ctx, &store.DeleteAttachment{ID: attachment.ID}); err != nil { - return nil, status.Errorf(codes.Internal, "failed to delete attachment") - } - } - - // Delete memo comments + // Delete memo comments first (store.DeleteMemo handles their relations and attachments) commentType := store.MemoRelationComment relations, err := s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{RelatedMemoID: &memo.ID, Type: &commentType}) if err != nil { @@ -525,10 +509,9 @@ func (s *APIV1Service) DeleteMemo(ctx context.Context, request *v1pb.DeleteMemoR } } - // Delete memo references - referenceType := store.MemoRelationReference - if err := s.Store.DeleteMemoRelation(ctx, &store.DeleteMemoRelation{RelatedMemoID: &memo.ID, Type: &referenceType}); err != nil { - return nil, status.Errorf(codes.Internal, "failed to delete memo references") + // Delete the memo (store.DeleteMemo handles relation and attachment cleanup) + if err = s.Store.DeleteMemo(ctx, &store.DeleteMemo{ID: memo.ID}); err != nil { + return nil, status.Errorf(codes.Internal, "failed to delete memo") } return &emptypb.Empty{}, nil diff --git a/store/memo.go b/store/memo.go index afd71e29a..ce6cde28d 100644 --- a/store/memo.go +++ b/store/memo.go @@ -138,5 +138,22 @@ func (s *Store) UpdateMemo(ctx context.Context, update *UpdateMemo) error { } func (s *Store) DeleteMemo(ctx context.Context, delete *DeleteMemo) error { + // Clean up memo_relation records where this memo is either the source or target. + if err := s.driver.DeleteMemoRelation(ctx, &DeleteMemoRelation{MemoID: &delete.ID}); err != nil { + return err + } + if err := s.driver.DeleteMemoRelation(ctx, &DeleteMemoRelation{RelatedMemoID: &delete.ID}); err != nil { + return err + } + // Clean up attachments linked to this memo. + attachments, err := s.ListAttachments(ctx, &FindAttachment{MemoID: &delete.ID}) + if err != nil { + return err + } + for _, attachment := range attachments { + if err := s.DeleteAttachment(ctx, &DeleteAttachment{ID: attachment.ID}); err != nil { + return err + } + } return s.driver.DeleteMemo(ctx, delete) }