Skip to content

Commit c2fd5ec

Browse files
authored
feat: subscription installer (#266)
* remove subscription opt in
1 parent 14fd94e commit c2fd5ec

File tree

8 files changed

+316
-70
lines changed

8 files changed

+316
-70
lines changed

config/config.exs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ config :ash, :validate_domain_config_inclusion?, false
77
config :ash, :pub_sub, debug?: true
88
config :logger, level: :info
99

10-
config :ash_graphql, :subscriptions, true
11-
1210
if Mix.env() == :test do
1311
config :ash_graphql, :simulate_subscription_slowness?, true
1412
end

lib/igniter.ex

Lines changed: 138 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ if Code.ensure_loaded?(Igniter) do
147147
end
148148

149149
@doc "Sets up the phoenix module for AshGraphql"
150-
def setup_phoenix(igniter, schema_name \\ nil) do
150+
def setup_phoenix(igniter, schema_name \\ nil, socket_name \\ nil) do
151151
schema_name = schema_name || Igniter.Project.Module.module_name(igniter, "GraphqlSchema")
152+
socket_name = socket_name || Igniter.Project.Module.module_name(igniter, "GraphqlSocket")
152153

153154
case Igniter.Libs.Phoenix.select_router(igniter) do
154155
{igniter, nil} ->
@@ -162,78 +163,176 @@ if Code.ensure_loaded?(Igniter) do
162163

163164
{igniter, router} ->
164165
igniter
165-
|> update_endpoints(router)
166-
|> Igniter.Libs.Phoenix.add_pipeline(:graphql, "plug AshGraphql.Plug", router: router)
167-
|> Igniter.Libs.Phoenix.add_scope(
168-
"/gql",
169-
"""
170-
pipe_through [:graphql]
171-
172-
forward "/playground",
173-
Absinthe.Plug.GraphiQL,
174-
schema: Module.concat(["#{inspect(schema_name)}"]),
175-
interface: :playground
176-
177-
forward "/",
178-
Absinthe.Plug,
179-
schema: Module.concat(["#{inspect(schema_name)}"])
180-
""",
181-
router: router
182-
)
166+
|> create_socket(schema_name, socket_name)
167+
|> update_router(router, socket_name, schema_name)
168+
|> update_application(router)
183169
end
184170
end
185171

172+
defp update_router(igniter, router, socket_name, schema_name) do
173+
igniter
174+
|> update_endpoints(router, socket_name)
175+
|> Igniter.Libs.Phoenix.add_pipeline(:graphql, "plug AshGraphql.Plug", router: router)
176+
|> Igniter.Libs.Phoenix.add_scope(
177+
"/gql",
178+
"""
179+
pipe_through [:graphql]
180+
181+
forward "/playground",
182+
Absinthe.Plug.GraphiQL,
183+
schema: Module.concat(["#{inspect(schema_name)}"]),
184+
socket: Module.concat(["#{inspect(socket_name)}"]),
185+
interface: :playground
186+
187+
forward "/",
188+
Absinthe.Plug,
189+
schema: Module.concat(["#{inspect(schema_name)}"])
190+
""",
191+
router: router
192+
)
193+
end
194+
195+
defp update_application(igniter, router) do
196+
{igniter, endpoints} =
197+
Igniter.Libs.Phoenix.endpoints_for_router(igniter, router)
198+
199+
igniter =
200+
Enum.reduce(endpoints, igniter, fn endpoint, igniter ->
201+
igniter
202+
|> Igniter.Project.Application.add_new_child({Absinthe.Subscription, endpoint},
203+
after: endpoint
204+
)
205+
end)
206+
207+
igniter
208+
|> Igniter.Project.Application.add_new_child(AshGraphql.Subscription.Batcher,
209+
after: Absinthe.Subscription
210+
)
211+
end
212+
213+
defp create_socket(igniter, schema_name, socket_name) do
214+
otp_app = Igniter.Project.Application.app_name(igniter)
215+
216+
igniter
217+
|> Igniter.Project.Module.find_and_update_or_create_module(
218+
socket_name,
219+
"""
220+
use Phoenix.Socket
221+
222+
use Absinthe.Phoenix.Socket,
223+
schema: #{inspect(schema_name)}
224+
225+
@otp_app #{inspect(otp_app)}
226+
227+
@impl true
228+
def connect(_params, socket, _connect_info) do
229+
{:ok, socket}
230+
end
231+
232+
@impl true
233+
def id(_socket), do: nil
234+
""",
235+
fn zipper ->
236+
# Should never get here
237+
{:ok, zipper}
238+
end
239+
)
240+
end
241+
186242
@doc "Returns all modules that `use AshGraphql`"
187243
def ash_graphql_schemas(igniter) do
188244
Igniter.Project.Module.find_all_matching_modules(igniter, fn _name, zipper ->
189245
match?({:ok, _}, Igniter.Code.Module.move_to_use(zipper, AshGraphql))
190246
end)
191247
end
192248

193-
defp update_endpoints(igniter, router) do
249+
defp update_endpoints(igniter, router, socket_name) do
194250
{igniter, endpoints_that_need_parser} =
195251
Igniter.Libs.Phoenix.endpoints_for_router(igniter, router)
196252

253+
igniter =
254+
Enum.reduce(endpoints_that_need_parser, igniter, fn endpoint, igniter ->
255+
Igniter.Project.Module.find_and_update_module!(igniter, endpoint, fn zipper ->
256+
case Igniter.Code.Function.move_to_function_call_in_current_scope(
257+
zipper,
258+
:plug,
259+
2,
260+
&Igniter.Code.Function.argument_equals?(&1, 0, Plug.Parsers)
261+
) do
262+
{:ok, zipper} ->
263+
with {:ok, zipper} <- Igniter.Code.Function.move_to_nth_argument(zipper, 1),
264+
{:ok, zipper} <- Igniter.Code.Keyword.get_key(zipper, :parsers),
265+
{:ok, zipper} <-
266+
Igniter.Code.List.append_new_to_list(zipper, Absinthe.Plug.Parser) do
267+
{:ok, zipper}
268+
else
269+
_ ->
270+
{:warning,
271+
"Could not add `Absinthe.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
272+
end
273+
274+
:error ->
275+
case parser_location(zipper) do
276+
{:ok, zipper} ->
277+
{:ok,
278+
Igniter.Code.Common.add_code(zipper, """
279+
plug Plug.Parsers,
280+
parsers: [:urlencoded, :multipart, :json, Absinthe.Plug.Parser],
281+
pass: ["*/*"],
282+
json_decoder: Jason
283+
""")}
284+
285+
_ ->
286+
{:warning,
287+
"Could not add `Absinthe.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
288+
end
289+
end
290+
end)
291+
end)
292+
197293
Enum.reduce(endpoints_that_need_parser, igniter, fn endpoint, igniter ->
198294
Igniter.Project.Module.find_and_update_module!(igniter, endpoint, fn zipper ->
199295
case Igniter.Code.Function.move_to_function_call_in_current_scope(
200296
zipper,
201-
:plug,
202-
2,
203-
&Igniter.Code.Function.argument_equals?(&1, 0, Plug.Parsers)
297+
:socket,
298+
3,
299+
&Igniter.Code.Function.argument_equals?(&1, 1, socket_name)
204300
) do
205301
{:ok, zipper} ->
206-
with {:ok, zipper} <- Igniter.Code.Function.move_to_nth_argument(zipper, 1),
207-
{:ok, zipper} <- Igniter.Code.Keyword.get_key(zipper, :parsers),
208-
{:ok, zipper} <-
209-
Igniter.Code.List.append_new_to_list(zipper, Absinthe.Plug.Parser) do
210-
{:ok, zipper}
211-
else
212-
_ ->
213-
{:warning,
214-
"Could not add `Absinthe.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
215-
end
302+
# Already installed
303+
{:ok, zipper}
216304

217305
:error ->
218-
case parser_location(zipper) do
306+
case socket_location(zipper) do
219307
{:ok, zipper} ->
220308
{:ok,
221309
Igniter.Code.Common.add_code(zipper, """
222-
plug Plug.Parsers,
223-
parsers: [:urlencoded, :multipart, :json, Absinthe.Plug.Parser],
224-
pass: ["*/*"],
225-
json_decoder: Jason
310+
socket "/ws/gql", #{inspect(socket_name)},
311+
websocket: true,
312+
longpoll: true
226313
""")}
227314

228315
_ ->
229316
{:warning,
230-
"Could not add `Absinthe.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
317+
"Could not add #{socket_name} in endpoint #{endpoint}. Please make this change manually."}
231318
end
232319
end
233320
end)
234321
end)
235322
end
236323

324+
defp socket_location(zipper) do
325+
with :error <-
326+
Igniter.Code.Function.move_to_function_call_in_current_scope(
327+
zipper,
328+
:socket,
329+
3,
330+
&Igniter.Code.Function.argument_equals?(&1, 1, Phoenix.LiveView.Socket)
331+
) do
332+
Igniter.Code.Module.move_to_use(zipper, Phoenix.Endpoint)
333+
end
334+
end
335+
237336
defp parser_location(zipper) do
238337
with :error <-
239338
Igniter.Code.Function.move_to_function_call_in_current_scope(

lib/mix/tasks/ash_graphql.install.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ if Code.ensure_loaded?(Igniter) do
1515
|> Spark.Igniter.prepend_to_section_order(:"Ash.Domain", [:graphql])
1616

1717
schema_name = Igniter.Libs.Phoenix.web_module_name(igniter, "GraphqlSchema")
18+
socket_name = Igniter.Libs.Phoenix.web_module_name(igniter, "GraphqlSocket")
1819

1920
{igniter, candidate_ash_graphql_schemas} =
2021
AshGraphql.Igniter.ash_graphql_schemas(igniter)
2122

2223
if Enum.empty?(candidate_ash_graphql_schemas) do
2324
igniter
2425
|> AshGraphql.Igniter.setup_absinthe_schema(schema_name)
25-
|> AshGraphql.Igniter.setup_phoenix(schema_name)
26+
|> AshGraphql.Igniter.setup_phoenix(schema_name, socket_name)
2627
else
2728
igniter
2829
|> Igniter.add_warning("AshGraphql schema already exists, skipping installation.")

lib/resource/resource.ex

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,7 @@ defmodule AshGraphql.Resource do
467467
@verifiers [
468468
AshGraphql.Resource.Verifiers.VerifyQueryMetadata,
469469
AshGraphql.Resource.Verifiers.RequirePkeyDelimiter,
470-
AshGraphql.Resource.Verifiers.VerifyPaginateRelationshipWith,
471-
AshGraphql.Resource.Verifiers.VerifySubscriptionOptIn
470+
AshGraphql.Resource.Verifiers.VerifyPaginateRelationshipWith
472471
]
473472

474473
@sections [@graphql]

lib/resource/verifiers/verify_subscription_opt_in.ex

Lines changed: 0 additions & 23 deletions
This file was deleted.

mix.exs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ defmodule AshGraphql.MixProject do
155155
{:absinthe, "~> 1.7"},
156156
{:absinthe_phoenix, "~> 2.0.0", optional: true},
157157
{:jason, "~> 1.2"},
158-
{:igniter, "~> 0.3 and >= 0.3.34", optional: true},
158+
{:igniter, "~> 0.5 and >= 0.5.28", optional: true},
159159
{:spark, "~> 2.2 and >= 2.2.10"},
160160
{:owl, "~> 0.11"},
161161
# dev/test dependencies
@@ -168,7 +168,8 @@ defmodule AshGraphql.MixProject do
168168
{:mix_test_watch, "~> 1.0", only: :dev, runtime: false},
169169
{:simple_sat, ">= 0.0.0", only: :test},
170170
{:mix_audit, ">= 0.0.0", only: [:dev, :test], runtime: false},
171-
{:benchee, "~> 1.1", only: [:dev, :test]}
171+
{:benchee, "~> 1.1", only: [:dev, :test]},
172+
{:phx_new, "~> 1.7", only: [:test]}
172173
]
173174
end
174175

mix.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"git_ops": {:hex, :git_ops, "2.7.0", "fed1400d516d06810ac46a9d4b3e12ca4973683158ddc5931935567075ff1a4c", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "29f1ddb3678969cb81dc56177d0c6e5c85a77a7ce50036207b920005cc6b5b26"},
2323
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
2424
"hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"},
25-
"igniter": {:hex, :igniter, "0.5.25", "a9e26794efe4b5619edd112b2ce8ffa3931f1e4d558dfebcd344553024e359b5", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "d944d3ed8439bb2d98391f39b86305d109f4123c947061db54c1c0f9ecad890e"},
25+
"igniter": {:hex, :igniter, "0.5.28", "db2cf71ac6f33b0c6893a0fad4fa218f07fa993c3b0e5d7295ff451d7d112312", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "44cf39a35defd5678f751d69bae68280dc7327243e14d00c365267d993d0b9c7"},
2626
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
2727
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
2828
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
@@ -41,6 +41,7 @@
4141
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
4242
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
4343
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
44+
"phx_new": {:hex, :phx_new, "1.7.20", "ba8eab3438a6c3524298cdfb44f9cee59af0935fffa4b40cbd07fe739f9ac93f", [:mix], [], "hexpm", "006bc4d57a9e1606fdf0776543f70e23cbd8b64b706b95d280b4d420f22d1d43"},
4445
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
4546
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
4647
"reactor": {:hex, :reactor, "0.13.3", "8d49362564970c3331ba306213bc2416c682a04bfab0f710ac3c740060bbdc71", [:mix], [{:igniter, "~> 0.4", [hex: :igniter, repo: "hexpm", optional: true]}, {:iterex, "~> 0.1", [hex: :iterex, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b8227ed82a2aabaedc24a09e347002bb14c58701989d7383c51e941e03085180"},

0 commit comments

Comments
 (0)