Skip to content

Commit a803b83

Browse files
author
Robert Mosolgo
authored
Merge pull request rmosolgo#1869 from goco-inc/prepare-input-objects
Prepare input objects
2 parents d4baab2 + 4f5fb49 commit a803b83

File tree

6 files changed

+88
-3
lines changed

6 files changed

+88
-3
lines changed

guides/type_definitions/input_objects.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,30 @@ You can also add or override methods on input object classes to customize them.
103103
- `@context`: The current {{ "GraphQL::Query::Context" | api_doc }}
104104

105105
Any extra methods you define on the class can be used for field resolution, as demonstrated above.
106+
107+
## Converting to Other Ruby Objects
108+
109+
Your input objects can be automatically converted to other Ruby types before they're passed to your application code. This is an easy way to use `Range`'s in your schema:
110+
111+
```ruby
112+
class Types::DateRangeInput < Types::BaseInputObject
113+
description "Range of dates"
114+
argument :min, Types::Date, "Minimum value of the range", required: true
115+
argument :max, Types::Date, "Maximum value of the range", required: true
116+
117+
def prepare
118+
min..max
119+
end
120+
end
121+
122+
class Types::CalendarType < Types::BaseObject
123+
field :appointments, [Types::Appointment], "Appointments on your calendar", null: false do
124+
argument :during, Types::DateRangeInput, "Only show appointments within this range", required: true
125+
end
126+
127+
def appointments(during:)
128+
# during will be an instance of Range
129+
object.appointments.select { |appointment| during.cover?(appointment.date) }
130+
end
131+
end
132+
```

lib/graphql/input_object_type.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ def coerce_non_null_input(value, ctx)
9999
end
100100
end
101101

102-
arguments_class.new(input_values, context: ctx, defaults_used: defaults_used)
102+
result = arguments_class.new(input_values, context: ctx, defaults_used: defaults_used)
103+
result.prepare
103104
end
104105

105106
# @api private

lib/graphql/query/arguments.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ def to_h
8787

8888
def_delegators :to_h, :keys, :values, :each, :any?
8989

90+
def prepare
91+
self
92+
end
93+
9094
# Access each key, value and type for the arguments in this set.
9195
# @yield [argument_value] The {ArgumentValue} for each argument
9296
# @yieldparam argument_value [ArgumentValue]
@@ -152,7 +156,8 @@ def wrap_value(value, arg_defn_type, context)
152156
wrap_value(value, arg_defn_type.of_type, context)
153157
when GraphQL::InputObjectType
154158
if value.is_a?(Hash)
155-
arg_defn_type.arguments_class.new(value, context: context, defaults_used: Set.new)
159+
result = arg_defn_type.arguments_class.new(value, context: context, defaults_used: Set.new)
160+
result.prepare
156161
else
157162
value
158163
end

lib/graphql/query/literal_input.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ def self.from_arguments(ast_arguments, argument_owner, variables)
108108
end
109109
end
110110

111-
argument_owner.arguments_class.new(values_hash, context: context, defaults_used: defaults_used)
111+
result = argument_owner.arguments_class.new(values_hash, context: context, defaults_used: defaults_used)
112+
result.prepare
112113
end
113114
end
114115
end

lib/graphql/schema/input_object.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def to_hash
5757
to_h
5858
end
5959

60+
def prepare
61+
self
62+
end
63+
6064
def unwrap_value(value)
6165
case value
6266
when Array

spec/graphql/schema/input_object_spec.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,53 @@ def self.resolve_type(type, obj, ctx)
168168
end
169169
end
170170

171+
describe "prepare (entire input object)" do
172+
module InputObjectPrepareObjectTest
173+
class InputObj < GraphQL::Schema::InputObject
174+
argument :min, Integer, required: true
175+
argument :max, Integer, required: false
176+
177+
def prepare
178+
min..max
179+
end
180+
end
181+
182+
class Query < GraphQL::Schema::Object
183+
field :inputs, String, null: false do
184+
argument :input, InputObj, required: true
185+
end
186+
187+
def inputs(input:)
188+
input.inspect
189+
end
190+
end
191+
192+
class Schema < GraphQL::Schema
193+
query(Query)
194+
end
195+
end
196+
197+
it "calls prepare on the input object (literal)" do
198+
query_str = <<-GRAPHQL
199+
{ inputs(input: { min: 5, max: 10 }) }
200+
GRAPHQL
201+
202+
res = InputObjectPrepareObjectTest::Schema.execute(query_str)
203+
expected_obj = (5..10).inspect
204+
assert_equal expected_obj, res["data"]["inputs"]
205+
end
206+
207+
it "calls prepare on the input object (variable)" do
208+
query_str = <<-GRAPHQL
209+
query ($input: InputObj!){ inputs(input: $input) }
210+
GRAPHQL
211+
212+
res = InputObjectPrepareObjectTest::Schema.execute(query_str, variables: { input: { min: 5, max: 10 } })
213+
expected_obj = (5..10).inspect
214+
assert_equal expected_obj, res["data"]["inputs"]
215+
end
216+
end
217+
171218
describe "loading application object(s)" do
172219
module InputObjectLoadsTest
173220
class SingleLoadInputObj < GraphQL::Schema::InputObject

0 commit comments

Comments
 (0)