Skip to content

Commit

Permalink
Compile-Time Resolver Validations (#16)
Browse files Browse the repository at this point in the history
* Ignore tool-versions

* Add unit test for validations on validating resolver function definitions

* Validate resolver functions after compiling workflow graph

* Organize validate_resolvers/1 implementation into a pipeline
  • Loading branch information
zkayser authored Apr 18, 2024
1 parent c757b55 commit f1f3e40
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ pacer-*.tar

# Temporary files, for example, from tests.
/tmp/

/.tool-versions
21 changes: 21 additions & 0 deletions lib/workflow.ex
Original file line number Diff line number Diff line change
Expand Up @@ -905,10 +905,31 @@ defmodule Pacer.Workflow do
@spec __after_compile__(Macro.Env.t(), binary()) :: :ok | no_return()
def __after_compile__(%{module: module} = _env, _) do
_ = validate_dependencies(module)
_ = validate_resolvers(module)

:ok
end

defp validate_resolvers(module) do
module
|> Module.get_attribute(:pacer_resolvers)
|> Enum.map(fn {field, resolver_fun} ->
resolver_fun
|> Function.info()
|> Map.new()
|> then(fn info ->
unless function_exported?(info.module, info.name, info.arity) do
raise Error, """
Resolver for field `#{inspect(field)}` is undefined. Ensure that the resolver you intend to use
has been defined and you have no mispellings.
Resolver Function: #{inspect(resolver_fun)}
"""
end
end)
end)
end

@spec ensure_no_duplicate_fields(module(), atom()) :: :ok | no_return()
defp ensure_no_duplicate_fields(module, field_name) do
if Enum.member?(Module.get_attribute(module, :pacer_fields), field_name) do
Expand Down
24 changes: 24 additions & 0 deletions test/workflow_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,30 @@ defmodule Pacer.WorkflowTest do
Code.eval_string(module)
end
end

test "alerts users when a resolver function does not exist" do
module = """
defmodule GraphWithInvalidResolver do
use Pacer.Workflow
graph do
field(:a, resolver: &NonExistentModule.mispelled_function/1, dependencies: [:b])
field(:b, default: "foo")
end
end
"""

expected_error_message = """
Resolver for field `:a` is undefined. Ensure that the resolver you intend to use
has been defined and you have no mispellings.
Resolver Function: &NonExistentModule.mispelled_function/1
"""

assert_raise Error, expected_error_message, fn ->
Code.eval_string(module)
end
end
end

describe "batch validations" do
Expand Down

0 comments on commit f1f3e40

Please sign in to comment.