Skip to content

Commit

Permalink
fix: restore support for custom paginators (ash-project#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterhartman authored Oct 26, 2023
1 parent 2c8fe82 commit 4ecdcea
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 40 deletions.
5 changes: 3 additions & 2 deletions lib/data_layer/data_layer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ defmodule AshJsonApiWrapper.DataLayer do
end

@impl true
def set_context(_resource, query, context) do
def set_context(resource, query, context) do
params = context[:data_layer][:query_params] || %{}
headers = Map.to_list(context[:data_layer][:headers] || %{})

Expand All @@ -343,6 +343,7 @@ defmodule AshJsonApiWrapper.DataLayer do
headers: headers,
api: query.api,
action: action,
endpoint: AshJsonApiWrapper.DataLayer.Info.endpoint(resource, action.name),
context: context
}}
end
Expand Down Expand Up @@ -668,7 +669,7 @@ defmodule AshJsonApiWrapper.DataLayer do
end

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

defp do_sort(other, _), do: other
Expand Down
111 changes: 111 additions & 0 deletions test/custom_pagination_test.exs
Original file line number Diff line number Diff line change
@@ -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
13 changes: 8 additions & 5 deletions test/hackernews_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule TopStory do
@moduledoc false
use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false

json_api_wrapper do
endpoints do
base "https://hacker-news.firebaseio.com/v0/"

endpoint :read do
limit_with "limitToFirst"
limit_with {:param, "limitToFirst"}
path "topstories.json"
end
end
Expand Down Expand Up @@ -59,7 +60,8 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule Story do
@moduledoc false
use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false

calculations do
calculate(:short_url, :string, ShortUrl)
Expand Down Expand Up @@ -110,7 +112,8 @@ defmodule AshJsonApiWrapper.Hackernews.Test do
defmodule User do
@moduledoc false
use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false

attributes do
attribute :id, :string do
Expand Down Expand Up @@ -142,7 +145,7 @@ defmodule AshJsonApiWrapper.Hackernews.Test do

defmodule Api do
@moduledoc false
use Ash.Api
use Ash.Api, validate_config_inclusion?: false

resources do
allow_unregistered?(true)
Expand Down
10 changes: 1 addition & 9 deletions test/open_api_cybrid_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule AshJsonApiWrapper.OpenApi.CybridTest do
use ExUnit.Case

require Ash.Query
@moduletag :oapi_cybrid

@json "test/support/cybrid.json" |> File.read!() |> Jason.decode!()

Expand Down Expand Up @@ -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
@json
|> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config)
Expand Down
12 changes: 2 additions & 10 deletions test/open_api_petstore_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do
use ExUnit.Case

require Ash.Query
@moduletag :oapi_petstore

@json "test/support/pet_store.json" |> File.read!() |> Jason.decode!()

Expand All @@ -17,7 +17,7 @@ defmodule AshJsonApiWrapper.OpenApi.PetstoreTest do
tesla: TestingTesla,
endpoint: "https://petstore3.swagger.io/api/v3",
resources: [
"Petstore.Order": [
Petstore: [
path: "/store/order/{orderId}",
object_type: "components.schemas.Order",
primary_key: "id",
Expand All @@ -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
@json
|> AshJsonApiWrapper.OpenApi.ResourceGenerator.generate(@config)
Expand Down
28 changes: 14 additions & 14 deletions test/petstore_test.exs
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
defmodule AshJsonApiWrapper.Petstore.Test do
use ExUnit.Case
require Ash.Query

@moduletag :petstore

defmodule TestingTesla do
use Tesla
# plug Tesla.Middleware.Logger
end

defmodule Petstore.Order do
use Ash.Resource, data_layer: AshJsonApiWrapper.DataLayer
defmodule Petstore do
use Ash.Resource,
data_layer: AshJsonApiWrapper.DataLayer,
validate_api_inclusion?: false

json_api_wrapper do
tesla(TestingTesla)

endpoints do
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")

field :status do
Expand All @@ -37,11 +38,11 @@ defmodule AshJsonApiWrapper.Petstore.Test do

actions do
read(:find_pets_by_status) do
primary? true
primary? false
end

read(:fpbs) do
primary? false
read(:by_status) do
primary? true
end

read(:pet) do
Expand All @@ -68,28 +69,27 @@ defmodule AshJsonApiWrapper.Petstore.Test do
end

defmodule Api do
@moduledoc false
use Ash.Api
use Ash.Api, validate_config_inclusion?: false

resources do
allow_unregistered?(true)
end
end

test "it works" do
Petstore.Order
Petstore
|> Ash.Query.for_read(:find_pets_by_status)
|> Ash.Query.filter(status == "pending")
|> Api.read!()

Petstore.Order
|> Ash.Query.for_read(:fpbs)
Petstore
|> Ash.Query.for_read(:by_status)
|> Ash.Query.filter(status == "available")
|> Api.read!()

Petstore.Order
Petstore
|> Ash.Query.for_read(:pet)
|> Ash.Query.filter(id == 1)
|> Ash.Query.filter(id == 10)
|> Api.read!()
end
end

0 comments on commit 4ecdcea

Please sign in to comment.