Skip to content

Commit

Permalink
Merge pull request #1808 from phaedryx/patch-4
Browse files Browse the repository at this point in the history
Allow fields to pass additional parameters
  • Loading branch information
Robert Mosolgo authored Sep 13, 2018
2 parents e301ccc + d5a7bfd commit 191725e
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 9 deletions.
16 changes: 9 additions & 7 deletions guides/type_definitions/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,19 +294,21 @@ end

At runtime, the requested runtime object will be passed to the field.

### Field Parameter Default Values
__Custom extras__ are also possible. Any method on your field class can be passed to `extras: [...]`, and the value will be injected into the method. For example, `extras: [:owner]` will inject the object type who owns the field. Any new methods on your custom field class may be used, too.

The field method requires you to pass `null:` keyword argument to determine whether the field is nullable or not. Another field you may want to overrid is `camelize`, which is `true` by default. You can override this behavior by adding a custom field.
### Field Parameter Default Values

The field method requires you to pass `null:` keyword argument to determine whether the field is nullable or not. Another field you may want to overrid is `camelize`, which is `true` by default. You can override this behavior by adding a custom field.

```ruby
class CustomField < GraphQL::Schema::Field
# Add `null: false` and `camelize: false` which provide default values
# in case the caller doesn't pass anything for those arguments.
# **kwargs is a catch-all that will get everything else
# Add `null: false` and `camelize: false` which provide default values
# in case the caller doesn't pass anything for those arguments.
# **kwargs is a catch-all that will get everything else
def initialize(*args, null: false, camelize: false, **kwargs, &block)
# Then, call super _without_ any args, where Ruby will take
# Then, call super _without_ any args, where Ruby will take
# _all_ the args originally passed to this method and pass it to the super method.
super
super
end
end
```
Expand Down
14 changes: 12 additions & 2 deletions lib/graphql/schema/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,17 @@ def apply_scope(value, ctx)
end
end

# @param ctx [GraphQL::Query::Context::FieldResolutionContext]
def fetch_extra(extra_name, ctx)
if respond_to?(extra_name)
self.public_send(extra_name)
elsif ctx.respond_to?(extra_name)
ctx.public_send(extra_name)
else
raise NotImplementedError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
end
end

NO_ARGS = {}.freeze

def public_send_field(obj, graphql_args, field_ctx)
Expand All @@ -429,8 +440,7 @@ def public_send_field(obj, graphql_args, field_ctx)
end

@extras.each do |extra_arg|
# TODO: provide proper tests for `:ast_node`, `:irep_node`, `:parent`, others?
ruby_kwargs[extra_arg] = field_ctx.public_send(extra_arg)
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
end
else
ruby_kwargs = NO_ARGS
Expand Down
16 changes: 16 additions & 0 deletions spec/graphql/schema/field_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@
assert_equal ["find", "addError"], err["path"]
assert_equal [{"line"=>4, "column"=>15}], err["locations"]
end

it "can get methods from the field instance" do
query_str = <<-GRAPHQL
{
upcaseCheck1
upcaseCheck2
upcaseCheck3
upcaseCheck4
}
GRAPHQL
res = Jazz::Schema.execute(query_str)
assert_equal "nil", res["data"].fetch("upcaseCheck1")
assert_equal "false", res["data"]["upcaseCheck2"]
assert_equal "TRUE", res["data"]["upcaseCheck3"]
assert_equal "\"WHY NOT?\"", res["data"]["upcaseCheck4"]
end
end

it "is the #owner of its arguments" do
Expand Down
9 changes: 9 additions & 0 deletions spec/support/jazz.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def to_graphql
# A custom field class that supports the `upcase:` option
class BaseField < GraphQL::Schema::Field
argument_class BaseArgument
attr_reader :upcase
def initialize(*args, **options, &block)
@upcase = options.delete(:upcase)
super(*args, **options, &block)
Expand Down Expand Up @@ -350,6 +351,14 @@ class Query < BaseObject
argument :input, [RawJson], required: true
end

field :upcase_check_1, String, null: true, method: :upcase_check, extras: [:upcase]
field :upcase_check_2, String, null: false, upcase: false, method: :upcase_check, extras: [:upcase]
field :upcase_check_3, String, null: false, upcase: true, method: :upcase_check, extras: [:upcase]
field :upcase_check_4, String, null: false, upcase: "why not?", method: :upcase_check, extras: [:upcase]
def upcase_check(upcase:)
upcase.inspect
end

def ensembles
# Filter out the unauthorized one to avoid an error later
Models.data["Ensemble"].select { |e| e.name != "Spinal Tap" }
Expand Down

0 comments on commit 191725e

Please sign in to comment.