A community based topic aggregation platform built on atproto

refactor(consumer): use RepositoryTx for atomic delete operations

Replace inline SQL in deleteCommentAndUpdateCounts with call to
SoftDeleteWithReasonTx via type assertion to RepositoryTx interface.

This eliminates duplicate deletion logic between consumer and repo
while maintaining atomic transaction for delete + count updates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+15 -12
+15 -12
internal/atproto/jetstream/comment_consumer.go
··· 260 // Comment was soft-deleted, now being recreated (resurrection) 261 // This is a NEW record with same rkey - update ALL fields including threading refs 262 // User may have deleted old comment and created a new one on a different parent/root 263 log.Printf("Resurrecting previously deleted comment: %s", comment.URI) 264 commentID = existingID 265 ··· 280 created_at = $12, 281 indexed_at = $13, 282 deleted_at = NULL, 283 reply_count = 0 284 WHERE id = $14 285 ` ··· 420 } 421 422 // deleteCommentAndUpdateCounts atomically soft-deletes a comment and updates parent counts 423 func (c *CommentEventConsumer) deleteCommentAndUpdateCounts(ctx context.Context, comment *comments.Comment) error { 424 tx, err := c.db.BeginTx(ctx, nil) 425 if err != nil { ··· 431 } 432 }() 433 434 - // 1. Soft-delete the comment (idempotent) 435 - deleteQuery := ` 436 - UPDATE comments 437 - SET deleted_at = $2 438 - WHERE uri = $1 AND deleted_at IS NULL 439 - ` 440 - 441 - result, err := tx.ExecContext(ctx, deleteQuery, comment.URI, time.Now()) 442 - if err != nil { 443 - return fmt.Errorf("failed to delete comment: %w", err) 444 } 445 446 - rowsAffected, err := result.RowsAffected() 447 if err != nil { 448 - return fmt.Errorf("failed to check delete result: %w", err) 449 } 450 451 // Idempotent: If no rows affected, comment already deleted ··· 462 collection := utils.ExtractCollectionFromURI(comment.ParentURI) 463 464 var updateQuery string 465 switch collection { 466 case "social.coves.community.post": 467 // Comment on post - decrement posts.comment_count
··· 260 // Comment was soft-deleted, now being recreated (resurrection) 261 // This is a NEW record with same rkey - update ALL fields including threading refs 262 // User may have deleted old comment and created a new one on a different parent/root 263 + // Clear deletion metadata to restore the comment 264 log.Printf("Resurrecting previously deleted comment: %s", comment.URI) 265 commentID = existingID 266 ··· 281 created_at = $12, 282 indexed_at = $13, 283 deleted_at = NULL, 284 + deletion_reason = NULL, 285 + deleted_by = NULL, 286 reply_count = 0 287 WHERE id = $14 288 ` ··· 423 } 424 425 // deleteCommentAndUpdateCounts atomically soft-deletes a comment and updates parent counts 426 + // Blanks content to preserve thread structure while respecting user privacy 427 + // The comment remains in the database but is shown as "[deleted]" in thread views 428 func (c *CommentEventConsumer) deleteCommentAndUpdateCounts(ctx context.Context, comment *comments.Comment) error { 429 tx, err := c.db.BeginTx(ctx, nil) 430 if err != nil { ··· 436 } 437 }() 438 439 + // 1. Soft-delete the comment: blank content but preserve structure 440 + // DELETE event from Jetstream = author deleted their own comment 441 + // Content is blanked to respect user privacy while preserving thread structure 442 + // Use the repository's transaction-aware method for DRY 443 + repoTx, ok := c.commentRepo.(comments.RepositoryTx) 444 + if !ok { 445 + return fmt.Errorf("comment repository does not support transactional operations") 446 } 447 448 + rowsAffected, err := repoTx.SoftDeleteWithReasonTx(ctx, tx, comment.URI, comments.DeletionReasonAuthor, comment.CommenterDID) 449 if err != nil { 450 + return fmt.Errorf("failed to delete comment: %w", err) 451 } 452 453 // Idempotent: If no rows affected, comment already deleted ··· 464 collection := utils.ExtractCollectionFromURI(comment.ParentURI) 465 466 var updateQuery string 467 + var result sql.Result 468 switch collection { 469 case "social.coves.community.post": 470 // Comment on post - decrement posts.comment_count