Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix description function calls #1005

Merged
merged 54 commits into from
Dec 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
20e463a
Merge pull request #2 from absinthe-graphql/master
software-opal Oct 12, 2020
fb08870
Merge branch 'master' of github.com:absinthe-graphql/absinthe
dylan-chong Dec 15, 2020
792f1da
Merge pull request #3 from solvedata/pull/upstream-master
justinakoh Dec 15, 2020
a8c4f1a
Add test for macro testing and fix bug in function
justinakoh Dec 15, 2020
d0240ad
Fix description function evaluation
justinakoh Dec 16, 2020
f390aeb
Add new tests testing normal functions to ensure expected behaviour
justinakoh Dec 16, 2020
a1bb493
Update formatting and layout of tests
justinakoh Dec 16, 2020
cc8a053
Update tests to reduce duplications
justinakoh Dec 16, 2020
44fe0ae
Formatting and adding in one more test for string:
justinakoh Dec 16, 2020
4bd51be
Fix description block
dylan-chong Dec 16, 2020
a9bc536
Fix enum with description param
dylan-chong Dec 16, 2020
f962b93
Remove wrap_in_reformat_description for consistency between descriptions
dylan-chong Dec 16, 2020
c29c262
Description for input_object
dylan-chong Dec 16, 2020
65618af
Fix object
dylan-chong Dec 16, 2020
bccf70a
Fix field description kw arg
dylan-chong Dec 16, 2020
a28730b
Fix arg kw arg
dylan-chong Dec 16, 2020
ec144b4
Fix update description
dylan-chong Dec 16, 2020
4f82158
Remember to commit function wrap_in_unquote
dylan-chong Dec 16, 2020
e39ec48
Merge pull request #4 from solvedata/fix/description-evaluation
justinakoh Dec 16, 2020
95480bc
Update test files to be in a separate module
justinakoh Dec 17, 2020
0aaf957
Update code tp include tests for description attribute
justinakoh Dec 17, 2020
477b789
Update comment
dylan-chong Dec 17, 2020
85fb8e7
Update code to include tests for description macro
justinakoh Dec 17, 2020
f8917a5
Update tests for input object
justinakoh Dec 17, 2020
4e0adf8
Add in more tests for field keyword attribute
justinakoh Dec 17, 2020
b3e0cbe
Add more tests for input object attribute description
justinakoh Dec 17, 2020
c192ec8
NEW LINE
justinakoh Dec 17, 2020
435246b
Update tests to include tests for macro description
justinakoh Dec 17, 2020
34f72ce
Add new test files for testing to test things
justinakoh Dec 17, 2020
aac0a7e
Add test for mutation test
justinakoh Dec 17, 2020
ccb6cf3
Fix module attributes don't work with multiple types files
dylan-chong Dec 17, 2020
dbcb7de
Add test for import types with module attribute
dylan-chong Dec 17, 2020
99ee813
Better import types test
dylan-chong Dec 21, 2020
46d5b66
Rename standard_library_function_works
dylan-chong Dec 21, 2020
aa538d8
Add external_module_function_call test
dylan-chong Dec 21, 2020
de73de0
Mix format
dylan-chong Dec 21, 2020
be8e3b8
Rename module_attribute_string_concat
dylan-chong Dec 21, 2020
ce742ef
Rename function_nested_in_module
dylan-chong Dec 21, 2020
7df5c50
Rename test
dylan-chong Dec 21, 2020
25b347e
Rename expected_value
dylan-chong Dec 21, 2020
ef90531
Rename function_call_using_absolute_path
dylan-chong Dec 21, 2020
1c8ac87
Move stuff into fixtures
dylan-chong Dec 21, 2020
043040d
Fixtures
dylan-chong Dec 21, 2020
bac3f1b
Object test
dylan-chong Dec 21, 2020
4baef8f
Shorten fixtures names
dylan-chong Dec 21, 2020
9780fa0
More object tests
dylan-chong Dec 21, 2020
e9403e8
Reduce dupe
dylan-chong Dec 21, 2020
c8feac5
Directive tests and fix
dylan-chong Dec 21, 2020
a235e43
Directive arg test
dylan-chong Dec 21, 2020
93c21a6
Scalar description
dylan-chong Dec 22, 2020
fba1663
Fix union types and add tests
dylan-chong Dec 22, 2020
3e7f316
Update comment
dylan-chong Dec 22, 2020
2e193de
Make test naming consistent
dylan-chong Dec 22, 2020
5ef5b90
Bad find and replace
dylan-chong Dec 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 65 additions & 14 deletions lib/absinthe/schema/notation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,12 @@ defmodule Absinthe.Schema.Notation do

__CALLER__
|> recordable!(:object, @placement[:object])
|> record!(Schema.ObjectTypeDefinition, identifier, attrs, block)
|> record!(
Schema.ObjectTypeDefinition,
identifier,
attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see function wrap_in_unquote for a description.

this Keyword.update(:description, nil, &wrap_in_unquote/1) is the fix pasted in all the places necessary. basically is the only change to notation.ex

block
)
end

@placement {:interfaces, [under: [:object]]}
Expand Down Expand Up @@ -407,6 +412,7 @@ defmodule Absinthe.Schema.Notation do
|> expand_ast(caller)
|> Keyword.delete(:args)
|> Keyword.delete(:meta)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
|> handle_deprecate

{attrs, block}
Expand Down Expand Up @@ -719,7 +725,7 @@ defmodule Absinthe.Schema.Notation do
defmacro scalar(identifier, attrs, do: block) do
__CALLER__
|> recordable!(:scalar, @placement[:scalar])
|> record!(Schema.ScalarTypeDefinition, identifier, attrs, block)
|> record_scalar!(identifier, attrs, block)
end

@doc """
Expand All @@ -730,13 +736,13 @@ defmodule Absinthe.Schema.Notation do
defmacro scalar(identifier, do: block) do
__CALLER__
|> recordable!(:scalar, @placement[:scalar])
|> record!(Schema.ScalarTypeDefinition, identifier, [], block)
|> record_scalar!(identifier, [], block)
end

defmacro scalar(identifier, attrs) do
__CALLER__
|> recordable!(:scalar, @placement[:scalar])
|> record!(Schema.ScalarTypeDefinition, identifier, attrs, nil)
|> record_scalar!(identifier, attrs, nil)
end

@placement {:serialize, [under: [:scalar]]}
Expand Down Expand Up @@ -934,7 +940,12 @@ defmodule Absinthe.Schema.Notation do
defmacro input_object(identifier, attrs \\ [], do: block) do
__CALLER__
|> recordable!(:input_object, @placement[:input_object])
|> record!(Schema.InputObjectTypeDefinition, identifier, attrs, block)
|> record!(
Schema.InputObjectTypeDefinition,
identifier,
attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1),
block
)
end

# UNIONS
Expand Down Expand Up @@ -965,7 +976,12 @@ defmodule Absinthe.Schema.Notation do
defmacro union(identifier, attrs \\ [], do: block) do
__CALLER__
|> recordable!(:union, @placement[:union])
|> record!(Schema.UnionTypeDefinition, identifier, attrs, block)
|> record!(
Schema.UnionTypeDefinition,
identifier,
attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1),
block
)
end

@placement {:types, [under: [:union]]}
Expand Down Expand Up @@ -1069,10 +1085,11 @@ defmodule Absinthe.Schema.Notation do
|> expand_ast(env)
|> Keyword.update(:values, [], fn values ->
Enum.map(values, fn ident ->
value_attrs = handle_enum_value_attrs(ident, module: env.module)
value_attrs = handle_enum_value_attrs(ident, [], env)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug fix: handle_enum_value_attrs needs an env struct to pass into expand_ast and this keyword list module: env.module to simulate the env doesn't work)

struct!(Schema.EnumValueDefinition, value_attrs)
end)
end)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
end

@placement {:value, [under: [:enum]]}
Expand Down Expand Up @@ -1296,6 +1313,7 @@ defmodule Absinthe.Schema.Notation do
raw_attrs
|> Keyword.put_new(:name, to_string(identifier))
|> Keyword.put_new(:type, type)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
|> handle_deprecate
end

Expand All @@ -1319,6 +1337,7 @@ defmodule Absinthe.Schema.Notation do
attrs
|> Keyword.put(:identifier, identifier)
|> Keyword.put_new(:name, to_string(identifier))
|> Keyword.update(:description, nil, &wrap_in_unquote/1)

scoped_def(env, Schema.DirectiveDefinition, identifier, attrs, block)
end
Expand Down Expand Up @@ -1401,16 +1420,27 @@ defmodule Absinthe.Schema.Notation do
scoped_def(env, :enum, identifier, attrs, block)
end

defp reformat_description(text), do: String.trim(text)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we lost the String.trim call on descriptions, I suspect this is something we'll want to get back, right @benwilson512?


@doc false
# Record a description in the current scope
def record_description!(env, text_block) do
text = reformat_description(text_block)
text = wrap_in_unquote(text_block)

put_attr(env.module, {:desc, text})
end

def handle_enum_value_attrs(identifier, raw_attrs) do
@doc false
# Record a scalar
def record_scalar!(env, identifier, attrs, block_or_nil) do
record!(
env,
Schema.ScalarTypeDefinition,
identifier,
attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1),
block_or_nil
)
end

def handle_enum_value_attrs(identifier, raw_attrs, env) do
value =
case Keyword.get(raw_attrs, :as, identifier) do
value when is_tuple(value) ->
Expand All @@ -1423,18 +1453,19 @@ defmodule Absinthe.Schema.Notation do
end

raw_attrs
|> expand_ast(raw_attrs)
|> expand_ast(env)
|> Keyword.put(:identifier, identifier)
|> Keyword.put(:value, value)
|> Keyword.put_new(:name, String.upcase(to_string(identifier)))
|> Keyword.delete(:as)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
|> handle_deprecate
end

@doc false
# Record an enum value in the current scope
def record_value!(env, identifier, raw_attrs) do
attrs = handle_enum_value_attrs(identifier, raw_attrs)
attrs = handle_enum_value_attrs(identifier, raw_attrs, env)
record!(env, Schema.EnumValueDefinition, identifier, attrs, [])
end

Expand All @@ -1445,7 +1476,7 @@ defmodule Absinthe.Schema.Notation do
values
|> expand_ast(env)
|> Enum.map(fn ident ->
value_attrs = handle_enum_value_attrs(ident, module: env.module)
value_attrs = handle_enum_value_attrs(ident, [], env)
struct!(Schema.EnumValueDefinition, value_attrs)
end)

Expand Down Expand Up @@ -1484,6 +1515,14 @@ defmodule Absinthe.Schema.Notation do
put_attr(env.module, {:middleware, [new_middleware]})
end

# We wrap the value (from the user) in an `unquote` call, so that when the schema `blueprint` is
# placed into `__absinthe_blueprint__` via `unquote(Macro.escape(blueprint, unquote: true))` the
# value get's unquoted. This allows us to evaluate function calls in the scope of the schema
# module.
defp wrap_in_unquote(value) do
{:unquote, [], [value]}
end

# ------------------------------

@doc false
Expand Down Expand Up @@ -1866,6 +1905,18 @@ defmodule Absinthe.Schema.Notation do

defp expand_ast(ast, env) do
Macro.prewalk(ast, fn
# We don't want to expand `@bla` into `Module.get_attribute(module, @bla)` because this
# function call will fail if the module is already compiled. Remember that the ast gets put
# into a generated `__absinthe_blueprint__` function which is called at "__after_compile__"
# time. This will be after a module has been compiled if there are multiple modules in the
# schema (in the case of an `import_types`).
#
# Also see test "test/absinthe/type/import_types_test.exs"
# "__absinthe_blueprint__ is callable at runtime even if there is a module attribute"
# and it's comment for more information
{:@, _, _} = node ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't quite worked out why this work, because I was sure this would fail with:

defmodule Foo do
  use Absinthe.Schema
  
  query do
  end
  @msg "It's a User"

  @desc @msg
  object :user do
  end

  @msg "It's a dog"

  @desc @msg
  object :dog do
  end
end

However based on my local testing:

iex(4)> Foo.__absinthe_type__(:user).description
"It's a User"
iex(5)> Foo.__absinthe_type__(:dog).description 
"It's a dog"

Works great!

Copy link
Contributor Author

@dylan-chong dylan-chong Dec 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value assigned to @desc module attribute is evaluated outside of Absinthe (@msg is evaluated when setting the @desc), so actually the example you showed there works without any magic (aside from elixir's built in magic itself)

node

{_, _, _} = node ->
Macro.expand(node, env)

Expand Down
43 changes: 43 additions & 0 deletions test/absinthe/execution/arguments/scalar_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
defmodule Absinthe.Execution.Arguments.ScalarTest do
use Absinthe.Case, async: true

alias Absinthe.Blueprint.Input
alias Absinthe.Fixtures.Scalar

@schema Absinthe.Fixtures.ArgumentsSchema

Expand Down Expand Up @@ -58,4 +60,45 @@ defmodule Absinthe.Execution.Arguments.ScalarTest do
)
end
end

describe "scalar keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Scalar.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end

describe "scalar description attribute evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Scalar.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label))

assert type.description == unquote(expected_value)
end
end)
end

describe "scalar description macro evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Scalar.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end
end
58 changes: 58 additions & 0 deletions test/absinthe/type/directive_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Absinthe.Type.DirectiveTest do
use Absinthe.Case, async: true

alias Absinthe.Schema
alias Absinthe.Fixtures.Directive

defmodule TestSchema do
use Absinthe.Schema
Expand Down Expand Up @@ -224,4 +225,61 @@ defmodule Absinthe.Type.DirectiveTest do
Absinthe.run(@query, Absinthe.Fixtures.ContactSchema)
end
end

describe "directive keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Directive.TestSchemaDescriptionKeyword.__absinthe_directive__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end

describe "directive description attribute evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type =
Directive.TestSchemaDescriptionAttribute.__absinthe_directive__(unquote(test_label))

assert type.description == unquote(expected_value)
end
end)
end

describe "directive description macro evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Directive.TestSchemaDescriptionMacro.__absinthe_directive__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end

describe "directive arg keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type =
Directive.TestSchemaArgDescriptionKeyword.__absinthe_directive__(unquote(test_label))

assert type.args[:arg_example].description == unquote(expected_value)
end
end)
end
end
56 changes: 56 additions & 0 deletions test/absinthe/type/enum_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Absinthe.Type.EnumTest do
use Absinthe.Case, async: true

alias Absinthe.Type
alias Absinthe.Fixtures.Enums

defmodule TestSchema do
use Absinthe.Schema
Expand Down Expand Up @@ -71,4 +72,59 @@ defmodule Absinthe.Type.EnumTest do
assert %Type.Enum.Value{name: "RED", value: :red, description: nil} = type.values[:red]
end
end

describe "enum value description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type =
Enums.TestSchemaValueDescriptionKeyword.__absinthe_type__(:description_keyword_argument)

assert type.values[unquote(test_label)].description == unquote(expected_value)
end
end)
end

describe "enum description keyword evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Enums.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end

describe "enum description attribute evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Enums.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end

describe "enum description macro evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Enums.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label))
assert type.description == unquote(expected_value)
end
end)
end
end
Loading