Skip to content

Commit 5512978

Browse files
committed
Add optional ordinal comparison fun
1 parent 6601cc5 commit 5512978

File tree

4 files changed

+101
-22
lines changed

4 files changed

+101
-22
lines changed

lib/absinthe.ex

+6-1
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,15 @@ defmodule Absinthe do
4646

4747
@type continuations_t :: nil | [Absinthe.Blueprint.Continuation.t()]
4848

49+
@type ordinal_fun :: (term() -> term())
50+
51+
@type ordinal_compare_fun :: (term(), term() -> {boolean(), term()})
52+
4953
@type result_t ::
5054
%{
5155
required(:data) => nil | result_selection_t,
52-
optional(:ordinal) => term(),
56+
optional(:ordinal_fun) => ordinal_fun(),
57+
optional(:ordinal_compare_fun) => ordinal_compare_fun(),
5358
optional(:continuation) => continuations_t,
5459
optional(:errors) => [result_error_t]
5560
}

lib/absinthe/phase/subscription/get_ordinal.ex

+28-4
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,44 @@ defmodule Absinthe.Phase.Subscription.GetOrdinal do
1111
def run(blueprint, _options \\ []) do
1212
with %{type: :subscription, selections: [field]} <- Blueprint.current_operation(blueprint),
1313
{:ok, config} = SubscribeSelf.get_config(field, blueprint.execution.context, blueprint),
14-
ordinal_fun when is_function(ordinal_fun, 1) <- config[:ordinal] do
15-
result = ordinal_fun.(blueprint.execution.root_value)
16-
{:ok, %{blueprint | result: Map.put(blueprint.result, :ordinal, result)}}
14+
{_, ordinal_fun} when is_function(ordinal_fun, 1) <- {:ordinal_fun, config[:ordinal]},
15+
{_, ordinal_compare_fun} when is_function(ordinal_compare_fun, 2) <-
16+
{:ordinal_compare_fun,
17+
Keyword.get(config, :ordinal_compare, &default_ordinal_compare/2)} do
18+
ordinal = ordinal_fun.(blueprint.execution.root_value)
19+
20+
result =
21+
blueprint.result
22+
|> Map.put(:ordinal, ordinal)
23+
|> Map.put(:ordinal_compare_fun, ordinal_compare_fun)
24+
25+
{:ok, %{blueprint | result: result}}
1726
else
18-
f when is_function(f) ->
27+
{:ordinal_fun, f} when is_function(f) ->
1928
IO.write(
2029
:stderr,
2130
"Ordinal function must be 1-arity"
2231
)
2332

2433
{:ok, blueprint}
2534

35+
{:ordinal_compare_fun, f} when is_function(f) ->
36+
IO.write(
37+
:stderr,
38+
"Ordinal compare function must be 2-arity"
39+
)
40+
41+
{:ok, blueprint}
42+
2643
_ ->
2744
{:ok, blueprint}
2845
end
2946
end
47+
48+
defp default_ordinal_compare(nil, new_ordinal), do: {true, new_ordinal}
49+
50+
defp default_ordinal_compare(old_ordinal, new_ordinal) when old_ordinal < new_ordinal,
51+
do: {true, new_ordinal}
52+
53+
defp default_ordinal_compare(old_ordinal, _new_ordinal), do: {false, old_ordinal}
3054
end

lib/absinthe/phase/subscription/result.ex

+13-17
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,15 @@ defmodule Absinthe.Phase.Subscription.Result do
1212
def run(blueprint, options) do
1313
topic = Keyword.fetch!(options, :topic)
1414
prime = Keyword.get(options, :prime)
15-
result = %{"subscribed" => topic}
1615

17-
case prime do
18-
nil ->
19-
{:ok, put_in(blueprint.result, result)}
16+
result = maybe_add_prime(%{"subscribed" => topic}, prime, blueprint, options)
2017

21-
prime_fun when is_function(prime_fun, 1) ->
22-
stash_prime(prime_fun, result, blueprint, options)
23-
24-
val ->
25-
raise """
26-
Invalid prime function. Must be a function of arity 1.
27-
28-
#{inspect(val)}
29-
"""
30-
end
18+
{:ok, put_in(blueprint.result, result)}
3119
end
3220

33-
def stash_prime(prime_fun, base_result, blueprint, options) do
21+
def maybe_add_prime(result, nil, _blueprint, _options), do: result
22+
23+
def maybe_add_prime(result, prime_fun, blueprint, options) when is_function(prime_fun, 1) do
3424
continuation = %Continuation{
3525
phase_input: blueprint,
3626
pipeline: [
@@ -41,8 +31,14 @@ defmodule Absinthe.Phase.Subscription.Result do
4131
]
4232
}
4333

44-
result = Map.put(base_result, :continuations, [continuation])
34+
Map.put(result, :continuations, [continuation])
35+
end
4536

46-
{:ok, put_in(blueprint.result, result)}
37+
def maybe_add_prime(_result, prime_fun, _blueprint, _options) do
38+
raise """
39+
Invalid prime function. Must be a function of arity 1.
40+
41+
#{inspect(prime_fun)}
42+
"""
4743
end
4844
end

test/absinthe/execution/subscription_test.exs

+54
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,23 @@ defmodule Absinthe.Execution.SubscriptionTest do
174174
}
175175
end
176176
end
177+
178+
field :prime_ordinal_with_compare, :user do
179+
arg :client_id, non_null(:id)
180+
arg :prime_data, list_of(:string)
181+
182+
config fn args, _ ->
183+
{
184+
:ok,
185+
topic: args.client_id,
186+
prime: fn _ ->
187+
{:ok, [%{name: "first_user", version: 1}, %{name: "second_user", version: 2}]}
188+
end,
189+
ordinal: fn %{version: version} -> version end,
190+
ordinal_compare: &custom_ordinal_compare/2
191+
}
192+
end
193+
end
177194
end
178195

179196
mutation do
@@ -185,6 +202,10 @@ defmodule Absinthe.Execution.SubscriptionTest do
185202
end
186203
end
187204
end
205+
206+
def custom_ordinal_compare(a, b) do
207+
{a > b, b + 0.5}
208+
end
188209
end
189210

190211
setup_all do
@@ -761,6 +782,39 @@ defmodule Absinthe.Execution.SubscriptionTest do
761782
Absinthe.continue(continuations)
762783
end
763784

785+
@query """
786+
subscription ($clientId: ID!) {
787+
primeOrdinalWithCompare(clientId: $clientId) {
788+
name
789+
}
790+
}
791+
"""
792+
test "subscription with priming, ordinals, and custom ordinal compare function" do
793+
client_id = "abc"
794+
795+
assert {:more, %{"subscribed" => _topic, continuations: continuations}} =
796+
run_subscription(
797+
@query,
798+
Schema,
799+
variables: %{
800+
"clientId" => client_id
801+
}
802+
)
803+
804+
assert {:more,
805+
%{
806+
data: %{"primeOrdinalWithCompare" => %{"name" => "first_user"}},
807+
ordinal: 1,
808+
ordinal_compare_fun: custom_ordinal_compare,
809+
continuations: continuations
810+
}} = Absinthe.continue(continuations)
811+
812+
assert custom_ordinal_compare.(1, 2) == {false, 2.5}
813+
814+
assert {:ok, %{data: %{"primeOrdinalWithCompare" => %{"name" => "second_user"}}, ordinal: 2}} =
815+
Absinthe.continue(continuations)
816+
end
817+
764818
defp run_subscription(query, schema, opts \\ []) do
765819
opts = Keyword.update(opts, :context, %{pubsub: PubSub}, &Map.put(&1, :pubsub, PubSub))
766820

0 commit comments

Comments
 (0)