fix: count_posts paginated before aggregation
This commit is contained in:
@@ -220,7 +220,7 @@ defmodule BDS.AI.ChatTools do
|
||||
def execute("count_posts", arguments, project_id) do
|
||||
project_id = project_id || active_project_id()
|
||||
group_by = List.wrap(arguments["groupBy"] || arguments["group_by"]) |> Enum.map(&to_string/1)
|
||||
{:ok, result} = Search.search_posts(project_id, "", search_filters(arguments))
|
||||
result = search_all_counted_posts(project_id, arguments)
|
||||
|
||||
groups =
|
||||
result.posts
|
||||
@@ -882,6 +882,16 @@ defmodule BDS.AI.ChatTools do
|
||||
|> Map.put(:limit, normalize_limit(arguments["limit"]))
|
||||
end
|
||||
|
||||
defp search_all_counted_posts(project_id, arguments) do
|
||||
filters = search_filters(arguments) |> Map.put(:offset, 0) |> Map.put(:limit, 1)
|
||||
{:ok, %{total: total}} = Search.search_posts(project_id, "", filters)
|
||||
|
||||
filters = Map.put(filters, :limit, max(total, 1))
|
||||
{:ok, result} = Search.search_posts(project_id, "", filters)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
defp maybe_put(map, _key, nil), do: map
|
||||
defp maybe_put(map, _key, ""), do: map
|
||||
defp maybe_put(map, key, value), do: Map.put(map, key, value)
|
||||
|
||||
@@ -390,8 +390,7 @@ defmodule BDS.MCP.Tools do
|
||||
defp count_posts(params) do
|
||||
project = Queries.active_project!()
|
||||
group_by = map_get(params, :groupBy, []) |> Enum.map(&to_string/1)
|
||||
filters = Queries.search_filters(params)
|
||||
{:ok, result} = Search.search_posts(project.id, "", filters)
|
||||
result = search_all_counted_posts(project.id, params)
|
||||
|
||||
groups =
|
||||
result.posts
|
||||
@@ -403,6 +402,16 @@ defmodule BDS.MCP.Tools do
|
||||
%{"groups" => groups, "total_posts" => result.total}
|
||||
end
|
||||
|
||||
defp search_all_counted_posts(project_id, params) do
|
||||
filters = Queries.search_filters(params) |> Map.put(:offset, 0) |> Map.put(:limit, 1)
|
||||
{:ok, %{total: total}} = Search.search_posts(project_id, "", filters)
|
||||
|
||||
filters = Map.put(filters, :limit, max(total, 1))
|
||||
{:ok, result} = Search.search_posts(project_id, "", filters)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
defp read_post_by_slug(%{"slug" => slug} = params),
|
||||
do: read_post_by_slug(Map.put_new(params, :slug, slug))
|
||||
|
||||
|
||||
@@ -770,6 +770,44 @@ defmodule BDS.AITest do
|
||||
)
|
||||
end
|
||||
|
||||
test "chat count_posts groups every matching post before returning groups" do
|
||||
{:ok, project} = create_project_fixture("Count Posts")
|
||||
|
||||
month_counts = [{2, 4}, {3, 6}, {4, 3}]
|
||||
|
||||
for {month, count} <- month_counts,
|
||||
index <- 1..count do
|
||||
created_at = unix_ms!(NaiveDateTime.new!(Date.new!(2026, month, index), ~T[12:00:00]))
|
||||
|
||||
Repo.insert!(
|
||||
Post.changeset(%Post{}, %{
|
||||
id: Ecto.UUID.generate(),
|
||||
project_id: project.id,
|
||||
title: "AI Count #{month}-#{index}",
|
||||
slug: "ai-count-#{month}-#{index}",
|
||||
content: "Body",
|
||||
status: :draft,
|
||||
created_at: created_at,
|
||||
updated_at: created_at,
|
||||
do_not_translate: false
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
assert %{groups: groups, total_posts: 13} =
|
||||
BDS.AI.ChatTools.execute(
|
||||
"count_posts",
|
||||
%{"groupBy" => ["month"], "year" => 2026},
|
||||
project.id
|
||||
)
|
||||
|
||||
assert Enum.sort_by(groups, & &1["month"]) == [
|
||||
%{"count" => 4, "month" => 2},
|
||||
%{"count" => 6, "month" => 3},
|
||||
%{"count" => 3, "month" => 4}
|
||||
]
|
||||
end
|
||||
|
||||
test "cancel_chat aborts an in-flight chat turn" do
|
||||
assert {:ok, _endpoint} =
|
||||
BDS.AI.put_endpoint(
|
||||
@@ -853,4 +891,10 @@ defmodule BDS.AITest do
|
||||
|
||||
%{post: post, media: media}
|
||||
end
|
||||
|
||||
defp unix_ms!(%NaiveDateTime{} = naive_datetime) do
|
||||
naive_datetime
|
||||
|> DateTime.from_naive!("Etc/UTC")
|
||||
|> DateTime.to_unix(:millisecond)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@ defmodule BDS.MCPTest do
|
||||
|
||||
alias BDS.Media.Media
|
||||
alias BDS.MCP.ProposalStore
|
||||
alias BDS.Posts.Post
|
||||
alias BDS.Repo
|
||||
alias BDS.Scripts.Script
|
||||
alias BDS.Templates.Template
|
||||
@@ -88,6 +89,39 @@ defmodule BDS.MCPTest do
|
||||
assert read_result["post"]["slug"] == "travel-notes"
|
||||
end
|
||||
|
||||
test "count_posts groups every matching post before returning groups", %{project: project} do
|
||||
month_counts = [{2, 24}, {3, 26}, {4, 23}]
|
||||
|
||||
for {month, count} <- month_counts,
|
||||
index <- 1..count do
|
||||
day = rem(index - 1, 28) + 1
|
||||
created_at = unix_ms!(NaiveDateTime.new!(Date.new!(2026, month, day), ~T[12:00:00]))
|
||||
|
||||
Repo.insert!(
|
||||
Post.changeset(%Post{}, %{
|
||||
id: Ecto.UUID.generate(),
|
||||
project_id: project.id,
|
||||
title: "MCP Count #{month}-#{index}",
|
||||
slug: "mcp-count-#{month}-#{index}",
|
||||
content: "Body",
|
||||
status: :draft,
|
||||
created_at: created_at,
|
||||
updated_at: created_at,
|
||||
do_not_translate: false
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
assert {:ok, %{"groups" => groups, "total_posts" => 73}} =
|
||||
BDS.MCP.call_tool("count_posts", %{groupBy: ["month"], year: 2026})
|
||||
|
||||
assert Enum.sort_by(groups, & &1["month"]) == [
|
||||
%{"count" => 24, "month" => 2},
|
||||
%{"count" => 26, "month" => 3},
|
||||
%{"count" => 23, "month" => 4}
|
||||
]
|
||||
end
|
||||
|
||||
test "translation tools expose post and media translations and upsert media metadata", %{
|
||||
project: project,
|
||||
temp_dir: temp_dir
|
||||
@@ -437,4 +471,10 @@ defmodule BDS.MCPTest do
|
||||
assert "bds://posts{?cursor}" in template_uris
|
||||
assert "bds://media{?cursor}" in template_uris
|
||||
end
|
||||
|
||||
defp unix_ms!(%NaiveDateTime{} = naive_datetime) do
|
||||
naive_datetime
|
||||
|> DateTime.from_naive!("Etc/UTC")
|
||||
|> DateTime.to_unix(:millisecond)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user