Skip to content

[f] 241 - Update the last activity user only for user action#12

Merged
giahung68 merged 3 commits intomainfrom
features/ver-227-update-last-user-activity
Dec 10, 2024
Merged

[f] 241 - Update the last activity user only for user action#12
giahung68 merged 3 commits intomainfrom
features/ver-227-update-last-user-activity

Conversation

@giahung68
Copy link
Copy Markdown
Collaborator

@giahung68 giahung68 commented Dec 9, 2024

Summary by CodeRabbit

  • New Features

    • Enhanced snippet functions to track user last activity by recording the current timestamp when comment, like, or upvote counts are modified.
    • Updated snippet retrieval logic to include user last activity for improved sorting and display.
  • Bug Fixes

    • Improved accuracy of user last activity updates alongside comment, like, and upvote counts.

@linear
Copy link
Copy Markdown

linear Bot commented Dec 9, 2024

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 9, 2024

Warning

Rate limit exceeded

@giahung68 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 23 minutes and 36 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ce14dee and 15b88c0.

📒 Files selected for processing (1)
  • supabase/database/sql/get_snippets_function.sql (2 hunks)

Walkthrough

The pull request modifies four SQL functions: update_snippet_comment_count, update_snippet_like_count, update_snippet_upvote_count, and update_last_user_activity. Each of the first three functions now includes an additional update to the user_last_activity field in the snippets table, setting it to the current timestamp (NOW()). The original logic for updating their respective counts remains intact, while the update_last_user_activity function aggregates timestamps from various user activities to set the user_last_activity field.

Changes

File Path Change Summary
supabase/database/sql/update_snippet_comment_count.sql Modified update_snippet_comment_count to update user_last_activity to NOW() alongside comment_count.
supabase/database/sql/update_snippet_like_count.sql Modified update_snippet_like_count to update user_last_activity to NOW() alongside like_count.
supabase/database/sql/update_snippet_upvote_count.sql Modified update_snippet_upvote_count to update user_last_activity to NOW() alongside upvote_count.
supabase/database/sql/update_last_user_activity.sql Modified to set user_last_activity to the maximum timestamp from label upvotes, likes, and comments.
supabase/database/sql/get_snippets_function.sql Updated get_snippets to include user_last_activity in the temporary table and modified ordering logic.

Possibly related PRs

  • [f] 116 - Implement sort feature (BE) #6: The update_snippet_like_count function is related as it also updates the user_last_activity field in the snippets table, similar to the changes made in the update_snippet_comment_count function in the main PR.
  • [f] 241 - Update the get_snippets query #11: The get_snippets function has been modified to include the user_last_activity field in its logic, which connects it to the changes in the main PR that also involve updating this field.

Suggested reviewers

  • nhphong

Poem

In the code where snippets play,
Counts of likes and comments sway.
With timestamps fresh, we keep them bright,
User activity shines in the night.
Hopping through functions, we make it right! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 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.

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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 99b1c85 and 51c02a1.

📒 Files selected for processing (3)
  • supabase/database/sql/update_snippet_comment_count.sql (1 hunks)
  • supabase/database/sql/update_snippet_like_count.sql (1 hunks)
  • supabase/database/sql/update_snippet_upvote_count.sql (1 hunks)
🔇 Additional comments (1)
supabase/database/sql/update_snippet_comment_count.sql (1)

5-11: ⚠️ Potential issue

Consider differentiating between user and system actions

The current implementation updates user_last_activity for both comment creation and deletion. However, based on the PR title "[f] 241 - Update the last activity user only for user action", we should consider:

  1. Comment deletion might be performed by admins/system
  2. We might want to update user_last_activity only for comment creation

Let's check if there are admin-related comment deletions:

Consider modifying the trigger to only update user_last_activity for INSERT operations:

 UPDATE snippets
 SET 
     comment_count = (
         SELECT COUNT(*)
         FROM comments 
         WHERE room_id = COALESCE(NEW.room_id, OLD.room_id)
     ),
-    user_last_activity = NOW()
+    user_last_activity = CASE 
+        WHEN TG_OP = 'INSERT' THEN NOW()
+        ELSE user_last_activity
+    END
 WHERE id = COALESCE(NEW.room_id, OLD.room_id);

Comment on lines +5 to +12
SET
like_count = (
SELECT COUNT(*)
FROM user_like_snippets
WHERE snippet = COALESCE(NEW.snippet, OLD.snippet)
AND value = 1
),
user_last_activity = NOW()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider handling unlike actions differently

Similar to the comment count update, we should consider differentiating between like and unlike actions for updating user_last_activity. This aligns with the PR objective of updating last activity only for user actions.

Consider modifying the trigger to only update user_last_activity for like actions (when value = 1):

 UPDATE snippets
 SET 
     like_count = (
         SELECT COUNT(*)
         FROM user_like_snippets
         WHERE snippet = COALESCE(NEW.snippet, OLD.snippet)
         AND value = 1
     ),
-    user_last_activity = NOW()
+    user_last_activity = CASE 
+        WHEN TG_OP = 'INSERT' AND NEW.value = 1 THEN NOW()
+        ELSE user_last_activity
+    END
 WHERE id = COALESCE(NEW.snippet, OLD.snippet);
📝 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
SET
like_count = (
SELECT COUNT(*)
FROM user_like_snippets
WHERE snippet = COALESCE(NEW.snippet, OLD.snippet)
AND value = 1
),
user_last_activity = NOW()
SET
like_count = (
SELECT COUNT(*)
FROM user_like_snippets
WHERE snippet = COALESCE(NEW.snippet, OLD.snippet)
AND value = 1
),
user_last_activity = CASE
WHEN TG_OP = 'INSERT' AND NEW.value = 1 THEN NOW()
ELSE user_last_activity
END

Comment on lines +12 to +19
SET
upvote_count = (
SELECT COUNT(*)
FROM label_upvotes lu
JOIN snippet_labels sl ON lu.snippet_label = sl.id
WHERE sl.snippet = snippet_id
),
user_last_activity = NOW()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider handling upvote removal differently

Similar to the previous files, we should differentiate between upvote and upvote removal actions for updating user_last_activity. This maintains consistency with the PR's objective.

Consider modifying the trigger to only update user_last_activity for upvote actions:

 UPDATE snippets
 SET 
     upvote_count = (
         SELECT COUNT(*)
         FROM label_upvotes lu
         JOIN snippet_labels sl ON lu.snippet_label = sl.id
         WHERE sl.snippet = snippet_id
     ),
-    user_last_activity = NOW()
+    user_last_activity = CASE 
+        WHEN TG_OP = 'INSERT' THEN NOW()
+        ELSE user_last_activity
+    END
 WHERE id = snippet_id;

Consider extracting the user activity update logic into a separate function to maintain consistency across all three triggers and make future modifications easier.

Committable suggestion skipped: line range outside the PR's diff.

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

🧹 Outside diff range and nitpick comments (3)
supabase/database/sql/update_last_user_activity.sql (3)

8-12: Consider adding an index for better performance.

This subquery joins snippet_labels with label_upvotes. Consider adding an index on snippet_labels(snippet, id) to optimize the lookup performance.


26-26: Inconsistent column naming: room_id vs snippet.

The room_id column in the comments table is used to reference snippets, while other tables use snippet. This inconsistency could lead to confusion. Consider renaming for consistency.

-WHERE room_id = s.id
+WHERE snippet = s.id

19-20: Simplify the value comparison condition.

The condition value = 1 OR value = -1 can be simplified using IN.

-AND (value = 1 OR value = -1)
+AND value IN (1, -1)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 51c02a1 and cb42594.

📒 Files selected for processing (1)
  • supabase/database/sql/update_last_user_activity.sql (1 hunks)

Comment on lines +1 to +30
UPDATE snippets s
SET user_last_activity = (
SELECT MAX(activity_time)
FROM (
-- Get label upvotes timestamps
SELECT created_at as activity_time
FROM label_upvotes
WHERE snippet_label IN (
SELECT id
FROM snippet_labels
WHERE snippet = s.id
)

UNION ALL

-- Get likes timestamps
SELECT created_at as activity_time
FROM user_like_snippets
WHERE snippet = s.id
AND (value = 1 OR value = -1)

UNION ALL

SELECT created_at as activity_time
FROM comments
WHERE room_id = s.id
AND deleted_at is null

) all_activities
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Race condition confirmed between aggregate and trigger-based updates of user_last_activity

The verification confirms a critical race condition:

  • The aggregate update in update_last_user_activity.sql calculates MAX(activity_time) from historical records
  • Three triggers (update_snippet_comment_count, update_snippet_like_count, update_snippet_upvote_count) set user_last_activity = NOW()
  • The aggregate update could overwrite a more recent NOW() timestamp from triggers

Recommendations:

  • Add WHERE user_last_activity < calculated_max condition to the aggregate update to prevent overwriting newer timestamps
  • Consider using transaction isolation level SERIALIZABLE for the aggregate update
  • Long term: consolidate the activity tracking logic to avoid multiple update paths
🔗 Analysis chain

Potential race condition with concurrent updates.

The AI summary indicates that other functions (update_snippet_comment_count, update_snippet_like_count, update_snippet_upvote_count) also update user_last_activity using NOW(). This could lead to race conditions where this aggregate update overwrites more recent activity timestamps.

Consider:

  1. Adding transaction isolation level controls
  2. Implementing a comparison to only update if the new timestamp is more recent

Let's verify the other function implementations:


The search results confirm the review comment's concern. Let me check the full context of these functions and their triggers to understand the complete picture:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other functions updating user_last_activity
rg -A 5 "user_last_activity.*NOW\(\)" --type sql

Length of output: 1379


Script:

#!/bin/bash
# Get full content of the files
echo "=== update_snippet_comment_count.sql ==="
cat supabase/database/sql/update_snippet_comment_count.sql
echo -e "\n=== update_snippet_like_count.sql ==="
cat supabase/database/sql/update_snippet_like_count.sql
echo -e "\n=== update_snippet_upvote_count.sql ==="
cat supabase/database/sql/update_snippet_upvote_count.sql

Length of output: 1960

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

🧹 Outside diff range and nitpick comments (1)
supabase/database/sql/get_snippets_function.sql (1)

Line range hint 3-11: Consider performance optimization and security implications

As this function grows in complexity, consider the following architectural improvements:

  1. Performance:

    • Consider materializing commonly used subqueries
    • Add appropriate indexes for the filtering conditions
    • Monitor query execution plan for potential bottlenecks
  2. Security:

    • The function uses SECURITY DEFINER, ensure all user input is properly validated
    • Consider implementing row-level security as an additional safety layer
    • Add input validation for page and page_size parameters
  3. Maintainability:

    • Consider breaking down complex filtering logic into separate functions
    • Add function documentation explaining the security model
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between cb42594 and ce14dee.

📒 Files selected for processing (1)
  • supabase/database/sql/get_snippets_function.sql (3 hunks)
🔇 Additional comments (2)
supabase/database/sql/get_snippets_function.sql (2)

36-36: LGTM: Addition of user_last_activity field

The field is correctly added to the SELECT list and will be used for activity-based sorting.


275-279: Verify NULL handling behavior for activity-based sorting

The current implementation places snippets with no activity (NULL user_last_activity) at the bottom of the list when sorting by activities. Please confirm if this aligns with the business requirements.

Alternative approaches could be:

  1. Place NULL activities at the top (using COALESCE(EXTRACT(EPOCH FROM s.user_last_activity), 9999999999))
  2. Use the recorded_at timestamp as a fallback (using COALESCE(s.user_last_activity, s.recorded_at))
✅ Verification successful

Current NULL handling for activity-based sorting is correct

The codebase shows that user_last_activity is consistently updated to NOW() whenever there's user interaction (comments, likes, upvotes) with a snippet. The update_last_user_activity.sql maintains this field by tracking all activity timestamps. Having inactive snippets (NULL user_last_activity) appear at the bottom of activity-based sorting is the correct behavior because:

  1. NULL values represent snippets with no user interactions
  2. The field is automatically updated on any user activity
  3. The sorting puts most recently active snippets at the top, which aligns with typical activity feed patterns
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the distribution of user_last_activity values
# This will help understand the impact of NULL handling

ast-grep --pattern 'UPDATE snippets SET user_last_activity = $_'

Length of output: 66


Script:

#!/bin/bash
# Let's search for files containing user_last_activity to understand its usage
rg -l "user_last_activity"

# Then look for SQL files that might define or modify this column
fd -e sql | xargs rg "user_last_activity" -B 2 -A 2

Length of output: 2907

'current_page', page,
'page_size', page_size,
'total_pages', total_pages
'total_pages', total_pages,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix: Remove trailing comma in JSON object

The trailing comma after 'total_pages' will cause a PostgreSQL syntax error. JSON object construction in PostgreSQL doesn't support trailing commas.

-        'total_pages', total_pages,
+        'total_pages', total_pages
📝 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
'total_pages', total_pages,
'total_pages', total_pages

@giahung68 giahung68 force-pushed the features/ver-227-update-last-user-activity branch from ce14dee to 15b88c0 Compare December 9, 2024 09:18
@giahung68 giahung68 merged commit e10b2b0 into main Dec 10, 2024
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