Skip to content

Commit

Permalink
pass prepared cursor fields to adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
woylie committed Jul 17, 2023
1 parent 9c937f7 commit 0866d1c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 21 deletions.
19 changes: 17 additions & 2 deletions lib/flop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1147,11 +1147,13 @@ defmodule Flop do
)
when is_integer(first) do
adapter = Keyword.get(opts, :adapter, Adapter.Ecto)
struct = if module = opts[:for], do: struct(module)
orderings = prepare_order_fields_and_directions(order_by, order_directions)
decoded_cursor = decoded_cursor || Cursor.decode!(after_)
cursor_fields = prepare_cursor_fields(struct, decoded_cursor, orderings)

q
|> adapter.apply_cursor(decoded_cursor, orderings, opts)
|> adapter.apply_cursor(cursor_fields, opts)
|> adapter.apply_limit_offset(first + 1, nil, opts)
end

Expand Down Expand Up @@ -1187,22 +1189,35 @@ defmodule Flop do
)
when is_integer(last) do
adapter = Keyword.get(opts, :adapter, Adapter.Ecto)
struct = if module = opts[:for], do: struct(module)

orderings =
order_by
|> prepare_order_fields_and_directions(order_directions)
|> reverse_ordering()

decoded_cursor = decoded_cursor || Cursor.decode!(before)
cursor_fields = prepare_cursor_fields(struct, decoded_cursor, orderings)

q
|> adapter.apply_cursor(decoded_cursor, orderings, opts)
|> adapter.apply_cursor(cursor_fields, opts)
# add 1 to limit, so that we know whether there are more items to show
|> adapter.apply_limit_offset(last + 1, nil, opts)
end

def paginate(q, _, _), do: q

@spec prepare_cursor_fields(struct | nil, map, [{atom, atom}]) :: [
{order_direction(), atom, any, Flop.FieldInfo.t()}
]
defp prepare_cursor_fields(struct, decoded_cursor, ordering) do
Enum.map(ordering, fn {direction, field} ->
field_info = struct && Flop.Schema.field_info(struct, field)
cursor_value = Map.get(decoded_cursor, field)
{direction, field, cursor_value, field_info}
end)
end

@spec reverse_ordering([order_direction()]) :: [order_direction()]
defp reverse_ordering(order_directions) do
Enum.map(order_directions, fn
Expand Down
7 changes: 4 additions & 3 deletions lib/flop/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ defmodule Flop.Adapter do

@type queryable :: term
@type opts :: keyword
@type cursor_fields :: [
{Flop.order_direction(), atom, any, Flop.FieldInfo.t()}
]

@callback init_backend_opts(keyword, keyword, module) :: keyword

Expand Down Expand Up @@ -30,9 +33,7 @@ defmodule Flop.Adapter do
@callback apply_page_page_size(queryable, page, page_size, opts) :: queryable
when page: pos_integer, page_size: pos_integer

@callback apply_cursor(queryable, decoded_cursor, order_directions, opts) ::
queryable
when decoded_cursor: map, order_directions: keyword
@callback apply_cursor(queryable, cursor_fields, opts) :: queryable

@callback count(queryable, opts) :: non_neg_integer

Expand Down
18 changes: 2 additions & 16 deletions lib/flop/adapter/ecto.ex
Original file line number Diff line number Diff line change
Expand Up @@ -292,25 +292,11 @@ defmodule Flop.Adapter.Ecto do
end

@impl Flop.Adapter
def apply_cursor(q, %{} = decoded_cursor, ordering, opts) do
struct = if module = opts[:for], do: struct(module)

where_dynamic =
struct
|> prepare_cursor_fields(decoded_cursor, ordering)
|> cursor_dynamic()

def apply_cursor(q, cursor_fields, _opts) do
where_dynamic = cursor_dynamic(cursor_fields)
Query.where(q, ^where_dynamic)
end

defp prepare_cursor_fields(struct, decoded_cursor, ordering) do
Enum.map(ordering, fn {direction, field} ->
field_info = struct && Flop.Schema.field_info(struct, field)
cursor_value = Map.get(decoded_cursor, field)
{direction, field, cursor_value, field_info}
end)
end

defp cursor_dynamic([]), do: true

defp cursor_dynamic([{_, _, _, %FieldInfo{extra: %{type: :compound}}} | t]) do
Expand Down

0 comments on commit 0866d1c

Please sign in to comment.