fix: non relay keyset pagination was broken when relay was introduced

This commit is contained in:
Zach Daniel 2022-10-12 12:11:51 -04:00
parent 9a3136fd5d
commit 8d79fd7d2a
4 changed files with 109 additions and 24 deletions

View file

@ -144,7 +144,7 @@ defmodule AshGraphql.Graphql.Resolver do
def resolve( def resolve(
%{arguments: args, context: context} = resolution, %{arguments: args, context: context} = resolution,
{api, resource, %{type: :list, action: action, modify_resolution: modify}} {api, resource, %{type: :list, relay?: relay?, action: action, modify_resolution: modify}}
) do ) do
opts = [ opts = [
actor: Map.get(context, :actor), actor: Map.get(context, :actor),
@ -157,7 +157,7 @@ defmodule AshGraphql.Graphql.Resolver do
{result, modify_args} = {result, modify_args} =
with {:ok, opts} <- validate_resolve_opts(resolution, pagination, opts, args), with {:ok, opts} <- validate_resolve_opts(resolution, pagination, opts, args),
result_fields <- get_result_fields(pagination), result_fields <- get_result_fields(pagination, relay?),
initial_query <- initial_query <-
query query
|> Ash.Query.set_tenant(Map.get(context, :tenant)) |> Ash.Query.set_tenant(Map.get(context, :tenant))
@ -172,7 +172,7 @@ defmodule AshGraphql.Graphql.Resolver do
authorize?: AshGraphql.Api.Info.authorize?(api) authorize?: AshGraphql.Api.Info.authorize?(api)
) )
|> api.read(opts) do |> api.read(opts) do
result = paginate(resource, action, page) result = paginate(resource, action, page, relay?)
{result, [query, result]} {result, [query, result]}
else else
{:error, error} -> {:error, error} ->
@ -279,15 +279,19 @@ defmodule AshGraphql.Graphql.Resolver do
{:ok, opts} {:ok, opts}
end end
defp get_result_fields(%{keyset?: true}) do defp get_result_fields(%{keyset?: true}, true) do
["edges", "node"] ["edges", "node"]
end end
defp get_result_fields(%{offset?: true}) do defp get_result_fields(%{keyset?: true}, false) do
["results"] ["results"]
end end
defp get_result_fields(_pagination) do defp get_result_fields(%{offset?: true}, _) do
["results"]
end
defp get_result_fields(_pagination, _) do
[] []
end end
@ -299,12 +303,17 @@ defmodule AshGraphql.Graphql.Resolver do
[] []
end end
defp paginate(_resource, _action, %Ash.Page.Keyset{ defp paginate(
results: results, _resource,
more?: more, _action,
after: after_cursor, %Ash.Page.Keyset{
before: before_cursor results: results,
}) do more?: more,
after: after_cursor,
before: before_cursor
},
true
) do
{start_cursor, end_cursor} = {start_cursor, end_cursor} =
case results do case results do
[] -> [] ->
@ -351,22 +360,44 @@ defmodule AshGraphql.Graphql.Resolver do
} }
end end
defp paginate(_resource, _action, %Ash.Page.Offset{results: results, count: count}) do defp paginate(
_resource,
_action,
%Ash.Page.Keyset{
results: results,
count: count
},
false
) do
{:ok, %{results: results, count: count}} {:ok, %{results: results, count: count}}
end end
defp paginate(resource, action, page) do defp paginate(_resource, _action, %Ash.Page.Offset{results: results, count: count}, _) do
{:ok, %{results: results, count: count}}
end
defp paginate(resource, action, page, relay?) do
case Ash.Resource.Info.action(resource, action).pagination do case Ash.Resource.Info.action(resource, action).pagination do
%{offset?: true} -> %{offset?: true} ->
paginate(resource, action, %Ash.Page.Offset{results: page, count: Enum.count(page)}) paginate(
resource,
action,
%Ash.Page.Offset{results: page, count: Enum.count(page)},
relay?
)
%{keyset?: true} -> %{keyset?: true} ->
paginate(resource, action, %Ash.Page.Keyset{ paginate(
results: page, resource,
more?: false, action,
after: nil, %Ash.Page.Keyset{
before: nil results: page,
}) more?: false,
after: nil,
before: nil
},
relay?
)
_ -> _ ->
{:ok, page} {:ok, page}

View file

@ -1078,7 +1078,6 @@ defmodule AshGraphql.Resource do
name: "first", name: "first",
identifier: :first, identifier: :first,
type: :integer, type: :integer,
default_value: action.pagination.default_limit,
description: "The number of records to return from the beginning." <> max_message, description: "The number of records to return from the beginning." <> max_message,
__reference__: ref(__ENV__) __reference__: ref(__ENV__)
}, },
@ -1100,7 +1099,6 @@ defmodule AshGraphql.Resource do
name: "last", name: "last",
identifier: :last, identifier: :last,
type: :integer, type: :integer,
default_value: action.pagination.default_limit,
description: "The number of records to return to the end." <> max_message, description: "The number of records to return to the end." <> max_message,
__reference__: ref(__ENV__) __reference__: ref(__ENV__)
} }

View file

@ -9,7 +9,58 @@ defmodule AshGraphql.PaginateTest do
end) end)
end end
describe "pagination" do describe "keyset pagination" do
setup do
letters = ["a", "b", "c", "d", "e"]
for text <- letters do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: text, published: true)
|> AshGraphql.Test.Api.create!()
for text <- letters do
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, text: text)
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
end
end
:ok
end
test "default_limit records are fetched" do
doc = """
query KeysetPaginatedPosts {
keysetPaginatedPosts(sort: [{field: TEXT}]) {
count
results{
text
}
}
}
"""
assert {:ok,
%{
data: %{
"keysetPaginatedPosts" => %{
"count" => 5,
"results" => [
%{"text" => "a"},
%{"text" => "b"},
%{"text" => "c"},
%{"text" => "d"},
%{"text" => "e"}
]
}
}
}} = Absinthe.run(doc, AshGraphql.Test.Schema)
end
end
describe "offset pagination" do
setup do setup do
letters = ["a", "b", "c", "d", "e"] letters = ["a", "b", "c", "d", "e"]

View file

@ -77,6 +77,7 @@ defmodule AshGraphql.Test.Post do
list :post_library, :library list :post_library, :library
list :post_score, :score list :post_score, :score
list :paginated_posts, :paginated list :paginated_posts, :paginated
list :keyset_paginated_posts, :keyset_paginated
list :paginated_posts_without_limit, :paginated_without_limit list :paginated_posts_without_limit, :paginated_without_limit
list :paginated_posts_limit_not_required, :paginated_limit_not_required list :paginated_posts_limit_not_required, :paginated_limit_not_required
end end
@ -160,6 +161,10 @@ defmodule AshGraphql.Test.Post do
pagination(required?: true, offset?: true, countable: true, default_limit: 20) pagination(required?: true, offset?: true, countable: true, default_limit: 20)
end end
read :keyset_paginated do
pagination(required?: true, keyset?: true, countable: true, default_limit: 20)
end
read :paginated_without_limit do read :paginated_without_limit do
pagination(required?: true, offset?: true, countable: true) pagination(required?: true, offset?: true, countable: true)
end end