defmodule Mix.Tasks.Absinthe.Gen.Resolver do use Mix.Task alias Mix.AbsintheGeneratorUtils @shortdoc "Generates an absinthe resolver" @moduledoc """ Generates an Absinthe Schema ### Options #{NimbleOptions.docs(AbsintheGenerator.Resolver.definitions())} ### Specifying Middleware To specify middleware we can utilize the following syntax ```bash pre_middleware:mutation:AuthMiddleware post_middleware:all:ChangesetErrorFormatter ``` Middleware can be set for `mutation`, `query`, `subscription` or `all` and can also be set to either run pre or post resolution using `pre_middleware` or `post_middleware` ### Example ```bash mix absinthe.gen.resolver func_name:2:MyModule.function --app-name MyApp --resolver-name students --moduledoc "this is the test" ``` """ @resolver_regex ~r/^[a-z_]+(:(with_parent|with_resolution|with_parent:with_resolution)){0,1}:[A-Za-z]+\.[a-z_]+$/ def run(args) do AbsintheGeneratorUtils.ensure_not_in_umbrella!("absinthe.gen.resolver") {args, extra_args} = AbsintheGeneratorUtils.parse_path_opts(args, [ path: :string, app_name: :string, moduledoc: :string, resolver_name: :string ]) parsed_resolver_functions = extra_args |> validate_resolver_string |> parse_resolver_functions args |> Map.new |> Map.put(:resolver_functions, parsed_resolver_functions) |> serialize_to_resolver_struct |> AbsintheGenerator.Resolver.run |> AbsintheGeneratorUtils.write_template(path_from_args(args)) end defp path_from_args(args) do Keyword.get( args, :path, "./lib/#{Macro.underscore(args[:app_name])}_web/resolvers/#{Macro.underscore(args[:resolver_name])}.ex" ) end defp validate_resolver_string(resolver_parts) do if resolver_parts === [] or Enum.all?(resolver_parts, &Regex.match?(@resolver_regex, &1)) do resolver_parts else Mix.raise(""" \n Resolver format isn't setup properly and must match the following regex #{inspect @resolver_regex} Example: func_name:MyModule.function all_users:with_parent:Account.all_users all_users:with_resolution:Account.all_users all_users:with_parent:with_resolution:Account.all_users """) end end defp parse_resolver_functions(parsed_resolver_functions) do Enum.map(parsed_resolver_functions, fn resolver_function -> case String.split(resolver_function, ":") do [resolver_func_name, fn_name] -> """ def #{resolver_func_name}(params, _resolution) do #{fn_name}(params) end """ [resolver_func_name, "with_parent", "with_resolution", fn_name] -> """ def #{resolver_func_name}(params, parent, resolution) do #{fn_name}(params, parent, resolution) end """ [resolver_func_name, "with_parent", fn_name] -> """ def #{resolver_func_name}(params, parent) do #{fn_name}(params, parent) end """ [resolver_func_name, "with_resolution", fn_name] -> """ def #{resolver_func_name}(params, resolution) do #{fn_name}(params, resolution) end """ end end) end defp serialize_to_resolver_struct(params) do %AbsintheGenerator.Resolver{ app_name: params[:app_name], moduledoc: params[:moduledoc], resolver_name: params[:resolver_name], resolver_functions: params[:resolver_functions] } end end