Skip to content

delete poll#38

Merged
RamRamez merged 2 commits intodevelopfrom
delete-poll
Apr 3, 2025
Merged

delete poll#38
RamRamez merged 2 commits intodevelopfrom
delete-poll

Conversation

@lovelgeorge99
Copy link
Copy Markdown
Collaborator

@lovelgeorge99 lovelgeorge99 commented Apr 2, 2025

Issue : #35

Summary by CodeRabbit

  • New Features
    • Introduced a poll deletion feature that allows users to remove polls seamlessly. When a poll is deleted, all related user actions and votes are automatically cleaned up to ensure data consistency and an improved management experience.
  • Bug Fixes
    • Enhanced referential integrity by implementing cascading delete behavior for related records when a poll is deleted.

@lovelgeorge99 lovelgeorge99 requested a review from RamRamez April 2, 2025 18:08
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2025

Walkthrough

This pull request implements cascading delete behavior for polls in the database. It updates SQL migration scripts and the Prisma schema to redefine foreign key constraints on the "UserAction" and "Vote" tables with cascading delete and update options. Additionally, new controller and service methods are introduced to handle poll deletions, which include database transactions and updates to the user's poll count.

Changes

File(s) Change Summary
prisma/.../migration.sql Dropped existing foreign key constraints on pollId for "UserAction" and "Vote", then re-added them with ON DELETE CASCADE ON UPDATE CASCADE.
prisma/schema.prisma Updated the @relation directives in the UserAction and Vote models to include onDelete: Cascade.
src/poll/poll.controller.ts, src/poll/poll.service.ts Added new deletePoll methods: the controller now handles DELETE requests and the service performs the deletion transaction and user count update.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PC as PollController
    participant PS as PollService
    participant DB as Database

    Client->>PC: DELETE /poll/:id
    PC->>PS: deletePoll(id)
    PS->>DB: Check if poll exists
    DB-->>PS: {Poll data} / {Not found}
    PS->>DB: Begin transaction to delete poll
    DB-->>PS: Poll deleted
    PS->>DB: Update user's pollsCreatedCount
    DB-->>PS: User data updated
    PS-->>PC: Return deleted poll data
    PC->>Client: 200 JSON response
Loading

Possibly related PRs

Suggested reviewers

  • RamRamez

Poem

I'm a little rabbit, hopping with glee,
Cascading deletes make the database free.
Polls vanish in a blink, with action in tow,
Clean and neat data—off we go!
Code carrots crunch, celebrating every flow! 🐰🌟

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/poll/poll.controller.ts (1)

50-61: Implementation looks good with one minor suggestion

The new deletePoll endpoint correctly uses the service layer to delete the poll and handles errors appropriately. However, consider adding a check if the poll exists before attempting to delete it.

Consider adding a 404 response for when the poll isn't found:

  @Delete(':id')
  async deletePoll(@Param('id') id: number, @Res() res: Response) {
    try {
      const poll = await this.pollService.deletePoll(Number(id));

+     if (!poll) {
+       return res.status(404).json({ message: 'Poll not found' });
+     }

      return res.status(200).json({ message: 'Poll deleted', poll: poll });
    } catch (error) {
+     if (error.message === 'Poll not found') {
+       return res.status(404).json({ message: error.message });
+     }
      return res
        .status(500)
        .json({ message: 'Internal server error', error: error.message });
    }
  }
src/poll/poll.service.ts (1)

138-165: Implementation looks solid with minor suggestion for error handling

The deletePoll method correctly:

  1. Checks if the poll exists before attempting to delete it
  2. Uses a transaction to ensure data consistency
  3. Updates the user's pollsCreatedCount

One improvement would be to use a more specific error type.

Use BadRequestException for better error handling consistency:

  async deletePoll(pollId: number) {
    const poll = await this.databaseService.poll.findUnique({
      where: { pollId },
    });
    if (!poll) {
-     throw new Error('Poll not found');
+     throw new BadRequestException('Poll not found');
    }

    return this.databaseService.$transaction(async (tx) => {
      const deleted = await tx.poll.delete({
        where: {
          pollId,
        },
      });

      // Update user's pollsCreatedCount
      await tx.user.update({
        where: { id: deleted.authorUserId },
        data: {
          pollsCreatedCount: {
            decrement: 1,
          },
        },
      });

      return deleted;
    });
  }
prisma/schema.prisma (2)

35-35: Add space after comma for consistency

The Prisma schema change correctly adds cascading delete behavior, but there is a minor formatting issue.

- poll      Poll       @relation(fields: [pollId], references: [pollId],onDelete: Cascade)
+ poll      Poll       @relation(fields: [pollId], references: [pollId], onDelete: Cascade)

65-65: Add space after comma for consistency

Similar to the previous comment, there's a minor formatting issue in the relation definition.

- poll             Poll     @relation(fields: [pollId], references: [pollId],onDelete: Cascade)
+ poll             Poll     @relation(fields: [pollId], references: [pollId], onDelete: Cascade)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61fd38c and 460b8b5.

📒 Files selected for processing (4)
  • prisma/migrations/20250402170145_add_cascade_delete/migration.sql (1 hunks)
  • prisma/schema.prisma (2 hunks)
  • src/poll/poll.controller.ts (1 hunks)
  • src/poll/poll.service.ts (1 hunks)
🔇 Additional comments (1)
prisma/migrations/20250402170145_add_cascade_delete/migration.sql (1)

1-11: SQL migration implements cascading deletion correctly

The migration properly:

  1. Drops existing foreign key constraints
  2. Adds new constraints with CASCADE behavior for both DELETE and UPDATE operations

This ensures that when a poll is deleted, all related user actions and votes will be automatically deleted as well.

@RamRamez
Copy link
Copy Markdown
Member

RamRamez commented Apr 2, 2025

@lovelgeorge99 I think we should delete the poll only when user is the author of the poll

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/poll/poll.service.ts (3)

138-169: Consider adding error handling for database operations.

The method lacks a try-catch block for handling potential database errors, which could make debugging more difficult and lead to unhandled exceptions.

  async deletePoll(userId: number, pollId: number) {
+   try {
      const poll = await this.databaseService.poll.findUnique({
        where: { pollId },
      });

      if (!poll) {
        throw new BadRequestException('Poll not found');
      }
      if (poll.authorUserId !== userId) {
        throw new BadRequestException('User Not Authorized');
      }

      return this.databaseService.$transaction(async (tx) => {
        const deleted = await tx.poll.delete({
          where: {
            pollId,
          },
        });

        // Update user's pollsCreatedCount
        await tx.user.update({
          where: { id: deleted.authorUserId },
          data: {
            pollsCreatedCount: {
              decrement: 1,
            },
          },
        });

        return deleted;
      });
+   } catch (error) {
+     // Log the error for debugging
+     console.error('Error deleting poll:', error);
+     throw new BadRequestException('Failed to delete poll');
+   }
  }

138-138: Add JSDoc comments to document the method.

Adding documentation would help other developers understand the purpose and behavior of this method.

+  /**
+   * Deletes a poll if the requesting user is the author.
+   * This operation will cascade delete related votes and user actions.
+   * 
+   * @param userId - The ID of the user requesting the deletion
+   * @param pollId - The ID of the poll to delete
+   * @returns The deleted poll object
+   * @throws BadRequestException if poll doesn't exist or user is not authorized
+   */
  async deletePoll(userId: number, pollId: number) {

146-148: Consider using more specific exception classes for authorization failures.

NestJS provides more specific exception classes like ForbiddenException or UnauthorizedException that would be more appropriate for authorization failures.

    if (poll.authorUserId !== userId) {
-      throw new Error('User Not Authorized');
+      throw new ForbiddenException('User is not authorized to delete this poll');
    }

Note: You would need to add the import for ForbiddenException from @nestjs/common.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 460b8b5 and 4642eba.

📒 Files selected for processing (2)
  • src/poll/poll.controller.ts (1 hunks)
  • src/poll/poll.service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/poll/poll.controller.ts
🔇 Additional comments (2)
src/poll/poll.service.ts (2)

150-168: The transaction implementation is correct and maintains data consistency.

The method correctly uses a transaction to ensure that both the poll deletion and the user's poll count update are performed atomically, which maintains data consistency.


138-169:

Details

✅ Verification successful

Verify that related records are properly cascaded.

According to the PR summary, cascading delete was implemented in the database schema. This method relies on that behavior to automatically delete related votes and user actions when a poll is deleted. Ensure that the Prisma schema and migrations properly set up these cascading relationships.


🏁 Script executed:

#!/bin/bash
# Check for cascading delete configuration in Prisma schema
echo "Checking Prisma schema for cascading delete configuration..."
fd --type f "schema.prisma" --exec cat {} | grep -A 10 "model Vote" | grep "onDelete"
fd --type f "schema.prisma" --exec cat {} | grep -A 10 "model UserAction" | grep "onDelete"

# Check migration files for cascading delete
echo "Checking migration files for cascading delete..."
fd --extension sql --exec grep -l "CASCADE" {}

Length of output: 783


Cascading Delete Behavior Validated

I verified that the Prisma schema correctly configures cascading deletes for related records. The schema shows that for both Vote and UserAction models the relationships include onDelete: Cascade, and the migration files confirm CASCADE is applied. No further changes are required for proper cascading behavior in this deletion method.

Comment on lines +137 to +169

async deletePoll(userId: number, pollId: number) {
const poll = await this.databaseService.poll.findUnique({
where: { pollId },
});

if (!poll) {
throw new Error('Poll not found');
}
if (poll.authorUserId !== userId) {
throw new Error('User Not Authorized');
}

return this.databaseService.$transaction(async (tx) => {
const deleted = await tx.poll.delete({
where: {
pollId,
},
});

// Update user's pollsCreatedCount
await tx.user.update({
where: { id: deleted.authorUserId },
data: {
pollsCreatedCount: {
decrement: 1,
},
},
});

return deleted;
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling by using NestJS exception classes.

The method uses generic Error class for exceptions instead of NestJS's built-in exception classes. This is inconsistent with the rest of the service which uses BadRequestException.

  async deletePoll(userId: number, pollId: number) {
    const poll = await this.databaseService.poll.findUnique({
      where: { pollId },
    });

    if (!poll) {
-      throw new Error('Poll not found');
+      throw new BadRequestException('Poll not found');
    }
    if (poll.authorUserId !== userId) {
-      throw new Error('User Not Authorized');
+      throw new BadRequestException('User Not Authorized');
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async deletePoll(userId: number, pollId: number) {
const poll = await this.databaseService.poll.findUnique({
where: { pollId },
});
if (!poll) {
throw new Error('Poll not found');
}
if (poll.authorUserId !== userId) {
throw new Error('User Not Authorized');
}
return this.databaseService.$transaction(async (tx) => {
const deleted = await tx.poll.delete({
where: {
pollId,
},
});
// Update user's pollsCreatedCount
await tx.user.update({
where: { id: deleted.authorUserId },
data: {
pollsCreatedCount: {
decrement: 1,
},
},
});
return deleted;
});
}
async deletePoll(userId: number, pollId: number) {
const poll = await this.databaseService.poll.findUnique({
where: { pollId },
});
if (!poll) {
throw new BadRequestException('Poll not found');
}
if (poll.authorUserId !== userId) {
throw new BadRequestException('User Not Authorized');
}
return this.databaseService.$transaction(async (tx) => {
const deleted = await tx.poll.delete({
where: {
pollId,
},
});
// Update user's pollsCreatedCount
await tx.user.update({
where: { id: deleted.authorUserId },
data: {
pollsCreatedCount: {
decrement: 1,
},
},
});
return deleted;
});
}

Copy link
Copy Markdown
Member

@RamRamez RamRamez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RamRamez RamRamez merged commit ca12e91 into develop Apr 3, 2025
1 check passed
@RamRamez RamRamez deleted the delete-poll branch April 3, 2025 16:58
@coderabbitai coderabbitai bot mentioned this pull request Apr 3, 2025
@coderabbitai coderabbitai bot mentioned this pull request May 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants