Skip to content

Commit 9f98ada

Browse files
committed
feat(Schema) instrumenters can modify fields
1 parent 7f13fd5 commit 9f98ada

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

lib/graphql/schema.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Schema
5656
:orphan_types, :resolve_type,
5757
:object_from_id, :id_from_object,
5858
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m }},
59+
instrument: -> (schema, type, instrumenter) { schema.instrumenters[type] << instrumenter },
5960
query_analyzer: ->(schema, analyzer) { schema.query_analyzers << analyzer },
6061
middleware: ->(schema, middleware) { schema.middleware << middleware },
6162
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block)}
@@ -65,7 +66,7 @@ class Schema
6566
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
6667
:max_depth, :max_complexity,
6768
:orphan_types, :directives,
68-
:query_analyzers, :middleware
69+
:query_analyzers, :middleware, :instrumenters
6970

7071
BUILT_IN_TYPES = Hash[[INT_TYPE, STRING_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, ID_TYPE].map{ |type| [type.name, type] }]
7172
DIRECTIVES = [GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
@@ -90,6 +91,7 @@ def initialize
9091
@resolve_type_proc = nil
9192
@object_from_id_proc = nil
9293
@id_from_object_proc = nil
94+
@instrumenters = Hash.new { |h, k| h[k] = [] }
9395
# Default to the built-in execution strategy:
9496
@query_execution_strategy = GraphQL::Query::SerialExecution
9597
@mutation_execution_strategy = GraphQL::Query::SerialExecution
@@ -110,10 +112,16 @@ def define(**kwargs, &block)
110112
super
111113
types
112114
@instrumented_field_map = InstrumentedFieldMap.new(self)
115+
field_instrumenters = @instrumenters[:field]
113116
types.each do |type_name, type|
114117
if type.kind.fields?
115118
type.all_fields.each do |field_defn|
116-
@instrumented_field_map.set(type.name, field_defn.name, field_defn)
119+
120+
instrumented_field_defn = field_instrumenters.reduce(field_defn) do |defn, inst|
121+
inst.instrument(type, defn)
122+
end
123+
124+
@instrumented_field_map.set(type.name, field_defn.name, instrumented_field_defn)
117125
end
118126
end
119127
end

spec/graphql/schema_spec.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,47 @@
182182
assert_equal GraphQL::Schema::Printer.print_schema(schema), GraphQL::Schema::Printer.print_schema(built_schema)
183183
end
184184
end
185+
186+
describe "#instrument" do
187+
class MultiplyInstrumenter
188+
def initialize(multiplier)
189+
@multiplier = multiplier
190+
end
191+
192+
def instrument(type_defn, field_defn)
193+
prev_proc = field_defn.resolve_proc
194+
new_resolve_proc = ->(obj, args, ctx) {
195+
inner_value = prev_proc.call(obj, args, ctx)
196+
inner_value * @multiplier
197+
}
198+
199+
field_defn.redefine do
200+
resolve(new_resolve_proc)
201+
end
202+
end
203+
end
204+
205+
let(:query_type) {
206+
GraphQL::ObjectType.define do
207+
name "Query"
208+
field :int, types.Int do
209+
argument :value, types.Int
210+
resolve -> (obj, args, ctx) { args[:value] }
211+
end
212+
end
213+
}
214+
215+
let(:schema) {
216+
spec = self
217+
GraphQL::Schema.define do
218+
query(spec.query_type)
219+
instrument(:field, MultiplyInstrumenter.new(3))
220+
end
221+
}
222+
223+
it "can modify field definitions" do
224+
res = schema.execute(" { int(value: 2) } ")
225+
assert_equal 6, res["data"]["int"]
226+
end
227+
end
185228
end

0 commit comments

Comments
 (0)