Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanl committed Aug 23, 2021
1 parent fab6d06 commit ffe00a0
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 56 deletions.
121 changes: 82 additions & 39 deletions lib/absinthe/relay/keyset_connection.ex
Expand Up @@ -492,65 +492,108 @@ defmodule Absinthe.Relay.KeysetConnection do
end

def keyset_params_from(%{first: _, last: _}, _opts) do
raise ArgumentError, "cannot provide both :first and :last options"
{:error, "cannot provide both :first and :last options"}
end
def keyset_params_from(%{before: _, after: _}, _opts) do
{:error, "cannot provide both :before and :after options"}
end

def keyset_params_from(%{first: n}, _opts) when is_integer(n) and n < 0 do
raise ArgumentError, "value of :first must be >= 0"
{:error, "value of :first must be >= 0"}
end

def keyset_params_from(%{last: n}, _opts) when is_integer(n) and n < 0 do
{:error, "value of :last must be >= 0"}
end

def keyset_params_from(%{first: n} = args, opts) when is_integer(n) do
keyset_column = Keyword.get(opts, :keyset_column, :id)
pagination_dir = Keyword.get(opts, :pagination_dir, :asc)

with {:ok, filters} <- get_filters(args, pagination_dir) do
{:ok, {keyset_column, filters, {:asc, pagination_dir}, n}}
def keyset_params_from(%{after: c, first: n}, opts) when is_integer(n) do
with {:ok, {keyset_column, display_dir}} <- parse_opts(opts),
{:ok, filters} <- get_filters([after: c], display_dir) do
{:ok, {keyset_column, filters, {sort, display_dir}, n}}
end
end

def keyset_params_from(%{last: n}, _opts) when is_integer(n) and n < 0 do
{:error, "value of :last must be >= 0"}
end

def keyset_params_from(%{last: n} = args, opts) when is_integer(n) do
keyset_column = Keyword.get(opts, :keyset_column, :id)
pagination_dir = Keyword.get(opts, :pagination_dir, :asc)
# def keyset_params_from(%{first: n} = args, opts) when is_integer(n) do
# keyset_column = Keyword.get(opts, :keyset_column, :id)
# display_dir = Keyword.get(opts, :display_dir, :asc)
#
# with {:ok, filters} <- get_filters(args, display_dir) do
# {:ok, {keyset_column, filters, {:asc, display_dir}, n}}
# end
# end
#
#
# def keyset_params_from(%{last: n} = args, opts) when is_integer(n) do
# keyset_column = Keyword.get(opts, :keyset_column, :id)
# display_dir = Keyword.get(opts, :display_dir, :asc)
#
# with {:ok, filters} <- get_filters(args, display_dir) do
# {:ok, {keyset_column, filters, {:desc, display_dir}, n}}
# end
# end
#
# def keyset_params_from(%{first: _, last: _} = args, opts) do
# keyset_column = Keyword.get(opts, :keyset_column, :id)
# IO.inspect(["YO DAWG", args, opts])
# nil
# end

with {:ok, filters} <- get_filters(args, pagination_dir) do
{:ok, {keyset_column, filters, {:desc, pagination_dir}, n}}
defp parse_opts(opts) do
with {:ok, keyset_column} <- parse_keyset_column_opt(opts),
{:ok, display_dir} <- parse_display_dir_opt(opts) do
{:ok, {keyset_column, display_dir}}
end
end

def keyset_params_from(%{first: _, last: _} = args, opts) do
defp parse_keyset_column_opt(opts) do
keyset_column = Keyword.get(opts, :keyset_column, :id)
IO.inspect(["YO DAWG", args, opts])
nil
if is_atom(keyset_column) do
{:ok, keyset_column}
else
{:error, {:invalid_keyset_column, keyset_column, "must be an atom"}}
end
end

defp get_filters(args, pagination_dir) do
filters =
Enum.reduce(args, %{filters: [], errors: []}, fn arg, %{filters: filters, errors: errors} ->
case arg do
# handle valid filters
{:after, n} -> %{filters: [{:>, n} | filters], errors: errors}
{:before, n} -> %{filters: [{:<, n} | filters], errors: errors}
# ignore valid limits
{:first, n} -> %{filters: filters, errors: errors}
{:last, n} -> %{filters: filters, errors: errors}
# mark anything else as an error
other -> %{filters: filters, errors: [other | errors]}
end
end)

case filters do
%{filters: filters, errors: []} ->
{:ok, filters}

%{errors: errors} ->
{:error, {:invalid_filters, errors}}
defp parse_display_dir_opt(opts) do
display_dir = Keyword.get(opts, :display_dir, :asc)
if display_dir in [:asc, :desc] do
{:ok, display_dir}
else
{:error, {:invalid_display_dir, display_dir, "must be :asc or :desc"}}
end
end

defp get_filters([after: c], :asc), do: {:ok, [{:>, c}]}
defp get_filters([after: c], :desc), do: {:ok, [{:<, c}]}
defp get_filters([before: c], :asc), do: {:ok, [{:<, c}]}
defp get_filters([before: c], :desc), do: {:ok, [{:>, c}]}

# defp get_filters(args, display_dir) do
# filters =
# Enum.reduce(args, %{filters: [], errors: []}, fn arg, %{filters: filters, errors: errors} ->
# case arg do
# # handle valid filters
# {:after, n} -> %{filters: [{:>, n} | filters], errors: errors}
# {:before, n} -> %{filters: [{:<, n} | filters], errors: errors}
# # ignore valid limits
# {:first, n} -> %{filters: filters, errors: errors}
# {:last, n} -> %{filters: filters, errors: errors}
# # mark anything else as an error
# other -> %{filters: filters, errors: [other | errors]}
# end
# end)
#
# case filters do
# %{filters: filters, errors: []} ->
# {:ok, filters}
#
# %{errors: errors} ->
# {:error, {:invalid_filters, errors}}
# end
# end

#
# @doc false
# @spec offset_and_limit_for_query(Options.t(), from_query_opts) ::
Expand Down
55 changes: 38 additions & 17 deletions test/lib/absinthe/relay/keyset_connection_test.exs
Expand Up @@ -18,10 +18,25 @@ defmodule Absinthe.Relay.KeysetConnectionTest do
end


# after: 100, first: 10 = id > 100 ORDER BY id ASC LIMIT 10
# after: 100, last: 10 = id > 100 ORDER BY id DESC LIMIT 10 # then reverse order
# before: 100, last: 10 = id < 100 ORDER BY id DESC LIMIT 10 # then reverse order
# before: 100, first: 10 = id < 100 ORDER BY id ASC LIMIT 10
# Display dir asc
# after x
# WHERE id > x ORDER BY x ASC
# first y
# WHERE id > x ORDER BY x ASC LIMIT y
# before x
# WHERE id < x ORDER BY x ASC
# last y
# WHERE id < x ORDER BY x DESC LIMIT y -- reverse
#
# Display dir desc
# after x
# WHERE id < x ORDER BY x DESC
# first y
# WHERE id < x ORDER BY x DESC LIMIT y
# before x
# WHERE id > x ORDER BY x DESC
# last y
# WHERE id > x ORDER BY x ASC LIMIT y -- reverse

# options: :keyset_column, :visible_sort

Expand All @@ -31,20 +46,26 @@ defmodule Absinthe.Relay.KeysetConnectionTest do
assert p == {:ok, {:id, [{:>, 100}], {:asc, :asc}, 10}}
end

test ":after + :first + :keyset_column" do
p = KeysetConnection.keyset_params_from(%{after: 100, first: 10}, [keyset_column: :seq])
assert p == {:ok, {:seq, [{:>, 100}], {:asc, :asc}, 10}}
end

test ":after + :first + :pagination_dir" do
p = KeysetConnection.keyset_params_from(%{after: 100, first: 10}, [pagination_dir: :desc])
assert p == {:ok, {:id, [{:>, 100}], {:desc, :desc}, 10}}
end
# test ":after" do
# p = KeysetConnection.keyset_params_from(%{after: 100})
# assert p == {:ok, {:id, [{:>, 100}], {:asc, :asc}, nil}}
# end

test ":before + :last" do
p = KeysetConnection.keyset_params_from(%{before: 100, last: 10})
assert p == {:ok, {:id, [{:<, 100}], {:desc, :asc}, 10}}
end
#
# test ":after + :first + :keyset_column" do
# p = KeysetConnection.keyset_params_from(%{after: 100, first: 10}, [keyset_column: :seq])
# assert p == {:ok, {:seq, [{:>, 100}], {:asc, :asc}, 10}}
# end
#
# test ":after + :first + :pagination_dir" do
# p = KeysetConnection.keyset_params_from(%{after: 100, first: 10}, [pagination_dir: :desc])
# assert p == {:ok, {:id, [{:>, 100}], {:desc, :desc}, 10}}
# end
#
# test ":before + :last" do
# p = KeysetConnection.keyset_params_from(%{before: 100, last: 10})
# assert p == {:ok, {:id, [{:<, 100}], {:desc, :asc}, 10}}
# end
end

# @jack_global_id Base.encode64("Person:jack")
Expand Down

0 comments on commit ffe00a0

Please sign in to comment.