From 2c18421aa679b82810346dfc803998e35b84c94f Mon Sep 17 00:00:00 2001 From: ericdude4 Date: Thu, 8 May 2025 12:52:38 -0400 Subject: [PATCH] support `max_total_entries` option + test --- lib/scrivener/paginater/ecto/query.ex | 19 +++++++++++++- test/scrivener/paginator/ecto/query_test.exs | 26 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/scrivener/paginater/ecto/query.ex b/lib/scrivener/paginater/ecto/query.ex index abbb2fb..547a60a 100644 --- a/lib/scrivener/paginater/ecto/query.ex +++ b/lib/scrivener/paginater/ecto/query.ex @@ -67,13 +67,30 @@ defimpl Scrivener.Paginater, for: Ecto.Query do |> exclude(:order_by) |> exclude(:select) |> select([{x, source_index}], struct(x, ^[field])) + |> maybe_limit_by_max_total_entries(options) |> subquery() |> select(count("*")) |> repo.one(options) end defp aggregate(query, repo, options) do - repo.aggregate(query, :count, options) + query + |> maybe_limit_by_max_total_entries(options) + |> repo.aggregate(:count, options) + end + + defp maybe_limit_by_max_total_entries(query, options) do + case Keyword.get(options, :max_total_entries) do + nil -> + query + + max_total_entries when is_integer(max_total_entries) and max_total_entries > 0 -> + limit(query, ^max_total_entries) + + otherwise -> + raise ArgumentError, + "max_total_entries must be a positive integer, got: #{inspect(otherwise)}" + end end defp total_pages(0, _), do: 1 diff --git a/test/scrivener/paginator/ecto/query_test.exs b/test/scrivener/paginator/ecto/query_test.exs index 671eecf..00a6f6c 100644 --- a/test/scrivener/paginator/ecto/query_test.exs +++ b/test/scrivener/paginator/ecto/query_test.exs @@ -233,6 +233,32 @@ defmodule Scrivener.Paginator.Ecto.QueryTest do assert page.total_entries == 130 end + test "will respect max_total_entries passed to paginate" do + create_posts() + + page = + Post + |> Post.published() + |> Scrivener.Ecto.Repo.paginate(options: [max_total_entries: 4]) + + assert length(page.entries) == 5 + assert page.total_entries == 4 + end + + test "will respect max_total_entries passed to paginate with a group by clause on field on joined table" do + create_posts() + + page = + Post + |> join(:inner, [p], c in assoc(p, :comments)) + |> group_by([p, c], c.body) + |> select([p, c], {c.body, count("*")}) + |> Scrivener.Ecto.Repo.paginate(options: [max_total_entries: 1]) + + assert length(page.entries) == 2 + assert page.total_entries == 1 + end + test "will use total_pages if page_numer is too large" do posts = create_posts()