Skip to content

Conversation

@yamcodes
Copy link
Contributor

@yamcodes yamcodes commented Mar 18, 2025

Description

Implement comment feature for articles.

Builds on #129 so it's better to merge that first.


PR Checklist

  • Read the Developer's Guide in CONTRIBUTING.md
  • Use a concise title to represent the changes introduced in this PR
  • Provide a detailed description of the changes introduced in this PR, and, if necessary, some screenshots
  • Reference an issue or discussion where the feature or changes have been previously discussed
  • Add a failing test that passes with the changes introduced in this PR, or explain why it's not feasible
  • Add documentation for the feature or changes introduced in this PR to the docs; you can run them with bun docs

Summary by CodeRabbit

  • New Features
    • Expanded article capabilities to include creation, updates, deletions, and personalized feeds.
    • Introduced full comment management, allowing users to add, view, and delete comments on articles.
    • Improved profile retrieval for a more dynamic and accurate display of user information.
    • Added functionality to manage favorited articles and their associated comments.
    • Enhanced schema definitions for articles and comments, providing a robust framework for management.
    • New methods for retrieving user profiles based on user ID.

@yamcodes yamcodes requested a review from Hajbo March 18, 2025 20:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2025

Walkthrough

The changes introduce new database schemas for managing articles, favorites, and comments. New tables and relationships are defined, along with comprehensive schema definitions and types for inserting, updating, and returning article and comment data. The articles module integrates a CommentsRepository and CommentsService, while the articles plugin defines several RESTful routes for article and comment operations. Additionally, updates to the profiles repository and service add methods for retrieving profiles by user ID, enhancing overall article management and comment functionalities.

Changes

File(s) Summary
src/articles/articles.model.ts, src/articles/articles.schema.ts Added new tables (articles, favorite_articles, comments), relationships, and comprehensive schema/type definitions for article management.
src/articles/articles.module.ts, src/articles/articles.plugin.ts Integrated CommentsRepository and CommentsService into the articles module; added new REST routes for handling articles and comment operations.
src/articles/comments/comments.repository.ts, src/articles/comments/comments.schema.ts, src/articles/comments/comments.service.ts Introduced a dedicated CommentsRepository with CRUD methods, comment schemas, and a CommentsService to manage comment creation, retrieval, and deletion.
src/profiles/profiles.repository.ts, src/profiles/profiles.service.ts Added a new asynchronous method findByUserId to retrieve user profiles by ID, enhancing profile lookup capabilities.

Sequence Diagram(s)

Comment Creation Flow

sequenceDiagram
    participant U as User
    participant AP as Articles Plugin
    participant CS as Comments Service
    participant CR as Comments Repository
    participant DB as Database

    U->>AP: POST /articles/:slug/comments (with comment data)
    AP->>CS: createComment(articleSlug, commentBody, userId)
    CS->>CR: create(commentData)
    CR->>DB: INSERT comment record
    DB-->>CR: Insertion confirmation
    CR-->>CS: New comment data
    CS-->>AP: ReturnedComment with author details
    AP-->>U: Response with created comment
Loading

Comment Deletion Flow

sequenceDiagram
    participant U as User
    participant AP as Articles Plugin
    participant CS as Comments Service
    participant CR as Comments Repository
    participant DB as Database

    U->>AP: DELETE /articles/:slug/comments/:id
    AP->>CS: deleteComment(articleSlug, commentId, userId)
    CS->>CR: delete(commentId, userId)
    CR->>DB: DELETE comment WHERE id = commentId AND authorId = userId
    DB-->>CR: Deletion confirmation
    CR-->>CS: Deletion status
    CS-->>AP: Success response
    AP-->>U: Comment deletion response
Loading

Poem

I'm a little rabbit hopping with glee,
Code carrots sprout in the module tree.
Articles, comments, and schemas so neat,
REST routes and services make it complete.
I munch on changes with a joyful heart,
Bounding along—each line a work of art! 🐰
Cheers to growth in every code part!

✨ 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 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.

@yamcodes yamcodes linked an issue Mar 18, 2025 that may be closed by this pull request
@yamcodes yamcodes added the enhancement New feature or request label Mar 18, 2025
@yamcodes yamcodes self-assigned this Mar 18, 2025
@yamcodes
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@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: 3

🧹 Nitpick comments (7)
src/articles/comments/comments.schema.ts (1)

32-32: DeleteCommentResponse stub is ready.
You may consider including a success/message field if the client needs explicit confirmation beyond HTTP status codes.

src/articles/comments/comments.service.ts (1)

114-120: getAuthorUsername is a clear helper.
Throwing BadRequestError when the user is missing might be better expressed as NotFoundError for clarity, if your error semantics differentiate. Otherwise, it is acceptable.

-  throw new BadRequestError(\`User with id \${userId} not found\`);
+  throw new NotFoundError(\`User with id \${userId} not found\`);
src/articles/articles.plugin.ts (2)

145-166: Consider handling non-existent article case.

The GET route implementation is correctly fetching comments with proper parameter typing. Similar to the POST route, consider adding error handling for cases where the article doesn't exist.

Also, the ternary expression to handle the userId could be simplified using optional chaining:

 return {
   comments: await store.commentsService.getComments(
     params.slug,
-    userId === null ? undefined : userId,
+    userId ?? undefined,
   ),
 };

168-188: Add validation for numeric ID.

While Number.parseInt handles conversion from string to number, it doesn't validate that the result is a valid number. Consider adding explicit validation to handle cases where the ID cannot be properly parsed.

 async ({ params, store, request }) => {
+  const commentId = Number.parseInt(params.id, 10);
+  if (Number.isNaN(commentId)) {
+    throw new Error('Invalid comment ID');
+  }
   await store.commentsService.deleteComment(
     params.slug,
-    Number.parseInt(params.id, 10),
+    commentId,
     await store.authService.getUserIdFromHeader(request.headers),
   );
   return {};
 },
src/articles/articles.schema.ts (1)

32-49: Consider using a more specific type for author.

The schema uses Type.Any() for the author field, which reduces type safety. Consider using a more specific type definition for better validation and IDE support.

 Type.Object({
-  author: Type.Any(),
+  author: Type.Object({
+    username: Type.String(),
+    bio: Type.Optional(Type.String()),
+    image: Type.Optional(Type.String()),
+    following: Type.Boolean(),
+  }),
 }),
src/articles/comments/comments.repository.ts (2)

10-17: Add error handling to createComment method.

The method looks good but doesn't handle potential insertion errors. Consider adding try/catch to provide more meaningful error messages.

 async createComment(commentData: CommentToCreate) {
+  try {
     const [comment] = await this.db
       .insert(comments)
       .values(commentData)
       .returning();
 
     return comment;
+  } catch (error) {
+    console.error('Failed to create comment:', error);
+    throw new Error('Failed to create comment');
+  }
 }

38-45: Consider moving getArticleBySlug to an articles repository.

This method seems out of place in a comments repository. Consider moving it to an articles repository and injecting that dependency instead, to maintain separation of concerns.

Also, add handling for when the article is not found:

 async getArticleBySlug(slug: string) {
   const [article] = await this.db
     .select()
     .from(articles)
     .where(eq(articles.slug, slug));

+  if (!article) {
+    throw new Error(`Article with slug ${slug} not found`);
+  }
+
   return article;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ca6358e and b919017.

📒 Files selected for processing (7)
  • src/articles/articles.model.ts (2 hunks)
  • src/articles/articles.module.ts (3 hunks)
  • src/articles/articles.plugin.ts (3 hunks)
  • src/articles/articles.schema.ts (3 hunks)
  • src/articles/comments/comments.repository.ts (1 hunks)
  • src/articles/comments/comments.schema.ts (1 hunks)
  • src/articles/comments/comments.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (6)
src/articles/articles.module.ts (2)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7:52)
src/articles/comments/comments.service.ts (1) (1)
  • CommentsService (7:121)
src/articles/articles.model.ts (1)
src/users/users.model.ts (1) (1)
  • users (12:23)
src/articles/comments/comments.repository.ts (2)
src/articles/comments/comments.schema.ts (1) (1)
  • CommentToCreate (9:12)
src/articles/articles.model.ts (2) (2)
  • comments (73:84)
  • articles (14:26)
src/articles/articles.schema.ts (1)
src/articles/articles.model.ts (1) (1)
  • favoriteArticles (42:55)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7:52)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (22:22)
  • CommentToCreate (9:12)
src/articles/articles.model.ts (1) (1)
  • comments (73:84)
src/articles/articles.plugin.ts (1)
src/articles/comments/comments.schema.ts (4) (4)
  • AddCommentSchema (3:7)
  • ReturnedCommentResponse (24:26)
  • ReturnedCommentsResponse (28:30)
  • DeleteCommentResponse (32:32)
🔇 Additional comments (31)
src/articles/articles.module.ts (4)

1-2: Imports look good.
The new imports ensure the CommentsRepository and CommentsService are available. Make sure that the path aliases (@/articles/...) are properly configured in your tsconfig.json.


25-29: Service instantiation is consistent.
CommentsService correctly depends on commentsRepository, profilesService, and usersRepository. This ensures it can manage comments and retrieve author profiles as needed.


31-35: New comments service state is integrated correctly.
Providing commentsService in the Elysia state ensures it’s accessible throughout the module. This aligns with the existing pattern for articlesService and authService.


14-14:

❓ Verification inconclusive

Repository instantiation is correct.
Using the existing db instance to create commentsRepository is consistent with the pattern used for other repositories. Confirm that the migrations for the comments table are already applied.


🏁 Script executed:

#!/bin/bash
# Verify that the 'comments' table exists in the database schema
# using a relevant DB introspection query or migration check.
# (Assuming there's a CLI to run migrations or introspect the schema.)
npm run db:migrate:status

Length of output: 261


Attention: Manual Verification Needed for Migration Check

The instantiation of commentsRepository using the existing db instance is correct and follows the repository pattern used elsewhere. However, the automated check for the comments table migration failed because the script db:migrate:status isn’t defined in the package scripts. Please manually verify that the migrations for the comments table have been applied or update the migration command in the repository’s configuration.

  • Confirm manually (or with an alternative script) that the comments table exists.
  • Consider adding or correcting the migration status script in the package.json.
src/articles/articles.model.ts (4)

37-39: New comments relation aligns with the table definition.
Declaring comments: many(comments) under articleRelations establishes a clear one-to-many relationship between articles and comments. Ensure that the relationName: 'articleComments' is referenced consistently in the codebase.


72-72: No substantive change.
This is a blank line insertion.


73-84: Definition of the comments table appears accurate.
The schema matches standard patterns of referencing articles.id and users.id. Timestamps defaulting to CURRENT_TIMESTAMP is consistent with the existing approach in other tables.


86-97: commentRelations is well-defined.
The one-to-many relationships to articles and users are appropriately declared using fields and references. This ensures that model relationships for comments are properly maintained.

src/articles/comments/comments.schema.ts (7)

1-2: Import statements are consistent with TypeBox usage.
Having type Static, Type from @sinclair/typebox is standard for defining schemas.


3-7: Structured “comment” property in AddCommentSchema.
Nesting the body field under comment matches typical RealWorld style payloads. No issues noted.


9-12: CommentToCreate merges schema props with DB fields.
Combining the user-supplied body with authorId and articleId is clear and straightforward.


14-20: CommentSchema definition is comprehensive.
Capturing id, body, timestamps, plus an author field of type Type.Any() provides flexibility for nested author data.


22-22: ReturnedComment correctness.
Exporting ReturnedComment based on CommentSchema enables type-safe contract for returned data.


24-26: ReturnedCommentResponse aligns with typical REST responses.
Wrapping the comment in a top-level comment object is consistent with standard patterns.


28-30: ReturnedCommentsResponse for multiple comments.
The array structure is appropriate for listing multiple comments in a consistent format.

src/articles/comments/comments.service.ts (6)

1-3: Imports for errors, profiles, and users are correct.
These references align with the constructor dependencies.


4-5: comments.repository and comments.schema usage.
Properly typed references ensure stronger type safety when creating and returning comments.


7-12: Constructor is logically consistent.
Accepting commentsRepository, profilesService, and usersRepository centralizes all needed integrations.


14-45: createComment handles validation and creation well.

  1. Checks whether the article exists.
  2. Correctly merges user input with authorId and articleId.
  3. Fetches and attaches the author’s profile.
  4. Returns the comment data in the expected format.

47-80: getComments returns an enriched list of comments.
The function retrieves comments, fetches each author’s profile, and formats date fields to ISO strings. This approach is solid and meets typical RealWorld-style expectations.


82-112: deleteComment boundaries are well-enforced.

  1. Ensures the article exists.
  2. Validates the target comment and ownership via comment.authorId.
  3. Invokes the repository deletion upon confirmation.
src/articles/articles.plugin.ts (2)

11-17: Good job with the proper imports.

The necessary schema imports for the new comment functionality have been correctly set up.


75-75: Fixed typo in summary.

Good catch on fixing "Artifle Feed" to "Article Feed".

src/articles/articles.schema.ts (5)

1-1: Good use of absolute import path.

Using absolute import paths improves maintainability and makes refactoring easier.


30-30: Updated type definition matches schema changes.

The simplified type definition correctly aligns with the changes to UpdateArticleSchema.


55-55: Good addition of DeleteArticleResponse.

Adding a specific response type for delete operations is good practice, even if it's just an empty object.


67-67: Good export of ArticleFavoritedBy type.

Making this type exported improves reusability across the codebase.


26-26:

✅ Verification successful

Verify the removal of tagList from UpdateArticleSchema.

The schema now only allows updating title, description, and body, but no longer includes tagList. Make sure this is intentional and aligns with your business requirements.


🏁 Script executed:

#!/bin/bash
# Check if tagList updates are handled elsewhere or if this is an intentional change

# Look for any tagList updates in article services
rg -A 5 -B 5 "tagList.*update" --type ts

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Look for any occurrence of "tagList" in the articles.schema.ts file to verify its complete removal
rg "tagList" src/articles/articles.schema.ts

# Additionally, search for "tagList" across all TypeScript files in the repository
rg "tagList" --type ts

Length of output: 666


Update Schema Clarification:
The removal of tagList from the UpdateArticleSchema is confirmed as intentional. The update schema is defined using Type.Pick(insertArticleSchemaRaw, ['title', 'description', 'body']), meaning that only the three fields of title, description, and body can be updated. While tagList remains defined in other parts of the schema (used for article creation and stored in the model), its exclusion from the update schema aligns with the business requirements.

src/articles/comments/comments.repository.ts (3)

1-6: Good imports and organization.

The imports are well organized with clear separation between external libraries and internal modules.


7-9: Good repository pattern implementation.

The class follows the repository pattern with dependency injection, which makes testing easier.


28-36: Good implementation of getCommentsByArticleId.

The method correctly retrieves comments for an article and sorts them by creation date in descending order.

Copy link
Collaborator

@Hajbo Hajbo left a comment

Choose a reason for hiding this comment

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

Looking good!

@yamcodes yamcodes mentioned this pull request Mar 19, 2025
4 tasks
Copy link
Contributor

@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

♻️ Duplicate comments (2)
src/articles/comments/comments.service.ts (2)

14-45: 🛠️ Refactor suggestion

Optimize database queries when retrieving author information

The current implementation makes two separate database queries to get author information:

  1. First fetching the username with getAuthorUsername()
  2. Then fetching the profile with profilesService.findByUsername()

This could be optimized to reduce database load.

Consider refactoring the ProfilesService to include a findById method that directly accepts a user ID:

- const authorUsername = await this.getAuthorUsername(comment.authorId);
- const authorProfile = await this.profilesService.findByUsername(
-   userId,
-   authorUsername,
- );
+ const authorProfile = await this.profilesService.findById(userId, comment.authorId);

47-80: 🛠️ Refactor suggestion

Performance concern: N+1 query problem in comment retrieval

For each comment, you're making two separate database queries:

  1. Getting the username for each comment author
  2. Getting the profile information for each author

This results in 2N+1 queries for N comments, which can create significant performance issues as the number of comments grows.

Consider refactoring to batch these operations:

  const comments = await this.commentsRepository.findManyByArticleId(article.id);
+ 
+ // Get unique author IDs
+ const authorIds = [...new Set(comments.map(comment => comment.authorId))];
+ 
+ // Fetch all required profiles in one or two queries
+ const authorProfiles = await this.profilesService.findManyByIds(currentUserId || 0, authorIds);
  
  const returnedComments = await Promise.all(
    comments.map(async (comment) => {
-      const authorUsername = await this.getAuthorUsername(comment.authorId);
-      const authorProfile = await this.profilesService.findByUsername(
-        currentUserId || 0,
-        authorUsername,
-      );
+      const authorProfile = authorProfiles.find(profile => profile.user.id === comment.authorId);

      return {
        id: comment.id,
        body: comment.body,
        createdAt: comment.createdAt,
        updatedAt: comment.updatedAt,
        author: authorProfile.profile,
      };
    }),
  );
🧹 Nitpick comments (1)
src/articles/comments/comments.service.ts (1)

114-120: Consider caching user information for repeated lookups

The getAuthorUsername method is called multiple times throughout the service. If user information rarely changes during a request lifecycle, consider implementing a simple in-memory cache to avoid redundant database queries.

+ private userCache: Map<number, string> = new Map();

  private async getAuthorUsername(userId: number): Promise<string> {
+   if (this.userCache.has(userId)) {
+     return this.userCache.get(userId)!;
+   }
    
    const user = await this.usersRepository.findById(userId);
    if (!user) {
      throw new BadRequestError(`User with id ${userId} not found`);
    }
+   this.userCache.set(userId, user.username);
    return user.username;
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 23ec6aa and a6cc3fe.

📒 Files selected for processing (2)
  • src/articles/comments/comments.schema.ts (1 hunks)
  • src/articles/comments/comments.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
src/articles/comments/comments.schema.ts (1)
src/articles/articles.model.ts (1) (1)
  • comments (73-84)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7-46)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
src/articles/articles.model.ts (1) (1)
  • comments (73-84)
🔇 Additional comments (6)
src/articles/comments/comments.service.ts (2)

1-12: Well-structured class design with appropriate dependencies

The service class is well-organized with proper dependency injection through the constructor. All dependencies are correctly typed and marked as private readonly, following good TypeScript practices.


82-112: Robust validation in the delete operation

The delete operation includes comprehensive validation:

  1. Verifies the article exists
  2. Verifies the comment exists
  3. Confirms the comment belongs to the specified article
  4. Ensures the user is authorized (is the comment author)

This thorough approach provides proper security and data integrity.

src/articles/comments/comments.schema.ts (4)

1-8: Good use of schema generation utilities

The code properly leverages TypeBox and Drizzle-TypeBox to generate base schemas from the database model, which ensures type consistency between the database and API layers.


9-18: Well-designed input schema and database type

The AddCommentSchema correctly models the client input (just the comment body), while CommentToCreate extends it with server-side information needed for storage. This separation of concerns is a good practice that keeps the API clean and the implementation flexible.


20-38: Security-conscious response schema design

The ReturnedCommentSchema properly omits sensitive internal fields (articleId, authorId) and carefully selects which user information to expose, excluding sensitive data like passwords and emails. The inclusion of the following property is useful for the UI to determine relationship status.


40-48: Consistent response schema pattern

The response schemas follow a consistent pattern of wrapping data in named properties (comment or comments), which is good for API consistency and future extensibility. The empty DeleteCommentResponse is appropriate for operations that only need to signal success.

- Updated CommentsService to use authorId directly when fetching author profile.
- Introduced findByUserId method in ProfilesRepository to retrieve user profiles by their ID.
- Enhanced ProfilesService with findByUserId method for better error handling and profile response generation.
Copy link
Contributor

@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

♻️ Duplicate comments (1)
src/articles/comments/comments.service.ts (1)

56-76: 🛠️ Refactor suggestion

Consider optimizing comment retrieval to reduce database queries.

The current implementation makes a separate database query for each comment to retrieve the author username and profile. This could become inefficient with a large number of comments.

Consider refactoring this to use a more efficient query approach:

  1. Fetch all comments with author IDs
  2. Get all unique author IDs
  3. Batch retrieve author profiles in a single query
  4. Map the profiles back to comments

This would reduce the number of database queries from O(n) to O(1) where n is the number of comments.

🧹 Nitpick comments (4)
src/profiles/profiles.repository.ts (1)

19-28: Optimization suggestion: Consider using findFirst instead of findMany when querying by primary key.

The implementation is correct, but since you're querying by the primary key (users.id), which should return at most one result, using findFirst would be more semantically appropriate and potentially more efficient than using findMany and then extracting the first element.

  async findByUserId(targetUserId: number) {
-    const result = await this.db.query.users.findMany({
+    const result = await this.db.query.users.findFirst({
      where: eq(users.id, targetUserId),
      with: { followers: true },
    });
-    if (result.length === 0) {
+    if (!result) {
      return null;
    }
-    return result[0];
+    return result;
  }
src/articles/comments/comments.service.ts (3)

31-43: Simplify author profile retrieval.

When creating a comment, you're passing the same user ID twice to findByUserId, which is redundant. Since the comment author is the current user, you can simplify this code.

  const comment = await this.commentsRepository.create(commentData);
  const authorProfile = await this.profilesService.findByUserId(
    userId,
-    comment.authorId,
+    userId,
  );

21-23: Standardize error types for consistency.

The service uses a mix of error types - BadRequestError for resources not found and AuthorizationError for permission issues. It would be more consistent and in line with REST API conventions to use more specific error types:

  • NotFoundError for resources not found
  • BadRequestError for invalid requests
  • AuthorizationError for permission issues

Replace BadRequestError with NotFoundError when resources are not found:

  if (!article) {
-    throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+    throw new NotFoundError(`Article with slug ${articleSlug} not found`);
  }

  // And similar changes for other not found errors

Also applies to: 52-54, 88-90, 94-96, 98-102, 104-108


1-5: Import NotFoundError for consistent error handling.

Since you're already importing errors, make sure to import NotFoundError for use with resource not found scenarios.

-import { AuthorizationError, BadRequestError } from '@errors';
+import { AuthorizationError, BadRequestError, NotFoundError } from '@errors';
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a6cc3fe and 91447f6.

📒 Files selected for processing (3)
  • src/articles/comments/comments.service.ts (1 hunks)
  • src/profiles/profiles.repository.ts (1 hunks)
  • src/profiles/profiles.service.ts (2 hunks)
🧰 Additional context used
🧬 Code Definitions (3)
src/profiles/profiles.repository.ts (1)
src/users/users.model.ts (1) (1)
  • users (12-23)
src/profiles/profiles.service.ts (1)
src/profiles/profiles.schema.ts (1) (1)
  • ParsedProfileSchema (27-27)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7-46)
src/profiles/profiles.service.ts (1) (1)
  • ProfilesService (6-81)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
🔇 Additional comments (5)
src/profiles/profiles.service.ts (2)

20-26: LGTM! Implementation of findByUserId method.

The method follows the same pattern as the existing findByUsername method, maintaining consistency in the codebase. It properly handles error cases by throwing a NotFoundError when a user is not found.


63-77: Well-handled nullable parameter type.

The updated implementation correctly handles the case where currentUserId is null by returning false for the following field, which is a sensible default. This enhances the robustness of the method.

src/articles/comments/comments.service.ts (3)

14-44: LGTM: Comment creation implementation.

The implementation is thorough in validating the article's existence, creating the comment with appropriate metadata, and retrieving author profile information for the response.


81-111: LGTM: Comment deletion implementation.

The implementation is comprehensive in its error handling, verifying:

  1. Article existence
  2. Comment existence
  3. Comment belongs to the specified article
  4. User has permission to delete the comment

This ensures robust validation before performing the deletion operation.


113-119: LGTM: Helper method for retrieving author username.

The private helper method is well-implemented and properly handles the case when a user is not found.

- Updated the findById method in CommentsRepository to include author information such as id, username, bio, and image.
- Added the ability to fetch the author's followers alongside their details.
- Updated CommentsService to directly use authorId when fetching author profiles, improving clarity and efficiency.
- Replaced the getAuthorUsername method with a direct call to findByUserId in ProfilesService.
Copy link
Contributor

@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

♻️ Duplicate comments (2)
src/articles/comments/comments.service.ts (2)

46-78: 🛠️ Refactor suggestion

Optimize database queries for fetching comments.

The getComments method currently makes a separate database query for each comment to fetch the author's profile. For articles with many comments, this could lead to a significant number of database queries (N+1 problem).

Consider optimizing this by:

  1. Fetching all unique author IDs from the comments
  2. Making a single query to get all profiles at once
  3. Mapping the profiles to their respective comments
async getComments(
  articleSlug: string,
  currentUserId?: number,
): Promise<ReturnedComment[]> {
  const article = await this.commentsRepository.findBySlug(articleSlug);

  if (!article) {
    throw new BadRequestError(`Article with slug ${articleSlug} not found`);
  }

  const comments = await this.commentsRepository.findManyByArticleId(
    article.id,
  );

+ // Get unique author IDs
+ const authorIds = [...new Set(comments.map(comment => comment.authorId))];
+ 
+ // Fetch all profiles at once
+ const authorProfiles = await Promise.all(
+   authorIds.map(authorId => 
+     this.profilesService.findByUserId(
+       currentUserId === undefined ? null : currentUserId,
+       authorId
+     )
+   )
+ );
+ 
+ // Create a map for quick profile lookup
+ const profileMap = new Map();
+ authorIds.forEach((authorId, index) => {
+   profileMap.set(authorId, authorProfiles[index].profile);
+ });

  const returnedComments = await Promise.all(
    comments.map(async (comment) => {
-     const authorProfile = await this.profilesService.findByUserId(
-       currentUserId || 0,
-       comment.authorId,
-     );

      return {
        id: comment.id,
        body: comment.body,
        createdAt: comment.createdAt,
        updatedAt: comment.updatedAt,
-       author: authorProfile.profile,
+       author: profileMap.get(comment.authorId),
      };
    }),
  );

  return returnedComments;
}

63-63: ⚠️ Potential issue

Improve handling of undefined currentUserId.

Using currentUserId || 0 is problematic because 0 could be a valid user ID, which would be treated the same as if currentUserId were undefined. This could lead to incorrect following status.

- const authorProfile = await this.profilesService.findByUserId(
-   currentUserId || 0,
-   comment.authorId,
- );
+ const authorProfile = await this.profilesService.findByUserId(
+   currentUserId === undefined ? null : currentUserId,
+   comment.authorId,
+ );
🧹 Nitpick comments (4)
src/articles/comments/comments.service.ts (4)

112-118: Remove unused private method.

The getAuthorUsername method is defined but not used anywhere in this class. Consider removing unused methods to improve code maintainability.

- private async getAuthorUsername(userId: number): Promise<string> {
-   const user = await this.usersRepository.findById(userId);
-   if (!user) {
-     throw new BadRequestError(`User with id ${userId} not found`);
-   }
-   return user.username;
- }

If this method is intended for future use, consider adding a TODO comment explaining its purpose.


19-23: Duplicate article validation logic across methods.

The same article validation logic is repeated in all three public methods. Consider extracting this common functionality into a private helper method.

+ private async getArticleBySlug(articleSlug: string) {
+   const article = await this.commentsRepository.findBySlug(articleSlug);
+   if (!article) {
+     throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+   }
+   return article;
+ }

async createComment(
  articleSlug: string,
  commentBody: { body: string },
  userId: number,
): Promise<ReturnedComment> {
-  const article = await this.commentsRepository.findBySlug(articleSlug);
-
-  if (!article) {
-    throw new BadRequestError(`Article with slug ${articleSlug} not found`);
-  }
+  const article = await this.getArticleBySlug(articleSlug);

  // Rest of the method...
}

// Apply similar changes to getComments and deleteComment methods

Also applies to: 50-54, 85-89


38-43: Duplicate comment response structure.

The same structure for formatting a returned comment is duplicated in both createComment and getComments methods. Consider extracting this into a private helper method.

+ private formatComment(comment: any, authorProfile: any): ReturnedComment {
+   return {
+     id: comment.id,
+     body: comment.body,
+     createdAt: comment.createdAt,
+     updatedAt: comment.updatedAt,
+     author: authorProfile.profile,
+   };
+ }

async createComment(
  // ...
) {
  // ...
  
-  return {
-    id: comment.id,
-    body: comment.body,
-    createdAt: comment.createdAt,
-    updatedAt: comment.updatedAt,
-    author: authorProfile.profile,
-  };
+  return this.formatComment(comment, authorProfile);
}

// Apply similar changes to the comments.map callback in getComments

Also applies to: 67-73


109-109: Consider handling delete operation result.

The deleteComment method doesn't check if the delete operation was successful. The repository's delete method likely returns information about the number of rows affected.

- await this.commentsRepository.delete(commentId, userId);
+ const result = await this.commentsRepository.delete(commentId, userId);
+ if (!result || result.count === 0) {
+   throw new BadRequestError('Failed to delete the comment');
+ }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 83ab1c4 and 41ee814.

📒 Files selected for processing (1)
  • src/articles/comments/comments.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7-59)
src/profiles/profiles.service.ts (1) (1)
  • ProfilesService (6-81)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
🔇 Additional comments (1)
src/articles/comments/comments.service.ts (1)

91-107: Great security checks to verify comment ownership.

The implementation properly validates the comment's existence, association with the article, and user authorization before deletion. This is a good security practice that prevents unauthorized deletion of comments.

@yamcodes yamcodes mentioned this pull request Mar 20, 2025
4 tasks
…ng and documentation

- Added JSDoc comments to the getComments method in CommentsService for better clarity on parameters and return values.
- Updated the findByUserId method in ProfilesService to accept a nullable currentUserId, improving type safety.
Copy link
Contributor

@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 (2)
src/articles/comments/comments.service.ts (2)

21-22: Use more specific error types for missing resources.

Throughout the file, missing resources (article or comment) are reported as BadRequestError. Consider using NotFoundError (or a similar 404-focused error) to better reflect the error cause when these resources are not present or do not belong to the specified article.

Example changes you might apply:

- throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+ throw new NotFoundError(`Article with slug ${articleSlug} not found`);

- throw new BadRequestError(`Comment with id ${commentId} not found`);
+ throw new NotFoundError(`Comment with id ${commentId} not found`);

- throw new BadRequestError(
-   `Comment with id ${commentId} does not belong to article ${articleSlug}`,
- );
+ throw new NotFoundError(
+   `Comment with id ${commentId} does not belong to article ${articleSlug}`,
+ );

Also applies to: 59-60, 99-101, 103-107


66-81: Be mindful of potential N+1 database queries.

For each comment, you're making a separate call to retrieve the author profile. If the number of comments is large, this can degrade performance significantly. Consider fetching all authors in one go, or using a join in the repository to avoid multiple queries.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 41ee814 and f8e7faa.

📒 Files selected for processing (2)
  • src/articles/comments/comments.service.ts (1 hunks)
  • src/profiles/profiles.service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/profiles/profiles.service.ts
🧰 Additional context used
🧠 Learnings (1)
src/articles/comments/comments.service.ts (1)
Learnt from: yamcodes
PR: agnyz/bedstack#134
File: src/articles/comments/comments.service.ts:32-35
Timestamp: 2025-03-20T20:01:10.732Z
Learning: In the comment creation flow in src/articles/comments/comments.service.ts, the code correctly uses the newly created comment's authorId when fetching the author profile, even though this is set from the userId parameter. This provides better semantic clarity than directly using userId again.
🧬 Code Definitions (1)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (7-59)
src/profiles/profiles.service.ts (1) (1)
  • ProfilesService (6-81)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
🔇 Additional comments (2)
src/articles/comments/comments.service.ts (2)

1-12: Implementation looks solid.

No issues found in the imports and constructor. Dependency injection is clear and follows standard best practices.


32-35: Good semantic clarity when retrieving the author profile.

Using comment.authorId (derived from userId) to fetch the author’s profile is consistent with your previous learnings. This approach is fine and emphasizes the logic that the author of the comment is the user making the request.

@yamcodes yamcodes requested a review from Hajbo March 20, 2025 20:33
Copy link
Collaborator

@Hajbo Hajbo left a comment

Choose a reason for hiding this comment

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

LGTM! We are almost there!🚀

…retrieval

- Add a new method in CommentsRepository to find comments by article ID, optimized to include author details and their followers.
- Simplify comment mapping in CommentsService to directly include author information, greatly improving performance from O(n*(k+t)) to O(n).
Doing this since we no longer need the extra fetching (no use case).

- Remove unnecessary author details fetching in the findById method.
- Add JSDoc.
Copy link
Contributor

@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 (2)
src/articles/comments/comments.service.ts (2)

58-60: Prefer a consistent error type for missing article.

As with the createComment method, you may want to throw a NotFoundError here to make it clear that the article does not exist.


89-91: Inconsistent error usage for missing comment.

Similar to missing article, consider throwing a NotFoundError instead of a BadRequestError when the comment is not found.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f8e7faa and 18114bd.

📒 Files selected for processing (2)
  • src/articles/comments/comments.repository.ts (1 hunks)
  • src/articles/comments/comments.service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/articles/comments/comments.repository.ts
🧰 Additional context used
🧠 Learnings (1)
src/articles/comments/comments.service.ts (1)
Learnt from: yamcodes
PR: agnyz/bedstack#134
File: src/articles/comments/comments.service.ts:32-35
Timestamp: 2025-03-20T20:01:10.732Z
Learning: In the comment creation flow in src/articles/comments/comments.service.ts, the code correctly uses the newly created comment's authorId when fetching the author profile, even though this is set from the userId parameter. This provides better semantic clarity than directly using userId again.
🧬 Code Definitions (1)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (6-79)
src/profiles/profiles.service.ts (1) (1)
  • ProfilesService (6-81)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
🔇 Additional comments (4)
src/articles/comments/comments.service.ts (4)

1-6: Module imports and constructors look good.

No correctness issues. The dependencies (ProfilesService, UsersRepository, CommentsRepository) are appropriately injected and stored for later use.


32-35: Fetching author profile using the newly created comment’s authorId is correct.

This implementation is consistent with the logic that comment.authorId should match the user who created the comment, and provides clarity.


66-79: Verify that comment.author is always present.

Given the repository's with: { author: ... } clause, comment.author should exist. However, if the DB query fails to return author details (e.g., orphaned records), this could cause runtime errors. Consider safety checks or confirming that the repository enforces referential integrity.


105-106: Authorization check is accurate.

Throwing an AuthorizationError if the user attempts to delete another author’s comment is correct.

- Replaced BadRequestError with NotFoundError when an article is not found by slug, improving clarity in error reporting.
Copy link
Contributor

@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

♻️ Duplicate comments (2)
src/articles/comments/comments.service.ts (2)

59-61: 🛠️ Refactor suggestion

Use NotFoundError for consistency with the createComment method.

In the createComment method you correctly use NotFoundError for a missing article, but here you're using BadRequestError instead. For consistency and better HTTP semantics, use NotFoundError in both places.

 if (!article) {
-  throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+  throw new NotFoundError(`Article with slug ${articleSlug} not found`);
 }

90-92: 🛠️ Refactor suggestion

Use NotFoundError for consistency with the createComment method.

Similar to the earlier comment, use NotFoundError here to maintain consistency throughout the service.

 if (!article) {
-  throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+  throw new NotFoundError(`Article with slug ${articleSlug} not found`);
 }
🧹 Nitpick comments (2)
src/articles/comments/comments.service.ts (2)

76-79: Consider using null coalescing operator for currentUserId check.

The current implementation for determining "following" status works correctly, but could be more concise using the null coalescing operator.

 following: currentUserId
-  ? comment.author.followers.some((f) => f.followerId === currentUserId)
-  : false,
+  ? comment.author.followers.some((f) => f.followerId === currentUserId) 
+  : false,

112-113: Consider returning the deleted comment ID for confirmation.

Currently, deleteComment returns void. Consider returning the deleted comment ID or a success message to provide confirmation to the caller.

-  async deleteComment(
+  async deleteComment(
   articleSlug: string,
   commentId: number,
   userId: number,
-): Promise<void> {
+): Promise<{ id: number }> {
   // ...existing code...
   
   await this.commentsRepository.delete(commentId, userId);
+  return { id: commentId };
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 29923e7 and dd9b96e.

📒 Files selected for processing (1)
  • src/articles/comments/comments.service.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/articles/comments/comments.service.ts (1)
Learnt from: yamcodes
PR: agnyz/bedstack#134
File: src/articles/comments/comments.service.ts:32-35
Timestamp: 2025-03-20T20:01:10.732Z
Learning: In the comment creation flow in src/articles/comments/comments.service.ts, the code correctly uses the newly created comment's authorId when fetching the author profile, even though this is set from the userId parameter. This provides better semantic clarity than directly using userId again.
🔇 Additional comments (6)
src/articles/comments/comments.service.ts (6)

1-7: Well-organized import structure with appropriate error types.

Your imports are well-organized, including specific error types for different scenarios. I like that you're importing NotFoundError from Elysia for resource not found situations.


8-14: Good service structure with proper dependency injection.

The service follows good practices with explicit dependencies injected through the constructor and marked as private readonly.


15-45: The comment creation implementation looks solid.

The flow for creating a comment is well-structured, checking for article existence, properly constructing the comment data, and returning the formatted response with author information.


47-81: Well-structured comments retrieval with proper documentation.

The getComments method is well-documented with JSDoc and effectively processes the comments to include author information with following status. The mapping logic is clean and straightforward.


100-104: Good validation to ensure comment belongs to the specified article.

This check helps maintain data integrity by ensuring the comment belongs to the correct article before proceeding with deletion.


106-110: Good authorization check to prevent unauthorized deletions.

The code correctly verifies that only the author of a comment can delete it, with a clear error message explaining the restriction.

…issing articles

- Replaced BadRequestError with NotFoundError when an article is not found by slug, enhancing clarity in error reporting.
Copy link
Contributor

@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

♻️ Duplicate comments (2)
src/articles/comments/comments.service.ts (2)

88-90: ⚠️ Potential issue

Use NotFoundError for a non-existent article.

For consistency with the error handling in other methods (like lines 20-22), use NotFoundError when an article doesn't exist.

if (!article) {
-  throw new BadRequestError(`Article with slug ${articleSlug} not found`);
+  throw new NotFoundError(`Article with slug ${articleSlug} not found`);
}

94-96: ⚠️ Potential issue

Use NotFoundError for a non-existent comment.

For consistency with resource not found errors, use NotFoundError when a comment doesn't exist rather than BadRequestError.

if (!comment) {
-  throw new BadRequestError(`Comment with id ${commentId} not found`);
+  throw new NotFoundError(`Comment with id ${commentId} not found`);
}
🧹 Nitpick comments (2)
src/articles/comments/comments.service.ts (2)

98-102: Consider using NotFoundError for comment-article mismatch.

When a comment doesn't belong to the specified article, it's essentially a resource not found situation in the context of that article.

if (comment.articleId !== article.id) {
-  throw new BadRequestError(
+  throw new NotFoundError(
    `Comment with id ${commentId} does not belong to article ${articleSlug}`,
  );
}

65-78: Consider refactoring the comment mapping logic for better maintenance.

The current mapping logic in getComments is inline. Consider extracting it to a helper method for better readability and maintainability, especially since you might need to reuse this logic elsewhere.

- return comments.map((comment) => ({
-   id: comment.id,
-   body: comment.body,
-   createdAt: comment.createdAt,
-   updatedAt: comment.updatedAt,
-   author: {
-     username: comment.author.username,
-     bio: comment.author.bio,
-     image: comment.author.image,
-     following: currentUserId
-       ? comment.author.followers.some((f) => f.followerId === currentUserId)
-       : false,
-   },
- }));
+ return comments.map((comment) => this.formatCommentResponse(comment, currentUserId));

// Add this helper method to the class
+ private formatCommentResponse(comment: any, currentUserId?: number): ReturnedComment {
+   return {
+     id: comment.id,
+     body: comment.body,
+     createdAt: comment.createdAt,
+     updatedAt: comment.updatedAt,
+     author: {
+       username: comment.author.username,
+       bio: comment.author.bio,
+       image: comment.author.image,
+       following: currentUserId
+         ? comment.author.followers.some((f) => f.followerId === currentUserId)
+         : false,
+     },
+   };
+ }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between dd9b96e and 581e9db.

📒 Files selected for processing (1)
  • src/articles/comments/comments.service.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/articles/comments/comments.service.ts (1)
Learnt from: yamcodes
PR: agnyz/bedstack#134
File: src/articles/comments/comments.service.ts:32-35
Timestamp: 2025-03-20T20:01:10.732Z
Learning: In the comment creation flow in src/articles/comments/comments.service.ts, the code correctly uses the newly created comment's authorId when fetching the author profile, even though this is set from the userId parameter. This provides better semantic clarity than directly using userId again.
🧬 Code Definitions (1)
src/articles/comments/comments.service.ts (3)
src/articles/comments/comments.repository.ts (1) (1)
  • CommentsRepository (6-71)
src/profiles/profiles.service.ts (1) (1)
  • ProfilesService (6-81)
src/articles/comments/comments.schema.ts (2) (2)
  • ReturnedComment (38-38)
  • CommentToCreate (15-18)
🔇 Additional comments (2)
src/articles/comments/comments.service.ts (2)

31-34: Clean approach for retrieving author profile.

The code correctly uses the newly created comment's authorId when fetching the author profile, which provides good semantic clarity even though it's set from the userId parameter.


74-76: Correct handling of following status for comments.

The implementation properly handles the following status by checking if currentUserId exists and setting it to false when not provided. This aligns with the behavior in ProfilesService and discussions about proper handling of the following field.

@yamcodes yamcodes requested a review from Hajbo March 21, 2025 12:16
Copy link
Collaborator

@Hajbo Hajbo left a comment

Choose a reason for hiding this comment

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

Amazing work 👑

@yamcodes yamcodes merged commit fb57e66 into main Mar 22, 2025
4 checks passed
@yamcodes yamcodes deleted the 78-implement-article-comment-feature-2 branch March 22, 2025 06:20
@coderabbitai coderabbitai bot mentioned this pull request Mar 23, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Article Comment feature

3 participants