graphql 1.7.14 → 1.8.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/loader_generator.rb +1 -1
  4. data/lib/generators/graphql/mutation_generator.rb +1 -6
  5. data/lib/generators/graphql/templates/function.erb +2 -2
  6. data/lib/generators/graphql/templates/loader.erb +2 -2
  7. data/lib/graphql.rb +2 -0
  8. data/lib/graphql/argument.rb +0 -1
  9. data/lib/graphql/backwards_compatibility.rb +2 -3
  10. data/lib/graphql/base_type.rb +18 -16
  11. data/lib/graphql/compatibility/query_parser_specification.rb +0 -117
  12. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -14
  13. data/lib/graphql/define/assign_object_field.rb +5 -12
  14. data/lib/graphql/deprecated_dsl.rb +28 -0
  15. data/lib/graphql/directive.rb +0 -1
  16. data/lib/graphql/enum_type.rb +1 -3
  17. data/lib/graphql/execution.rb +0 -1
  18. data/lib/graphql/execution/multiplex.rb +29 -12
  19. data/lib/graphql/field.rb +5 -20
  20. data/lib/graphql/function.rb +12 -0
  21. data/lib/graphql/input_object_type.rb +1 -3
  22. data/lib/graphql/internal_representation/node.rb +14 -26
  23. data/lib/graphql/internal_representation/visit.rb +6 -3
  24. data/lib/graphql/introspection/arguments_field.rb +0 -1
  25. data/lib/graphql/introspection/enum_values_field.rb +0 -1
  26. data/lib/graphql/introspection/fields_field.rb +0 -1
  27. data/lib/graphql/introspection/input_fields_field.rb +0 -1
  28. data/lib/graphql/introspection/interfaces_field.rb +0 -1
  29. data/lib/graphql/introspection/of_type_field.rb +0 -1
  30. data/lib/graphql/introspection/possible_types_field.rb +0 -1
  31. data/lib/graphql/introspection/schema_field.rb +0 -1
  32. data/lib/graphql/introspection/type_by_name_field.rb +0 -1
  33. data/lib/graphql/introspection/typename_field.rb +0 -1
  34. data/lib/graphql/language.rb +0 -3
  35. data/lib/graphql/language/generation.rb +182 -3
  36. data/lib/graphql/language/lexer.rb +69 -144
  37. data/lib/graphql/language/lexer.rl +4 -15
  38. data/lib/graphql/language/nodes.rb +76 -136
  39. data/lib/graphql/language/parser.rb +621 -668
  40. data/lib/graphql/language/parser.y +11 -17
  41. data/lib/graphql/language/token.rb +3 -10
  42. data/lib/graphql/object_type.rb +6 -1
  43. data/lib/graphql/query.rb +13 -8
  44. data/lib/graphql/query/arguments.rb +33 -48
  45. data/lib/graphql/query/context.rb +1 -0
  46. data/lib/graphql/query/literal_input.rb +1 -4
  47. data/lib/graphql/relay/connection_resolve.rb +3 -0
  48. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  49. data/lib/graphql/relay/relation_connection.rb +19 -14
  50. data/lib/graphql/schema.rb +219 -12
  51. data/lib/graphql/schema/argument.rb +33 -0
  52. data/lib/graphql/schema/build_from_definition.rb +18 -64
  53. data/lib/graphql/schema/enum.rb +76 -0
  54. data/lib/graphql/schema/field.rb +127 -0
  55. data/lib/graphql/schema/field/dynamic_resolve.rb +63 -0
  56. data/lib/graphql/schema/field/unwrapped_resolve.rb +20 -0
  57. data/lib/graphql/schema/input_object.rb +61 -0
  58. data/lib/graphql/schema/interface.rb +32 -0
  59. data/lib/graphql/schema/loader.rb +2 -2
  60. data/lib/graphql/schema/member.rb +97 -0
  61. data/lib/graphql/schema/member/build_type.rb +106 -0
  62. data/lib/graphql/schema/member/has_fields.rb +56 -0
  63. data/lib/graphql/schema/member/instrumentation.rb +113 -0
  64. data/lib/graphql/schema/member/list_type_proxy.rb +21 -0
  65. data/lib/graphql/schema/member/non_null_type_proxy.rb +21 -0
  66. data/lib/graphql/schema/object.rb +65 -0
  67. data/lib/graphql/schema/printer.rb +266 -33
  68. data/lib/graphql/schema/scalar.rb +25 -0
  69. data/lib/graphql/schema/traversal.rb +26 -17
  70. data/lib/graphql/schema/union.rb +48 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -5
  72. data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -15
  73. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -11
  74. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -7
  75. data/lib/graphql/tracing.rb +0 -1
  76. data/lib/graphql/tracing/platform_tracing.rb +7 -20
  77. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  78. data/lib/graphql/unresolved_type_error.rb +2 -3
  79. data/lib/graphql/version.rb +1 -1
  80. data/readme.md +1 -1
  81. data/spec/dummy/app/channels/graphql_channel.rb +1 -22
  82. data/spec/dummy/log/development.log +0 -239
  83. data/spec/dummy/log/test.log +0 -204
  84. data/spec/dummy/test/system/action_cable_subscription_test.rb +0 -4
  85. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  86. data/spec/generators/graphql/function_generator_spec.rb +0 -26
  87. data/spec/generators/graphql/loader_generator_spec.rb +0 -24
  88. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  89. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  90. data/spec/graphql/backtrace_spec.rb +0 -10
  91. data/spec/graphql/base_type_spec.rb +5 -19
  92. data/spec/graphql/boolean_type_spec.rb +3 -3
  93. data/spec/graphql/directive_spec.rb +1 -3
  94. data/spec/graphql/enum_type_spec.rb +5 -18
  95. data/spec/graphql/execution/execute_spec.rb +1 -1
  96. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  97. data/spec/graphql/float_type_spec.rb +2 -2
  98. data/spec/graphql/id_type_spec.rb +1 -1
  99. data/spec/graphql/input_object_type_spec.rb +2 -15
  100. data/spec/graphql/int_type_spec.rb +2 -2
  101. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  102. data/spec/graphql/introspection/schema_type_spec.rb +0 -1
  103. data/spec/graphql/language/generation_spec.rb +186 -21
  104. data/spec/graphql/language/lexer_spec.rb +1 -21
  105. data/spec/graphql/language/nodes_spec.rb +12 -21
  106. data/spec/graphql/language/parser_spec.rb +1 -1
  107. data/spec/graphql/query/arguments_spec.rb +15 -37
  108. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  109. data/spec/graphql/query/variables_spec.rb +1 -1
  110. data/spec/graphql/query_spec.rb +5 -31
  111. data/spec/graphql/rake_task_spec.rb +1 -3
  112. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  113. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  114. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  115. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  116. data/spec/graphql/relay/mutation_spec.rb +3 -3
  117. data/spec/graphql/relay/relation_connection_spec.rb +1 -65
  118. data/spec/graphql/schema/build_from_definition_spec.rb +4 -86
  119. data/spec/graphql/schema/enum_spec.rb +60 -0
  120. data/spec/graphql/schema/field_spec.rb +14 -0
  121. data/spec/graphql/schema/input_object_spec.rb +43 -0
  122. data/spec/graphql/schema/interface_spec.rb +98 -0
  123. data/spec/graphql/schema/object_spec.rb +119 -0
  124. data/spec/graphql/schema/printer_spec.rb +15 -92
  125. data/spec/graphql/schema/scalar_spec.rb +40 -0
  126. data/spec/graphql/schema/union_spec.rb +35 -0
  127. data/spec/graphql/schema/validation_spec.rb +1 -1
  128. data/spec/graphql/schema/warden_spec.rb +11 -11
  129. data/spec/graphql/schema_spec.rb +25 -23
  130. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -10
  131. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  132. data/spec/graphql/string_type_spec.rb +3 -3
  133. data/spec/graphql/subscriptions_spec.rb +1 -1
  134. data/spec/graphql/tracing/platform_tracing_spec.rb +1 -60
  135. data/spec/support/dummy/schema.rb +25 -39
  136. data/spec/support/jazz.rb +334 -0
  137. data/spec/support/lazy_helpers.rb +21 -23
  138. data/spec/support/star_wars/data.rb +7 -6
  139. data/spec/support/star_wars/schema.rb +109 -142
  140. metadata +39 -33
  141. data/lib/graphql/execution/instrumentation.rb +0 -82
  142. data/lib/graphql/language/block_string.rb +0 -47
  143. data/lib/graphql/language/document_from_schema_definition.rb +0 -277
  144. data/lib/graphql/language/printer.rb +0 -351
  145. data/lib/graphql/tracing/data_dog_tracing.rb +0 -49
  146. data/spec/graphql/execution/instrumentation_spec.rb +0 -165
  147. data/spec/graphql/language/block_string_spec.rb +0 -70
  148. data/spec/graphql/language/document_from_schema_definition_spec.rb +0 -770
  149. data/spec/graphql/language/printer_spec.rb +0 -203
@@ -1,351 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Language
4
- class Printer
5
- # Turn an arbitrary AST node back into a string.
6
- #
7
- # @example Turning a document into a query string
8
- # document = GraphQL.parse(query_string)
9
- # GraphQL::Language::Printer.new.print(document)
10
- # # => "{ ... }"
11
- #
12
- #
13
- # @example Building a custom printer
14
- #
15
- # class MyPrinter < GraphQL::Language::Printer
16
- # def print_argument(arg)
17
- # "#{arg.name}: <HIDDEN>"
18
- # end
19
- # end
20
- #
21
- # MyPrinter.new.print(document)
22
- # # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
23
- #
24
- #
25
- # @param indent [String] Whitespace to add to the printed node
26
- # @return [String] Valid GraphQL for `node`
27
- def print(node, indent: "")
28
- print_node(node, indent: indent)
29
- end
30
-
31
- protected
32
-
33
- def print_document(document)
34
- document.definitions.map { |d| print_node(d) }.join("\n\n")
35
- end
36
-
37
- def print_argument(argument)
38
- "#{argument.name}: #{print_node(argument.value)}".dup
39
- end
40
-
41
- def print_directive(directive)
42
- out = "@#{directive.name}".dup
43
-
44
- if directive.arguments.any?
45
- out << "(#{directive.arguments.map { |a| print_argument(a) }.join(", ")})"
46
- end
47
-
48
- out
49
- end
50
-
51
- def print_enum(enum)
52
- "#{enum.name}".dup
53
- end
54
-
55
- def print_null_value
56
- "null".dup
57
- end
58
-
59
- def print_field(field, indent: "")
60
- out = "#{indent}".dup
61
- out << "#{field.alias}: " if field.alias
62
- out << "#{field.name}"
63
- out << "(#{field.arguments.map { |a| print_argument(a) }.join(", ")})" if field.arguments.any?
64
- out << print_directives(field.directives)
65
- out << print_selections(field.selections, indent: indent)
66
- out
67
- end
68
-
69
- def print_fragment_definition(fragment_def, indent: "")
70
- out = "#{indent}fragment #{fragment_def.name}".dup
71
- if fragment_def.type
72
- out << " on #{print_node(fragment_def.type)}"
73
- end
74
- out << print_directives(fragment_def.directives)
75
- out << print_selections(fragment_def.selections, indent: indent)
76
- out
77
- end
78
-
79
- def print_fragment_spread(fragment_spread, indent: "")
80
- out = "#{indent}...#{fragment_spread.name}".dup
81
- out << print_directives(fragment_spread.directives)
82
- out
83
- end
84
-
85
- def print_inline_fragment(inline_fragment, indent: "")
86
- out = "#{indent}...".dup
87
- if inline_fragment.type
88
- out << " on #{print_node(inline_fragment.type)}"
89
- end
90
- out << print_directives(inline_fragment.directives)
91
- out << print_selections(inline_fragment.selections, indent: indent)
92
- out
93
- end
94
-
95
- def print_input_object(input_object)
96
- "{#{input_object.arguments.map { |a| "#{a.name}: #{print(a.value)}" }.join(", ")}}"
97
- end
98
-
99
- def print_list_type(list_type)
100
- "[#{print_node(list_type.of_type)}]".dup
101
- end
102
-
103
- def print_non_null_type(non_null_type)
104
- "#{print_node(non_null_type.of_type)}!".dup
105
- end
106
-
107
- def print_operation_definition(operation_definition, indent: "")
108
- out = "#{indent}#{operation_definition.operation_type}".dup
109
- out << " #{operation_definition.name}" if operation_definition.name
110
-
111
- if operation_definition.variables.any?
112
- out << "(#{operation_definition.variables.map { |v| print_variable_definition(v) }.join(", ")})"
113
- end
114
-
115
- out << print_directives(operation_definition.directives)
116
- out << print_selections(operation_definition.selections, indent: indent)
117
- out
118
- end
119
-
120
- def print_type_name(type_name)
121
- "#{type_name.name}".dup
122
- end
123
-
124
- def print_variable_definition(variable_definition)
125
- out = "$#{variable_definition.name}: #{print_node(variable_definition.type)}".dup
126
- out << " = #{print_node(variable_definition.default_value)}" unless variable_definition.default_value.nil?
127
- out
128
- end
129
-
130
- def print_variable_identifier(variable_identifier)
131
- "$#{variable_identifier.name}".dup
132
- end
133
-
134
- def print_schema_definition(schema)
135
- if (schema.query.nil? || schema.query == 'Query') &&
136
- (schema.mutation.nil? || schema.mutation == 'Mutation') &&
137
- (schema.subscription.nil? || schema.subscription == 'Subscription')
138
- return
139
- end
140
-
141
- out = "schema {\n".dup
142
- out << " query: #{schema.query}\n" if schema.query
143
- out << " mutation: #{schema.mutation}\n" if schema.mutation
144
- out << " subscription: #{schema.subscription}\n" if schema.subscription
145
- out << "}"
146
- end
147
-
148
- def print_scalar_type_definition(scalar_type)
149
- out = print_description(scalar_type)
150
- out << "scalar #{scalar_type.name}"
151
- out << print_directives(scalar_type.directives)
152
- end
153
-
154
- def print_object_type_definition(object_type)
155
- out = print_description(object_type)
156
- out << "type #{object_type.name}"
157
- out << " implements " << object_type.interfaces.map(&:name).join(" & ") unless object_type.interfaces.empty?
158
- out << print_directives(object_type.directives)
159
- out << print_field_definitions(object_type.fields)
160
- end
161
-
162
- def print_input_value_definition(input_value)
163
- out = "#{input_value.name}: #{print_node(input_value.type)}".dup
164
- out << " = #{print_node(input_value.default_value)}" unless input_value.default_value.nil?
165
- out << print_directives(input_value.directives)
166
- end
167
-
168
- def print_arguments(arguments, indent: "")
169
- if arguments.all?{ |arg| !arg.description }
170
- return "(#{arguments.map{ |arg| print_input_value_definition(arg) }.join(", ")})"
171
- end
172
-
173
- out = "(\n".dup
174
- out << arguments.map.with_index{ |arg, i|
175
- "#{print_description(arg, indent: " " + indent, first_in_block: i == 0)} #{indent}"\
176
- "#{print_input_value_definition(arg)}"
177
- }.join("\n")
178
- out << "\n#{indent})"
179
- end
180
-
181
- def print_field_definition(field)
182
- out = field.name.dup
183
- unless field.arguments.empty?
184
- out << print_arguments(field.arguments, indent: " ")
185
- end
186
- out << ": #{print_node(field.type)}"
187
- out << print_directives(field.directives)
188
- end
189
-
190
- def print_interface_type_definition(interface_type)
191
- out = print_description(interface_type)
192
- out << "interface #{interface_type.name}"
193
- out << print_directives(interface_type.directives)
194
- out << print_field_definitions(interface_type.fields)
195
- end
196
-
197
- def print_union_type_definition(union_type)
198
- out = print_description(union_type)
199
- out << "union #{union_type.name}"
200
- out << print_directives(union_type.directives)
201
- out << " = " + union_type.types.map(&:name).join(" | ")
202
- end
203
-
204
- def print_enum_type_definition(enum_type)
205
- out = print_description(enum_type)
206
- out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
207
- enum_type.values.each.with_index do |value, i|
208
- out << print_description(value, indent: ' ', first_in_block: i == 0)
209
- out << print_enum_value_definition(value)
210
- end
211
- out << "}"
212
- end
213
-
214
- def print_enum_value_definition(enum_value)
215
- out = " #{enum_value.name}".dup
216
- out << print_directives(enum_value.directives)
217
- out << "\n"
218
- end
219
-
220
- def print_input_object_type_definition(input_object_type)
221
- out = print_description(input_object_type)
222
- out << "input #{input_object_type.name}"
223
- out << print_directives(input_object_type.directives)
224
- out << " {\n"
225
- input_object_type.fields.each.with_index do |field, i|
226
- out << print_description(field, indent: ' ', first_in_block: i == 0)
227
- out << " #{print_input_value_definition(field)}\n"
228
- end
229
- out << "}"
230
- end
231
-
232
- def print_directive_definition(directive)
233
- out = print_description(directive)
234
- out << "directive @#{directive.name}"
235
-
236
- if directive.arguments.any?
237
- out << print_arguments(directive.arguments)
238
- end
239
-
240
- out << " on #{directive.locations.join(' | ')}"
241
- end
242
-
243
- def print_description(node, indent: "", first_in_block: true)
244
- return ''.dup unless node.description
245
-
246
- description = indent != '' && !first_in_block ? "\n".dup : "".dup
247
- description << GraphQL::Language::Comments.commentize(node.description, indent: indent)
248
- end
249
-
250
- def print_field_definitions(fields)
251
- out = " {\n".dup
252
- fields.each.with_index do |field, i|
253
- out << print_description(field, indent: ' ', first_in_block: i == 0)
254
- out << " #{print_field_definition(field)}\n"
255
- end
256
- out << "}"
257
- end
258
-
259
- def print_directives(directives)
260
- if directives.any?
261
- directives.map { |d| " #{print_directive(d)}" }.join
262
- else
263
- ""
264
- end
265
- end
266
-
267
- def print_selections(selections, indent: "")
268
- if selections.any?
269
- out = " {\n".dup
270
- selections.each do |selection|
271
- out << print_node(selection, indent: indent + " ") << "\n"
272
- end
273
- out << "#{indent}}"
274
- else
275
- ""
276
- end
277
- end
278
-
279
- def print_node(node, indent: "")
280
- case node
281
- when Nodes::Document
282
- print_document(node)
283
- when Nodes::Argument
284
- print_argument(node)
285
- when Nodes::Directive
286
- print_directive(node)
287
- when Nodes::Enum
288
- print_enum(node)
289
- when Nodes::NullValue
290
- print_null_value
291
- when Nodes::Field
292
- print_field(node, indent: indent)
293
- when Nodes::FragmentDefinition
294
- print_fragment_definition(node, indent: indent)
295
- when Nodes::FragmentSpread
296
- print_fragment_spread(node, indent: indent)
297
- when Nodes::InlineFragment
298
- print_inline_fragment(node, indent: indent)
299
- when Nodes::InputObject
300
- print_input_object(node)
301
- when Nodes::ListType
302
- print_list_type(node)
303
- when Nodes::NonNullType
304
- print_non_null_type(node)
305
- when Nodes::OperationDefinition
306
- print_operation_definition(node, indent: indent)
307
- when Nodes::TypeName
308
- print_type_name(node)
309
- when Nodes::VariableDefinition
310
- print_variable_definition(node)
311
- when Nodes::VariableIdentifier
312
- print_variable_identifier(node)
313
- when Nodes::SchemaDefinition
314
- print_schema_definition(node)
315
- when Nodes::ScalarTypeDefinition
316
- print_scalar_type_definition(node)
317
- when Nodes::ObjectTypeDefinition
318
- print_object_type_definition(node)
319
- when Nodes::InputValueDefinition
320
- print_input_value_definition(node)
321
- when Nodes::FieldDefinition
322
- print_field_definition(node)
323
- when Nodes::InterfaceTypeDefinition
324
- print_interface_type_definition(node)
325
- when Nodes::UnionTypeDefinition
326
- print_union_type_definition(node)
327
- when Nodes::EnumTypeDefinition
328
- print_enum_type_definition(node)
329
- when Nodes::EnumValueDefinition
330
- print_enum_value_definition(node)
331
- when Nodes::InputObjectTypeDefinition
332
- print_input_object_type_definition(node)
333
- when Nodes::DirectiveDefinition
334
- print_directive_definition(node)
335
- when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
336
- GraphQL::Language.serialize(node)
337
- when Array
338
- "[#{node.map { |v| print_node(v) }.join(", ")}]".dup
339
- when Hash
340
- "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
341
- else
342
- GraphQL::Language.serialize(node.to_s)
343
- end
344
- end
345
-
346
- private
347
-
348
- attr_reader :node
349
- end
350
- end
351
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- module Tracing
5
- class DataDogTracing < PlatformTracing
6
- self.platform_keys = {
7
- 'lex' => 'lex.graphql',
8
- 'parse' => 'parse.graphql',
9
- 'validate' => 'validate.graphql',
10
- 'analyze_query' => 'analyze.graphql',
11
- 'analyze_multiplex' => 'analyze.graphql',
12
- 'execute_multiplex' => 'execute.graphql',
13
- 'execute_query' => 'execute.graphql',
14
- 'execute_query_lazy' => 'execute.graphql',
15
- }
16
-
17
- def platform_trace(platform_key, key, data)
18
- tracer.trace(platform_key, service: service_name) do |span|
19
- span.span_type = 'custom'
20
-
21
- if key == 'execute_multiplex'
22
- operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
23
- span.resource = operations unless operations.empty?
24
- end
25
-
26
- if key == 'execute_query'
27
- span.set_tag(:selected_operation_name, data[:query].selected_operation_name)
28
- span.set_tag(:selected_operation_type, data[:query].selected_operation.operation_type)
29
- span.set_tag(:query_string, data[:query].query_string)
30
- end
31
-
32
- yield
33
- end
34
- end
35
-
36
- def service_name
37
- options.fetch(:service, 'ruby-graphql')
38
- end
39
-
40
- def tracer
41
- options.fetch(:tracer, Datadog.tracer)
42
- end
43
-
44
- def platform_field_key(type, field)
45
- "#{type.name}.#{field.name}"
46
- end
47
- end
48
- end
49
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- describe GraphQL::Schema do
5
- describe "instrumentation teardown bug" do
6
- # This instrumenter records that it ran,
7
- # or raises an error if instructed to do so
8
- class InstrumenterError < StandardError
9
- attr_reader :key
10
- def initialize(key)
11
- @key = key
12
- super()
13
- end
14
- end
15
-
16
- class LogInstrumenter
17
- def before_query(unit_of_work)
18
- run_hook(unit_of_work, "begin")
19
- end
20
-
21
- def after_query(unit_of_work)
22
- run_hook(unit_of_work, "end")
23
- end
24
-
25
- alias :before_multiplex :before_query
26
- alias :after_multiplex :after_query
27
-
28
- private
29
-
30
- def run_hook(unit_of_work, event_name)
31
- unit_of_work.context[log_key(event_name)] = true
32
- if unit_of_work.context[raise_key(event_name)]
33
- raise InstrumenterError.new(log_key(event_name))
34
- end
35
- end
36
-
37
- def log_key(event_name)
38
- context_key("did_#{event_name}")
39
- end
40
-
41
- def raise_key(event_name)
42
- context_key("should_raise_#{event_name}")
43
- end
44
-
45
- def context_key(suffix)
46
- prefix = self.class.name.sub("Instrumenter", "").downcase
47
- :"#{prefix}_instrumenter_#{suffix}"
48
- end
49
- end
50
-
51
- class FirstInstrumenter < LogInstrumenter; end
52
- class SecondInstrumenter < LogInstrumenter; end
53
-
54
- let(:query_type) {
55
- GraphQL::ObjectType.define do
56
- name "Query"
57
- field :int, types.Int do
58
- argument :value, types.Int
59
- resolve ->(obj, args, ctx) { args.value }
60
- end
61
- end
62
- }
63
-
64
- let(:schema) {
65
- spec = self
66
- GraphQL::Schema.define do
67
- query(spec.query_type)
68
- instrument(:query, FirstInstrumenter.new)
69
- instrument(:query, SecondInstrumenter.new)
70
- end
71
- }
72
-
73
- describe "query instrumenters" do
74
- it "before_query of the 2nd instrumenter does not run but after_query does" do
75
- context = {second_instrumenter_should_raise_begin: true}
76
- assert_raises InstrumenterError do
77
- schema.execute(" { int(value: 2) } ", context: context)
78
- end
79
- assert context[:first_instrumenter_did_begin]
80
- assert context[:first_instrumenter_did_end]
81
- assert context[:second_instrumenter_did_begin]
82
- refute context[:second_instrumenter_did_end]
83
- end
84
-
85
- it "runs after_query even if a previous after_query raised an error" do
86
- context = {second_instrumenter_should_raise_end: true}
87
- err = assert_raises InstrumenterError do
88
- schema.execute(" { int(value: 2) } ", context: context)
89
- end
90
- # The error came from the second instrumenter:
91
- assert_equal :second_instrumenter_did_end, err.key
92
- # But the first instrumenter still got a chance to teardown
93
- assert context[:first_instrumenter_did_begin]
94
- assert context[:first_instrumenter_did_end]
95
- assert context[:second_instrumenter_did_begin]
96
- assert context[:second_instrumenter_did_end]
97
- end
98
- end
99
-
100
- describe "within a multiplex" do
101
- let(:multiplex_schema) {
102
- schema.redefine {
103
- instrument(:multiplex, FirstInstrumenter.new)
104
- instrument(:multiplex, SecondInstrumenter.new)
105
- }
106
- }
107
-
108
- it "only runs after_multiplex if before_multiplex finished" do
109
- multiplex_ctx = {second_instrumenter_should_raise_begin: true}
110
- query_1_ctx = {}
111
- query_2_ctx = {}
112
- assert_raises InstrumenterError do
113
- multiplex_schema.multiplex(
114
- [
115
- {query: "{int(value: 1)}", context: query_1_ctx},
116
- {query: "{int(value: 2)}", context: query_2_ctx},
117
- ],
118
- context: multiplex_ctx
119
- )
120
- end
121
-
122
- assert multiplex_ctx[:first_instrumenter_did_begin]
123
- assert multiplex_ctx[:first_instrumenter_did_end]
124
- assert multiplex_ctx[:second_instrumenter_did_begin]
125
- refute multiplex_ctx[:second_instrumenter_did_end]
126
- # No query instrumentation was run at all
127
- assert_equal 0, query_1_ctx.size
128
- assert_equal 0, query_2_ctx.size
129
- end
130
-
131
- it "does full and partial query runs" do
132
- multiplex_ctx = {}
133
- query_1_ctx = {}
134
- query_2_ctx = {second_instrumenter_should_raise_begin: true}
135
- assert_raises InstrumenterError do
136
- multiplex_schema.multiplex(
137
- [
138
- { query: " { int(value: 2) } ", context: query_1_ctx },
139
- { query: " { int(value: 2) } ", context: query_2_ctx },
140
- ],
141
- context: multiplex_ctx
142
- )
143
- end
144
-
145
- # multiplex got a full run
146
- assert multiplex_ctx[:first_instrumenter_did_begin]
147
- assert multiplex_ctx[:first_instrumenter_did_end]
148
- assert multiplex_ctx[:second_instrumenter_did_begin]
149
- assert multiplex_ctx[:second_instrumenter_did_end]
150
-
151
- # query 1 got a full run
152
- assert query_1_ctx[:first_instrumenter_did_begin]
153
- assert query_1_ctx[:first_instrumenter_did_end]
154
- assert query_1_ctx[:second_instrumenter_did_begin]
155
- assert query_1_ctx[:second_instrumenter_did_end]
156
-
157
- # query 2 got a partial run
158
- assert query_2_ctx[:first_instrumenter_did_begin]
159
- assert query_2_ctx[:first_instrumenter_did_end]
160
- assert query_2_ctx[:second_instrumenter_did_begin]
161
- refute query_2_ctx[:second_instrumenter_did_end]
162
- end
163
- end
164
- end
165
- end