mirror of
https://github.com/ash-project/ash_json_api_wrapper.git
synced 2024-09-21 13:52:59 +12:00
fix: restore support for custom paginators (#6)
This commit is contained in:
parent
2c8fe82ff1
commit
4ecdcea91e
6 changed files with 139 additions and 40 deletions
|
@ -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
|
||||||
|
|
111
test/custom_pagination_test.exs
Normal file
111
test/custom_pagination_test.exs
Normal 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
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue