2023-10-26 15:08:42 +13:00
|
|
|
defmodule AshJsonApiWrapper.CustomPagination.Test do
|
|
|
|
use ExUnit.Case
|
|
|
|
require Ash.Query
|
2023-11-14 07:21:38 +13:00
|
|
|
import Mox
|
2023-10-26 15:08:42 +13:00
|
|
|
@moduletag :custom_pagination
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
# Make sure mocks are verified when the test exits
|
|
|
|
setup :verify_on_exit!
|
|
|
|
|
|
|
|
defmodule TestingTesla do
|
|
|
|
use Tesla
|
|
|
|
|
|
|
|
adapter(AshJsonApiWrapper.MockAdapter)
|
|
|
|
# plug(Tesla.Middleware.Logger)
|
|
|
|
|
|
|
|
plug(Tesla.Middleware.Retry,
|
|
|
|
delay: 2000,
|
|
|
|
max_retries: 5,
|
|
|
|
max_delay: 4_000,
|
|
|
|
should_retry: fn
|
|
|
|
{:ok, %{status: status}} when status in [429] -> true
|
|
|
|
{:ok, _} -> false
|
|
|
|
{:error, _} -> true
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2023-10-26 15:08:42 +13:00
|
|
|
# ── Custom paginator ──
|
|
|
|
|
|
|
|
defmodule CustomPaginator do
|
|
|
|
use AshJsonApiWrapper.Paginator
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
defp cursor do
|
2023-10-26 15:08:42 +13:00
|
|
|
case :ets.whereis(:cursor) do
|
|
|
|
:undefined ->
|
|
|
|
:ets.new(:cursor, [:set, :protected, :named_table])
|
|
|
|
|> :ets.insert({self(), 1})
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
[{_, value} | _rest] = :ets.lookup(:cursor, self())
|
|
|
|
value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
defp increment_cursor do
|
2023-10-26 15:08:42 +13:00
|
|
|
:ets.insert(:cursor, {self(), cursor() + 1})
|
|
|
|
end
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
defp reset_cursor do
|
|
|
|
cursor()
|
2023-10-26 15:08:42 +13:00
|
|
|
:ets.insert(:cursor, {self(), 1})
|
|
|
|
end
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
def start(_opts) do
|
2023-10-26 15:08:42 +13:00
|
|
|
reset_cursor()
|
2023-11-14 07:21:38 +13:00
|
|
|
{:ok, %{params: %{"p" => 1}}}
|
|
|
|
end
|
|
|
|
|
|
|
|
def continue(_response, [], _) do
|
2023-10-26 15:08:42 +13:00
|
|
|
:halt
|
|
|
|
end
|
|
|
|
|
|
|
|
def continue(_response, _entities, _opts) do
|
|
|
|
increment_cursor()
|
2023-11-14 07:21:38 +13:00
|
|
|
{:ok, %{params: %{"p" => cursor()}}}
|
2023-10-26 15:08:42 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# ── Resource ──
|
|
|
|
|
|
|
|
defmodule Users do
|
|
|
|
use Ash.Resource,
|
|
|
|
data_layer: AshJsonApiWrapper.DataLayer,
|
|
|
|
validate_api_inclusion?: false
|
|
|
|
|
|
|
|
json_api_wrapper do
|
2023-11-14 07:21:38 +13:00
|
|
|
tesla(TestingTesla)
|
2023-10-26 15:08:42 +13:00
|
|
|
|
|
|
|
endpoints do
|
|
|
|
base("https://65383945a543859d1bb1528e.mockapi.io/api/v1")
|
|
|
|
|
|
|
|
endpoint :list_users do
|
|
|
|
path("/users")
|
|
|
|
limit_with {:param, "l"}
|
|
|
|
runtime_sort? true
|
|
|
|
paginator CustomPaginator
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
|
|
|
read(:list_users) do
|
|
|
|
primary?(true)
|
|
|
|
|
|
|
|
pagination do
|
|
|
|
offset?(true)
|
|
|
|
required?(true)
|
|
|
|
default_limit(50)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
attribute :id, :integer do
|
|
|
|
primary_key?(true)
|
|
|
|
allow_nil?(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
attribute(:name, :string)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Api do
|
|
|
|
use Ash.Api, validate_config_inclusion?: false
|
|
|
|
|
|
|
|
resources do
|
|
|
|
allow_unregistered?(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# ── Test it! ──
|
|
|
|
|
|
|
|
test "it works" do
|
|
|
|
Application.put_env(:ash, :validate_api_resource_inclusion?, false)
|
|
|
|
Application.put_env(:ash, :validate_api_config_inclusion?, false)
|
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
AshJsonApiWrapper.MockAdapter
|
|
|
|
|> expect(:call, 4, fn env, _options ->
|
|
|
|
case env.query do
|
|
|
|
%{"l" => 3, "p" => 2} ->
|
|
|
|
{:ok, %Tesla.Env{env | status: 200, body: "[]"}}
|
|
|
|
|
|
|
|
%{"l" => 3, "p" => 1} ->
|
|
|
|
{:ok,
|
|
|
|
%Tesla.Env{
|
|
|
|
env
|
|
|
|
| status: 200,
|
|
|
|
body: """
|
|
|
|
[
|
|
|
|
{"name": "Kendra Ernser", "id":"1"},
|
|
|
|
{"name": "Max Hartman", "id":"2"},
|
|
|
|
{"name": "John Benton", "id":"3"}
|
|
|
|
]
|
|
|
|
"""
|
|
|
|
}}
|
|
|
|
|
|
|
|
query ->
|
|
|
|
{:ok,
|
|
|
|
%Tesla.Env{
|
|
|
|
env
|
|
|
|
| status: 500,
|
|
|
|
body: "Unexpected parameters: #{query |> Kernel.inspect()}"
|
|
|
|
}}
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2023-10-26 15:08:42 +13:00
|
|
|
users =
|
|
|
|
Users
|
|
|
|
|> Ash.Query.for_read(:list_users)
|
2023-11-14 07:21:38 +13:00
|
|
|
# |> Ash.Query.limit(2)
|
|
|
|
|> Api.read!(page: [limit: 2, offset: 0])
|
|
|
|
|
|
|
|
users2 =
|
|
|
|
Users
|
|
|
|
|> Ash.Query.for_read(:list_users)
|
|
|
|
|> Api.read!(page: [limit: 2, offset: 1])
|
2023-10-26 15:08:42 +13:00
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
users_count = users.results |> Enum.count()
|
|
|
|
users2_count = users2.results |> Enum.count()
|
2023-10-26 15:08:42 +13:00
|
|
|
|
2023-11-14 07:21:38 +13:00
|
|
|
assert(users_count == users2_count)
|
2023-10-26 15:08:42 +13:00
|
|
|
end
|
|
|
|
end
|