fix: restore support for custom paginators (#6)

This commit is contained in:
Peter Hartman 2023-10-26 03:08:42 +01:00 committed by GitHub
parent 2c8fe82ff1
commit 4ecdcea91e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 40 deletions

View file

@ -330,7 +330,7 @@ defmodule AshJsonApiWrapper.DataLayer do
end end
@impl true @impl true
def set_context(_resource, query, context) do def set_context(resource, query, context) do
params = context[:data_layer][:query_params] || %{} params = context[:data_layer][:query_params] || %{}
headers = Map.to_list(context[:data_layer][:headers] || %{}) headers = Map.to_list(context[:data_layer][:headers] || %{})
@ -343,6 +343,7 @@ defmodule AshJsonApiWrapper.DataLayer do
headers: headers, headers: headers,
api: query.api, api: query.api,
action: action, action: action,
endpoint: AshJsonApiWrapper.DataLayer.Info.endpoint(resource, action.name),
context: context context: context
}} }}
end end
@ -668,7 +669,7 @@ defmodule AshJsonApiWrapper.DataLayer do
end end
defp do_sort({:ok, results}, %{sort: sort}) when sort not in [nil, []] do defp do_sort({:ok, results}, %{sort: sort}) when sort not in [nil, []] do
Ash.Sort.runtime_sort(results, sort) Ash.Sort.runtime_sort(results, sort, [])
end end
defp do_sort(other, _), do: other defp do_sort(other, _), do: other

View file

@ -0,0 +1,111 @@
defmodule AshJsonApiWrapper.CustomPagination.Test do
use ExUnit.Case
require Ash.Query
@moduletag :custom_pagination
# ── Custom paginator ──
defmodule CustomPaginator do
use AshJsonApiWrapper.Paginator
def cursor do
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
def increment_cursor do
:ets.insert(:cursor, {self(), cursor() + 1})
end
def reset_cursor do
:ets.insert(:cursor, {self(), 1})
end
def continue(_response, [], _) do
reset_cursor()
:halt
end
def continue(_response, _entities, _opts) do
increment_cursor()
{:ok, %{params: %{:p => cursor()}}}
end
end
# ── Resource ──
defmodule Users do
use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false
json_api_wrapper do
tesla(Tesla)
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)
users =
Users
|> Ash.Query.for_read(:list_users)
|> Api.read!(page: [limit: 99])
user_count = users.results |> Enum.count()
assert(user_count == 99)
end
end

View file

@ -6,14 +6,15 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule TopStory do defmodule TopStory do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false
json_api_wrapper do json_api_wrapper do
endpoints do endpoints do
base "https://hacker-news.firebaseio.com/v0/" base "https://hacker-news.firebaseio.com/v0/"
endpoint :read do endpoint :read do
limit_with "limitToFirst" limit_with {:param, "limitToFirst"}
path "topstories.json" path "topstories.json"
end end
end end
@ -59,7 +60,8 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule Story do defmodule Story do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false
calculations do calculations do
calculate(:short_url, :string, ShortUrl) calculate(:short_url, :string, ShortUrl)
@ -110,7 +112,8 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule User do defmodule User do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false
attributes do attributes do
attribute :id, :string do attribute :id, :string do
@ -142,7 +145,7 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule Api do defmodule Api do
@moduledoc false @moduledoc false
use Ash.Api use Ash.Api, validate_config_inclusion?: false
resources do resources do
allow_unregistered?(true) allow_unregistered?(true)

View file

@ -1,7 +1,7 @@
defmodule AshJsonApiWrapper.OpenApi.CybridTest do defmodule AshJsonApiWrapper.OpenApi.CybridTest do
use ExUnit.Case use ExUnit.Case
require Ash.Query require Ash.Query
@moduletag :oapi_cybrid
@json "test/support/cybrid.json" |> File.read!() |> Jason.decode!() @json "test/support/cybrid.json" |> File.read!() |> Jason.decode!()
@ -38,14 +38,6 @@ defmodule AshJsonApiWrapper.OpenApi.CybridTest do
] ]
] ]
defmodule Api do
use Ash.Api
resources do
allow_unregistered? true
end
end
test "it does stuff" do test "it does stuff" do
@json @json
|> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config) |> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config)

View file

@ -1,7 +1,7 @@
defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do
use ExUnit.Case use ExUnit.Case
require Ash.Query require Ash.Query
@moduletag :oapi_petstore
@json "test/support/pet_store.json" |> File.read!() |> Jason.decode!() @json "test/support/pet_store.json" |> File.read!() |> Jason.decode!()
@ -17,7 +17,7 @@ defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do
tesla: TestingTesla, tesla: TestingTesla,
endpoint: "https://petstore3.swagger.io/api/v3", endpoint: "https://petstore3.swagger.io/api/v3",
resources: [ resources: [
"Petstore.Order": [ Petstore: [
path: "/store/order/{orderId}", path: "/store/order/{orderId}",
object_type: "components.schemas.Order", object_type: "components.schemas.Order",
primary_key: "id", primary_key: "id",
@ -31,14 +31,6 @@ defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do
] ]
] ]
defmodule Api do
use Ash.Api
resources do
allow_unregistered? true
end
end
test "it does stuff" do test "it does stuff" do
@json @json
|> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config) |> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config)

View file

@ -1,7 +1,6 @@
defmodule AshJsonApiWrapper.Petstore.Test do defmodule AshJsonApiWrapper.Petstore.Test do
use ExUnit.Case use ExUnit.Case
require Ash.Query require Ash.Query
@moduletag :petstore @moduletag :petstore
defmodule TestingTesla do defmodule TestingTesla do
@ -9,8 +8,10 @@ defmodule AshJsonApiWrapper.Petstore.Test do
# plug Tesla.Middleware.Logger # plug Tesla.Middleware.Logger
end end
defmodule Petstore.Order do defmodule Petstore do
use Ash.Resource, data_layer: AshJsonApiWrapper.DataLayer use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false
json_api_wrapper do json_api_wrapper do
tesla(TestingTesla) tesla(TestingTesla)
@ -18,7 +19,7 @@ defmodule AshJsonApiWrapper.Petstore.Test do
endpoints do endpoints do
base("https://petstore3.swagger.io/api/v3") base("https://petstore3.swagger.io/api/v3")
endpoint [:find_pets_by_status, :fpbs] do endpoint [:find_pets_by_status, :by_status] do
path("/pet/findByStatus") path("/pet/findByStatus")
field :status do field :status do
@ -37,11 +38,11 @@ defmodule AshJsonApiWrapper.Petstore.Test do
actions do actions do
read(:find_pets_by_status) do read(:find_pets_by_status) do
primary? true primary? false
end end
read(:fpbs) do read(:by_status) do
primary? false primary? true
end end
read(:pet) do read(:pet) do
@ -68,8 +69,7 @@ defmodule AshJsonApiWrapper.Petstore.Test do
end end
defmodule Api do defmodule Api do
@moduledoc false use Ash.Api, validate_config_inclusion?: false
use Ash.Api
resources do resources do
allow_unregistered?(true) allow_unregistered?(true)
@ -77,19 +77,19 @@ defmodule AshJsonApiWrapper.Petstore.Test do
end end
test "it works" do test "it works" do
Petstore.Order Petstore
|> Ash.Query.for_read(:find_pets_by_status) |> Ash.Query.for_read(:find_pets_by_status)
|> Ash.Query.filter(status == "pending") |> Ash.Query.filter(status == "pending")
|> Api.read!() |> Api.read!()
Petstore.Order Petstore
|> Ash.Query.for_read(:fpbs) |> Ash.Query.for_read(:by_status)
|> Ash.Query.filter(status == "available") |> Ash.Query.filter(status == "available")
|> Api.read!() |> Api.read!()
Petstore.Order Petstore
|> Ash.Query.for_read(:pet) |> Ash.Query.for_read(:pet)
|> Ash.Query.filter(id == 1) |> Ash.Query.filter(id == 10)
|> Api.read!() |> Api.read!()
end end
end end