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>

Changed files
+15 -12
internal
atproto
+15 -12
internal/atproto/jetstream/comment_consumer.go
···
// Comment was soft-deleted, now being recreated (resurrection)
// This is a NEW record with same rkey - update ALL fields including threading refs
// User may have deleted old comment and created a new one on a different parent/root
+
// Clear deletion metadata to restore the comment
log.Printf("Resurrecting previously deleted comment: %s", comment.URI)
commentID = existingID
···
created_at = $12,
indexed_at = $13,
deleted_at = NULL,
+
deletion_reason = NULL,
+
deleted_by = NULL,
reply_count = 0
WHERE id = $14
`
···
}
// deleteCommentAndUpdateCounts atomically soft-deletes a comment and updates parent counts
+
// Blanks content to preserve thread structure while respecting user privacy
+
// The comment remains in the database but is shown as "[deleted]" in thread views
func (c *CommentEventConsumer) deleteCommentAndUpdateCounts(ctx context.Context, comment *comments.Comment) error {
tx, err := c.db.BeginTx(ctx, nil)
if err != nil {
···
}
}()
-
// 1. Soft-delete the comment (idempotent)
-
deleteQuery := `
-
UPDATE comments
-
SET deleted_at = $2
-
WHERE uri = $1 AND deleted_at IS NULL
-
`
-
-
result, err := tx.ExecContext(ctx, deleteQuery, comment.URI, time.Now())
-
if err != nil {
-
return fmt.Errorf("failed to delete comment: %w", err)
+
// 1. Soft-delete the comment: blank content but preserve structure
+
// DELETE event from Jetstream = author deleted their own comment
+
// Content is blanked to respect user privacy while preserving thread structure
+
// Use the repository's transaction-aware method for DRY
+
repoTx, ok := c.commentRepo.(comments.RepositoryTx)
+
if !ok {
+
return fmt.Errorf("comment repository does not support transactional operations")
}
-
rowsAffected, err := result.RowsAffected()
+
rowsAffected, err := repoTx.SoftDeleteWithReasonTx(ctx, tx, comment.URI, comments.DeletionReasonAuthor, comment.CommenterDID)
if err != nil {
-
return fmt.Errorf("failed to check delete result: %w", err)
+
return fmt.Errorf("failed to delete comment: %w", err)
}
// Idempotent: If no rows affected, comment already deleted
···
collection := utils.ExtractCollectionFromURI(comment.ParentURI)
var updateQuery string
+
var result sql.Result
switch collection {
case "social.coves.community.post":
// Comment on post - decrement posts.comment_count