Skip to content

Conversation

ericdude4
Copy link

@ericdude4 ericdude4 commented May 8, 2025

I'm finding that for paginating tables with hundreds of thousands of rows, it can take a long time to simply count the records in the table - even if all filters are indexed properly.

I had the thought that we could optionally apply a limit when counting the total rows. Of course this could result in incorrect total_entries and total_pages, but my thought is that this can be handled in a UI with something like "viewing page 1 of 100+ pages" and "viewing 25 of 1000+ entries".

Summary by CodeRabbit

  • New Features

    • Added support for capping the total number of entries counted during pagination using a maximum limit option.
  • Tests

    • Introduced tests to verify that pagination correctly respects the maximum total entries limit, including scenarios with grouped and joined queries.

Copy link

coderabbitai bot commented May 8, 2025

Walkthrough

The changes introduce a private helper function to conditionally apply a limit to Ecto queries based on a :max_total_entries option, affecting how aggregation counts are calculated. The aggregation logic is updated to use this helper, and new tests are added to verify that pagination respects the max_total_entries constraint, including for grouped and joined queries.

Changes

File(s) Change Summary
lib/scrivener/paginater/ecto/query.ex Added a private helper to limit queries by :max_total_entries, updated aggregation logic to use it.
test/scrivener/paginator/ecto/query_test.exs Added tests verifying pagination respects max_total_entries, including for grouped/joined queries.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant ScrivenerPaginator
    participant EctoQuery

    Caller->>ScrivenerPaginator: paginate(query, opts)
    ScrivenerPaginator->>EctoQuery: maybe_limit_by_max_total_entries(query, opts)
    EctoQuery-->>ScrivenerPaginator: query (possibly limited)
    ScrivenerPaginator->>EctoQuery: aggregate(query, :count, field)
    EctoQuery-->>ScrivenerPaginator: total_entries (capped if max_total_entries set)
    ScrivenerPaginator-->>Caller: paginated result (with capped total_entries)
Loading

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

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

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in 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.

Copy link

@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)
lib/scrivener/paginater/ecto/query.ex (1)

82-94: Solid implementation with proper validation.

The helper function correctly validates that max_total_entries is a positive integer before applying the limit. The error message is clear and descriptive, which will help developers understand how to correctly use this option.

One consideration: While raising an ArgumentError is appropriate for obvious programming errors, you might consider adding a note to the documentation about this validation to help users avoid runtime errors.

Consider adding documentation (either in a module doc or function doc) to clearly specify the expected type and constraints for the max_total_entries option.

test/scrivener/paginator/ecto/query_test.exs (1)

236-260: Consider adding a test for invalid max_total_entries.

While your current tests cover the happy path well, I recommend adding a test that verifies the ArgumentError is raised when an invalid max_total_entries value is provided (such as a negative number or non-integer).

+ test "raises ArgumentError when max_total_entries is invalid" do
+   assert_raise ArgumentError, fn ->
+     Post
+     |> Post.published()
+     |> Scrivener.Ecto.Repo.paginate(options: [max_total_entries: -1])
+   end
+ 
+   assert_raise ArgumentError, fn ->
+     Post
+     |> Post.published()
+     |> Scrivener.Ecto.Repo.paginate(options: [max_total_entries: "not_an_integer"])
+   end
+ end
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9705f and 2c18421.

📒 Files selected for processing (2)
  • lib/scrivener/paginater/ecto/query.ex (1 hunks)
  • test/scrivener/paginator/ecto/query_test.exs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
test/scrivener/paginator/ecto/query_test.exs (2)
test/support/post.ex (1)
  • published (16-18)
lib/scrivener/paginater/ecto/query.ex (1)
  • paginate (9-36)
🔇 Additional comments (4)
lib/scrivener/paginater/ecto/query.ex (2)

70-70: Efficient improvement to grouped query aggregation.

The addition of maybe_limit_by_max_total_entries in the pipeline ensures that grouped queries also benefit from the max_total_entries optimization, which is important for performance when dealing with large datasets.


77-80: Well-structured refactoring of the aggregate function.

Good refactoring of the simple aggregate function to include the max_total_entries limit option. The implementation maintains a clean pipeline structure and effectively implements the core performance optimization described in the PR objectives.

test/scrivener/paginator/ecto/query_test.exs (2)

236-246: Good basic test coverage for the new feature.

This test effectively verifies the core functionality - that max_total_entries properly limits the total_entries count while not affecting the number of entries returned on the current page. The assertion on line 245 correctly confirms that the total_entries is capped at 4 as specified.


248-260: Excellent test for complex query scenarios.

This test provides valuable coverage for the more complex use case involving inner joins, group by clauses, and tuple selects. It verifies that the pagination mechanism properly respects the max_total_entries option even in these advanced scenarios.

The assertions on lines 258-259 correctly verify both that the entries returned are unaffected (2 entries) while the total_entries count is capped at 1 as specified by max_total_entries.

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.

1 participant