graphql 2.0.13 → 2.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/relay.rb +18 -1
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_object.erb +2 -0
  17. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +8 -0
  26. data/lib/graphql/analysis/analyzer.rb +89 -0
  27. data/lib/graphql/analysis/field_usage.rb +82 -0
  28. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  29. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  30. data/lib/graphql/analysis/query_complexity.rb +183 -0
  31. data/lib/graphql/analysis/query_depth.rb +58 -0
  32. data/lib/graphql/analysis/visitor.rb +283 -0
  33. data/lib/graphql/analysis.rb +92 -1
  34. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  35. data/lib/graphql/backtrace/table.rb +2 -2
  36. data/lib/graphql/backtrace/trace.rb +93 -0
  37. data/lib/graphql/backtrace/tracer.rb +1 -1
  38. data/lib/graphql/backtrace.rb +2 -1
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/request.rb +5 -0
  43. data/lib/graphql/dataloader/source.rb +89 -45
  44. data/lib/graphql/dataloader.rb +115 -142
  45. data/lib/graphql/duration_encoding_error.rb +16 -0
  46. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  47. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  48. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
  49. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  50. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +331 -455
  52. data/lib/graphql/execution/interpreter.rb +125 -61
  53. data/lib/graphql/execution/lazy.rb +6 -12
  54. data/lib/graphql/execution/lookahead.rb +124 -46
  55. data/lib/graphql/execution/multiplex.rb +3 -117
  56. data/lib/graphql/execution.rb +0 -1
  57. data/lib/graphql/introspection/directive_type.rb +3 -3
  58. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  59. data/lib/graphql/introspection/entry_points.rb +11 -5
  60. data/lib/graphql/introspection/field_type.rb +2 -2
  61. data/lib/graphql/introspection/schema_type.rb +10 -13
  62. data/lib/graphql/introspection/type_type.rb +17 -10
  63. data/lib/graphql/introspection.rb +3 -2
  64. data/lib/graphql/language/block_string.rb +34 -18
  65. data/lib/graphql/language/definition_slice.rb +1 -1
  66. data/lib/graphql/language/document_from_schema_definition.rb +75 -59
  67. data/lib/graphql/language/lexer.rb +358 -1506
  68. data/lib/graphql/language/nodes.rb +166 -93
  69. data/lib/graphql/language/parser.rb +795 -1953
  70. data/lib/graphql/language/printer.rb +340 -160
  71. data/lib/graphql/language/sanitized_printer.rb +21 -23
  72. data/lib/graphql/language/static_visitor.rb +167 -0
  73. data/lib/graphql/language/visitor.rb +188 -141
  74. data/lib/graphql/language.rb +61 -1
  75. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  76. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  77. data/lib/graphql/pagination/array_connection.rb +6 -6
  78. data/lib/graphql/pagination/connection.rb +33 -6
  79. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  80. data/lib/graphql/query/context/scoped_context.rb +101 -0
  81. data/lib/graphql/query/context.rb +117 -112
  82. data/lib/graphql/query/null_context.rb +12 -25
  83. data/lib/graphql/query/validation_pipeline.rb +6 -5
  84. data/lib/graphql/query/variables.rb +3 -3
  85. data/lib/graphql/query.rb +86 -30
  86. data/lib/graphql/railtie.rb +9 -6
  87. data/lib/graphql/rake_task.rb +29 -11
  88. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  89. data/lib/graphql/schema/addition.rb +59 -23
  90. data/lib/graphql/schema/always_visible.rb +11 -0
  91. data/lib/graphql/schema/argument.rb +55 -26
  92. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  93. data/lib/graphql/schema/build_from_definition.rb +56 -32
  94. data/lib/graphql/schema/directive/one_of.rb +24 -0
  95. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  96. data/lib/graphql/schema/directive/transform.rb +1 -1
  97. data/lib/graphql/schema/directive.rb +15 -3
  98. data/lib/graphql/schema/enum.rb +35 -24
  99. data/lib/graphql/schema/enum_value.rb +2 -3
  100. data/lib/graphql/schema/field/connection_extension.rb +2 -16
  101. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  102. data/lib/graphql/schema/field.rb +147 -107
  103. data/lib/graphql/schema/field_extension.rb +1 -4
  104. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  105. data/lib/graphql/schema/has_single_input_argument.rb +158 -0
  106. data/lib/graphql/schema/input_object.rb +47 -11
  107. data/lib/graphql/schema/interface.rb +15 -21
  108. data/lib/graphql/schema/introspection_system.rb +7 -17
  109. data/lib/graphql/schema/late_bound_type.rb +10 -0
  110. data/lib/graphql/schema/list.rb +2 -2
  111. data/lib/graphql/schema/loader.rb +2 -3
  112. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
  113. data/lib/graphql/schema/member/build_type.rb +11 -3
  114. data/lib/graphql/schema/member/has_arguments.rb +170 -130
  115. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  116. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  117. data/lib/graphql/schema/member/has_directives.rb +81 -61
  118. data/lib/graphql/schema/member/has_fields.rb +100 -38
  119. data/lib/graphql/schema/member/has_interfaces.rb +65 -10
  120. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  121. data/lib/graphql/schema/member/has_validators.rb +32 -6
  122. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  123. data/lib/graphql/schema/member/scoped.rb +19 -0
  124. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  125. data/lib/graphql/schema/member/validates_input.rb +3 -3
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +16 -5
  128. data/lib/graphql/schema/printer.rb +11 -8
  129. data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
  130. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  131. data/lib/graphql/schema/resolver.rb +47 -32
  132. data/lib/graphql/schema/scalar.rb +3 -3
  133. data/lib/graphql/schema/subscription.rb +11 -4
  134. data/lib/graphql/schema/subset.rb +397 -0
  135. data/lib/graphql/schema/timeout.rb +25 -29
  136. data/lib/graphql/schema/type_expression.rb +2 -2
  137. data/lib/graphql/schema/type_membership.rb +3 -0
  138. data/lib/graphql/schema/union.rb +11 -2
  139. data/lib/graphql/schema/unique_within_type.rb +1 -1
  140. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  141. data/lib/graphql/schema/validator.rb +4 -2
  142. data/lib/graphql/schema/warden.rb +238 -93
  143. data/lib/graphql/schema.rb +498 -103
  144. data/lib/graphql/static_validation/all_rules.rb +2 -1
  145. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  146. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  147. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  148. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  149. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  150. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  151. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  152. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  153. data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
  154. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  155. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  156. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  158. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  159. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  160. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  161. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  163. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  164. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  165. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  166. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  167. data/lib/graphql/static_validation/validation_context.rb +5 -5
  168. data/lib/graphql/static_validation/validator.rb +4 -1
  169. data/lib/graphql/static_validation.rb +0 -1
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
  171. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  172. data/lib/graphql/subscriptions/event.rb +11 -10
  173. data/lib/graphql/subscriptions/serialize.rb +2 -0
  174. data/lib/graphql/subscriptions.rb +20 -13
  175. data/lib/graphql/testing/helpers.rb +151 -0
  176. data/lib/graphql/testing.rb +2 -0
  177. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  178. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  179. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  180. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  181. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  182. data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
  183. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  184. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  185. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  186. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  187. data/lib/graphql/tracing/platform_trace.rb +118 -0
  188. data/lib/graphql/tracing/platform_tracing.rb +17 -3
  189. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  190. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  191. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  192. data/lib/graphql/tracing/scout_trace.rb +72 -0
  193. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  194. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  195. data/lib/graphql/tracing/trace.rb +76 -0
  196. data/lib/graphql/tracing.rb +20 -40
  197. data/lib/graphql/type_kinds.rb +7 -4
  198. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  199. data/lib/graphql/types/relay/base_connection.rb +1 -1
  200. data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
  201. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  202. data/lib/graphql/types/relay/node_behaviors.rb +8 -2
  203. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  204. data/lib/graphql/types/relay.rb +0 -1
  205. data/lib/graphql/types/string.rb +1 -1
  206. data/lib/graphql/types.rb +1 -0
  207. data/lib/graphql/version.rb +1 -1
  208. data/lib/graphql.rb +27 -20
  209. data/readme.md +13 -3
  210. metadata +96 -47
  211. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  212. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  213. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  214. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  215. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  216. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  217. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  218. data/lib/graphql/analysis/ast.rb +0 -81
  219. data/lib/graphql/deprecation.rb +0 -9
  220. data/lib/graphql/filter.rb +0 -53
  221. data/lib/graphql/language/lexer.rl +0 -280
  222. data/lib/graphql/language/parser.y +0 -554
  223. data/lib/graphql/language/token.rb +0 -34
  224. data/lib/graphql/schema/base_64_bp.rb +0 -26
  225. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  226. data/lib/graphql/static_validation/type_stack.rb +0 -216
  227. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
  228. data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -26,7 +26,7 @@ module GraphQL
26
26
  # rename some inputs to avoid conflicts inside the block
27
27
  maybe_lazy = value
28
28
  value = nil
29
- context.schema.after_lazy(maybe_lazy) do |resolved_value|
29
+ context.query.after_lazy(maybe_lazy) do |resolved_value|
30
30
  value = resolved_value
31
31
  if value.is_a? GraphQL::ExecutionError
32
32
  # This isn't even going to work because context doesn't have ast_node anymore
@@ -54,23 +54,9 @@ module GraphQL
54
54
  value.edge_class = custom_t
55
55
  end
56
56
  value
57
- elsif context.schema.new_connections?
57
+ else
58
58
  context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
59
59
  context.schema.connections.wrap(field, object.object, value, original_arguments, context)
60
- else
61
- if object.is_a?(GraphQL::Schema::Object)
62
- object = object.object
63
- end
64
- connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
65
- connection_class.new(
66
- value,
67
- original_arguments,
68
- field: field,
69
- max_page_size: field.max_page_size,
70
- default_page_size: field.default_page_size,
71
- parent: object,
72
- context: context,
73
- )
74
60
  end
75
61
  end
76
62
  end
@@ -10,7 +10,14 @@ module GraphQL
10
10
  else
11
11
  ret_type = @field.type.unwrap
12
12
  if ret_type.respond_to?(:scope_items)
13
- ret_type.scope_items(value, context)
13
+ scoped_items = ret_type.scope_items(value, context)
14
+ if !scoped_items.equal?(value) && !ret_type.reauthorize_scoped_objects
15
+ if (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
16
+ (query_runtime_state = current_runtime_state[context.query])
17
+ query_runtime_state.was_authorized_by_scope_items = true
18
+ end
19
+ end
20
+ scoped_items
14
21
  else
15
22
  value
16
23
  end
@@ -6,11 +6,12 @@ module GraphQL
6
6
  class Schema
7
7
  class Field
8
8
  include GraphQL::Schema::Member::HasArguments
9
+ include GraphQL::Schema::Member::HasArguments::FieldConfigured
9
10
  include GraphQL::Schema::Member::HasAstNode
10
11
  include GraphQL::Schema::Member::HasPath
11
12
  include GraphQL::Schema::Member::HasValidators
12
13
  extend GraphQL::Schema::FindInheritedValue
13
- include GraphQL::Schema::FindInheritedValue::EmptyObjects
14
+ include GraphQL::EmptyObjects
14
15
  include GraphQL::Schema::Member::HasDirectives
15
16
  include GraphQL::Schema::Member::HasDeprecationReason
16
17
 
@@ -40,6 +41,18 @@ module GraphQL
40
41
  end
41
42
  end
42
43
 
44
+ def directives
45
+ if @resolver_class && (r_dirs = @resolver_class.directives).any?
46
+ if (own_dirs = super).any?
47
+ own_dirs + r_dirs
48
+ else
49
+ r_dirs
50
+ end
51
+ else
52
+ super
53
+ end
54
+ end
55
+
43
56
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
44
57
  attr_accessor :owner
45
58
 
@@ -91,7 +104,7 @@ module GraphQL
91
104
  # @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
92
105
  # @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
93
106
  # @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
94
- # @return [GraphQL::Schema:Field] an instance of `self
107
+ # @return [GraphQL::Schema:Field] an instance of `self`
95
108
  # @see {.initialize} for other options
96
109
  def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
97
110
  if (resolver_class = resolver || mutation || subscription)
@@ -129,15 +142,15 @@ module GraphQL
129
142
  def connection?
130
143
  if @connection.nil?
131
144
  # Provide default based on type name
132
- return_type_name = if @resolver_class && @resolver_class.type
133
- Member::BuildType.to_type_name(@resolver_class.type)
134
- elsif @return_type_expr
145
+ return_type_name = if @return_type_expr
135
146
  Member::BuildType.to_type_name(@return_type_expr)
147
+ elsif @resolver_class && @resolver_class.type
148
+ Member::BuildType.to_type_name(@resolver_class.type)
136
149
  else
137
150
  # As a last ditch, try to force loading the return type:
138
151
  type.unwrap.name
139
152
  end
140
- @connection = return_type_name.end_with?("Connection")
153
+ @connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
141
154
  else
142
155
  @connection
143
156
  end
@@ -217,8 +230,8 @@ module GraphQL
217
230
  # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
218
231
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
219
232
  # @param validates [Array<Hash>] Configurations for validating this field
220
- # @fallback_value [Object] A fallback value if the method is not defined
221
- def initialize(type: nil, name: nil, owner: nil, null: nil, description: :not_given, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: :not_given, default_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
233
+ # @param fallback_value [Object] A fallback value if the method is not defined
234
+ def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
222
235
  if name.nil?
223
236
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
224
237
  end
@@ -229,11 +242,13 @@ module GraphQL
229
242
  end
230
243
  @original_name = name
231
244
  name_s = -name.to_s
245
+
232
246
  @underscored_name = -Member::BuildType.underscore(name_s)
233
247
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
234
- if description != :not_given
235
- @description = description
236
- end
248
+
249
+ @description = description
250
+ @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
251
+
237
252
  self.deprecation_reason = deprecation_reason
238
253
 
239
254
  if method && hash_key && dig
@@ -255,12 +270,16 @@ module GraphQL
255
270
  if hash_key
256
271
  @hash_key = hash_key
257
272
  @hash_key_str = hash_key.to_s
273
+ else
274
+ @hash_key = NOT_CONFIGURED
275
+ @hash_key_str = NOT_CONFIGURED
258
276
  end
259
277
 
260
278
  @method_str = -method_name.to_s
261
279
  @method_sym = method_name.to_sym
262
280
  @resolver_method = (resolver_method || name_s).to_sym
263
281
  @complexity = complexity
282
+ @dynamic_introspection = dynamic_introspection
264
283
  @return_type_expr = type
265
284
  @return_type_null = if !null.nil?
266
285
  null
@@ -270,15 +289,11 @@ module GraphQL
270
289
  true
271
290
  end
272
291
  @connection = connection
273
- @has_max_page_size = max_page_size != :not_given
274
- @max_page_size = max_page_size == :not_given ? nil : max_page_size
275
- @has_default_page_size = default_page_size != :not_given
276
- @default_page_size = default_page_size == :not_given ? nil : default_page_size
292
+ @max_page_size = max_page_size
293
+ @default_page_size = default_page_size
277
294
  @introspection = introspection
278
295
  @extras = extras
279
- if !broadcastable.nil?
280
- @broadcastable = broadcastable
281
- end
296
+ @broadcastable = broadcastable
282
297
  @resolver_class = resolver_class
283
298
  @scope = scope
284
299
  @trace = trace
@@ -337,7 +352,7 @@ module GraphQL
337
352
  self.validates(validates)
338
353
  end
339
354
 
340
- if definition_block
355
+ if block_given?
341
356
  if definition_block.arity == 1
342
357
  yield self
343
358
  else
@@ -349,11 +364,13 @@ module GraphQL
349
364
  @call_after_define = true
350
365
  end
351
366
 
367
+ attr_accessor :dynamic_introspection
368
+
352
369
  # If true, subscription updates with this field can be shared between viewers
353
370
  # @return [Boolean, nil]
354
371
  # @see GraphQL::Subscriptions::BroadcastAnalyzer
355
372
  def broadcastable?
356
- if defined?(@broadcastable)
373
+ if !NOT_CONFIGURED.equal?(@broadcastable)
357
374
  @broadcastable
358
375
  elsif @resolver_class
359
376
  @resolver_class.broadcastable?
@@ -367,10 +384,10 @@ module GraphQL
367
384
  def description(text = nil)
368
385
  if text
369
386
  @description = text
370
- elsif defined?(@description)
387
+ elsif !NOT_CONFIGURED.equal?(@description)
371
388
  @description
372
389
  elsif @resolver_class
373
- @description || @resolver_class.description
390
+ @resolver_class.description
374
391
  else
375
392
  nil
376
393
  end
@@ -466,6 +483,8 @@ module GraphQL
466
483
  if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
467
484
  max_possible_page_size = arguments[:last]
468
485
  end
486
+ elsif arguments.is_a?(GraphQL::UnauthorizedError)
487
+ raise arguments
469
488
  end
470
489
 
471
490
  if max_possible_page_size.nil?
@@ -478,41 +497,24 @@ module GraphQL
478
497
  metadata_complexity = 0
479
498
  lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
480
499
 
481
- if (page_info_lookahead = lookahead.selection(:page_info)).selected?
482
- metadata_complexity += 1 # pageInfo
483
- metadata_complexity += page_info_lookahead.selections.size # subfields
484
- end
485
-
486
- if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
487
- metadata_complexity += 1
500
+ lookahead.selections.each do |next_lookahead|
501
+ # this includes `pageInfo`, `nodes` and `edges` and any custom fields
502
+ # TODO this doesn't support procs yet -- unlikely to need it.
503
+ metadata_complexity += next_lookahead.field.complexity
504
+ if next_lookahead.name != :nodes && next_lookahead.name != :edges
505
+ # subfields, eg, for pageInfo -- assumes no subselections
506
+ metadata_complexity += next_lookahead.selections.size
507
+ end
488
508
  end
489
509
 
490
- nodes_edges_complexity = 0
491
- nodes_edges_complexity += 1 if lookahead.selects?(:edges)
492
- nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
493
-
494
510
  # Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
495
- items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
496
- # Add 1 for _this_ field
497
- 1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
511
+ items_complexity = child_complexity - metadata_complexity
512
+ subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
513
+ # Apply this field's own complexity
514
+ apply_own_complexity_to(subfields_complexity, query, nodes)
498
515
  end
499
516
  else
500
- defined_complexity = complexity
501
- case defined_complexity
502
- when Proc
503
- arguments = query.arguments_for(nodes.first, self)
504
- if arguments.is_a?(GraphQL::ExecutionError)
505
- return child_complexity
506
- elsif arguments.respond_to?(:keyword_arguments)
507
- arguments = arguments.keyword_arguments
508
- end
509
-
510
- defined_complexity.call(query.context, arguments, child_complexity)
511
- when Numeric
512
- defined_complexity + child_complexity
513
- else
514
- raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
515
- end
517
+ apply_own_complexity_to(child_complexity, query, nodes)
516
518
  end
517
519
  end
518
520
 
@@ -542,22 +544,34 @@ module GraphQL
542
544
 
543
545
  # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
544
546
  def has_max_page_size?
545
- @has_max_page_size || (@resolver_class && @resolver_class.has_max_page_size?)
547
+ !NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
546
548
  end
547
549
 
548
550
  # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
549
551
  def max_page_size
550
- @max_page_size || (@resolver_class && @resolver_class.max_page_size)
552
+ if !NOT_CONFIGURED.equal?(@max_page_size)
553
+ @max_page_size
554
+ elsif @resolver_class && @resolver_class.has_max_page_size?
555
+ @resolver_class.max_page_size
556
+ else
557
+ nil
558
+ end
551
559
  end
552
560
 
553
561
  # @return [Boolean] True if this field's {#default_page_size} should override the schema default.
554
562
  def has_default_page_size?
555
- @has_default_page_size || (@resolver_class && @resolver_class.has_default_page_size?)
563
+ !NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
556
564
  end
557
565
 
558
566
  # @return [Integer, nil] Applied to connections if {#has_default_page_size?}
559
567
  def default_page_size
560
- @default_page_size || (@resolver_class && @resolver_class.default_page_size)
568
+ if !NOT_CONFIGURED.equal?(@default_page_size)
569
+ @default_page_size
570
+ elsif @resolver_class && @resolver_class.has_default_page_size?
571
+ @resolver_class.default_page_size
572
+ else
573
+ nil
574
+ end
561
575
  end
562
576
 
563
577
  class MissingReturnTypeError < GraphQL::Error; end
@@ -589,48 +603,43 @@ module GraphQL
589
603
  end
590
604
  end
591
605
 
592
- def accessible?(context)
593
- if @resolver_class
594
- @resolver_class.accessible?(context)
595
- else
596
- true
597
- end
598
- end
599
-
600
606
  def authorized?(object, args, context)
601
607
  if @resolver_class
602
608
  # The resolver _instance_ will check itself during `resolve()`
603
609
  @resolver_class.authorized?(object, context)
604
610
  else
605
- if (arg_values = context[:current_arguments])
606
- # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
607
- using_arg_values = true
608
- arg_values = arg_values.argument_values
609
- else
610
- arg_values = args
611
- using_arg_values = false
612
- end
613
- # Faster than `.any?`
614
- arguments(context).each_value do |arg|
615
- arg_key = arg.keyword
616
- if arg_values.key?(arg_key)
617
- arg_value = arg_values[arg_key]
618
- if using_arg_values
619
- if arg_value.default_used?
620
- # pass -- no auth required for default used
621
- next
622
- else
623
- application_arg_value = arg_value.value
624
- if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
625
- application_arg_value.keyword_arguments
611
+ if args.size > 0
612
+ if (arg_values = context[:current_arguments])
613
+ # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
614
+ using_arg_values = true
615
+ arg_values = arg_values.argument_values
616
+ else
617
+ arg_values = args
618
+ using_arg_values = false
619
+ end
620
+
621
+ args = context.types.arguments(self)
622
+ args.each do |arg|
623
+ arg_key = arg.keyword
624
+ if arg_values.key?(arg_key)
625
+ arg_value = arg_values[arg_key]
626
+ if using_arg_values
627
+ if arg_value.default_used?
628
+ # pass -- no auth required for default used
629
+ next
630
+ else
631
+ application_arg_value = arg_value.value
632
+ if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
633
+ application_arg_value.keyword_arguments
634
+ end
626
635
  end
636
+ else
637
+ application_arg_value = arg_value
627
638
  end
628
- else
629
- application_arg_value = arg_value
630
- end
631
639
 
632
- if !arg.authorized?(object, application_arg_value, context)
633
- return false
640
+ if !arg.authorized?(object, application_arg_value, context)
641
+ return false
642
+ end
634
643
  end
635
644
  end
636
645
  end
@@ -650,9 +659,9 @@ module GraphQL
650
659
  method_to_call = nil
651
660
  method_args = nil
652
661
 
653
- Schema::Validator.validate!(validators, application_object, query_ctx, args)
662
+ @own_validators && Schema::Validator.validate!(validators, application_object, query_ctx, args)
654
663
 
655
- query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
664
+ query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
656
665
  if is_authorized
657
666
  with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
658
667
  method_args = ruby_kwargs
@@ -665,7 +674,7 @@ module GraphQL
665
674
 
666
675
  inner_object = obj.object
667
676
 
668
- if defined?(@hash_key)
677
+ if !NOT_CONFIGURED.equal?(@hash_key)
669
678
  hash_value = if inner_object.is_a?(Hash)
670
679
  inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
671
680
  elsif inner_object.respond_to?(:[])
@@ -676,7 +685,7 @@ module GraphQL
676
685
  if hash_value == false
677
686
  hash_value
678
687
  else
679
- hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
688
+ hash_value || (@fallback_value != NOT_CONFIGURED ? @fallback_value : nil)
680
689
  end
681
690
  elsif obj.respond_to?(resolver_method)
682
691
  method_to_call = resolver_method
@@ -692,9 +701,9 @@ module GraphQL
692
701
  inner_object.dig(*@dig_keys)
693
702
  elsif inner_object.key?(@method_sym)
694
703
  inner_object[@method_sym]
695
- elsif inner_object.key?(@method_str)
704
+ elsif inner_object.key?(@method_str) || !inner_object.default_proc.nil?
696
705
  inner_object[@method_str]
697
- elsif @fallback_value != :not_given
706
+ elsif @fallback_value != NOT_CONFIGURED
698
707
  @fallback_value
699
708
  else
700
709
  nil
@@ -707,7 +716,7 @@ module GraphQL
707
716
  else
708
717
  inner_object.public_send(@method_sym)
709
718
  end
710
- elsif @fallback_value != :not_given
719
+ elsif @fallback_value != NOT_CONFIGURED
711
720
  @fallback_value
712
721
  else
713
722
  raise <<-ERR
@@ -744,6 +753,8 @@ module GraphQL
744
753
  end
745
754
  # if the line above doesn't raise, re-raise
746
755
  raise
756
+ rescue GraphQL::ExecutionError => err
757
+ err
747
758
  end
748
759
 
749
760
  # @param ctx [GraphQL::Query::Context]
@@ -799,6 +810,17 @@ ERR
799
810
  end
800
811
  end
801
812
 
813
+ class ExtendedState
814
+ def initialize(args, object)
815
+ @arguments = args
816
+ @object = object
817
+ @memos = nil
818
+ @added_extras = nil
819
+ end
820
+
821
+ attr_accessor :arguments, :object, :memos, :added_extras
822
+ end
823
+
802
824
  # Wrap execution with hooks.
803
825
  # Written iteratively to avoid big stack traces.
804
826
  # @return [Object] Whatever the
@@ -809,20 +831,20 @@ ERR
809
831
  # This is a hack to get the _last_ value for extended obj and args,
810
832
  # in case one of the extensions doesn't `yield`.
811
833
  # (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
812
- extended = { args: args, obj: obj, memos: nil, added_extras: nil }
834
+ extended = ExtendedState.new(args, obj)
813
835
  value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
814
- if (added_extras = extended[:added_extras])
836
+ if (added_extras = extended.added_extras)
815
837
  args = args.dup
816
838
  added_extras.each { |e| args.delete(e) }
817
839
  end
818
840
  yield(obj, args)
819
841
  end
820
842
 
821
- extended_obj = extended[:obj]
822
- extended_args = extended[:args]
823
- memos = extended[:memos] || EMPTY_HASH
843
+ extended_obj = extended.object
844
+ extended_args = extended.arguments # rubocop:disable Development/ContextIsPassedCop
845
+ memos = extended.memos || EMPTY_HASH
824
846
 
825
- ctx.schema.after_lazy(value) do |resolved_value|
847
+ ctx.query.after_lazy(value) do |resolved_value|
826
848
  idx = 0
827
849
  @extensions.each do |ext|
828
850
  memo = memos[idx]
@@ -840,23 +862,41 @@ ERR
840
862
  if extension
841
863
  extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
842
864
  if memo
843
- memos = extended[:memos] ||= {}
865
+ memos = extended.memos ||= {}
844
866
  memos[idx] = memo
845
867
  end
846
868
 
847
869
  if (extras = extension.added_extras)
848
- ae = extended[:added_extras] ||= []
870
+ ae = extended.added_extras ||= []
849
871
  ae.concat(extras)
850
872
  end
851
873
 
852
- extended[:obj] = extended_obj
853
- extended[:args] = extended_args
874
+ extended.object = extended_obj
875
+ extended.arguments = extended_args
854
876
  run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
855
877
  end
856
878
  else
857
879
  yield(obj, args)
858
880
  end
859
881
  end
882
+
883
+ def apply_own_complexity_to(child_complexity, query, nodes)
884
+ case (own_complexity = complexity)
885
+ when Numeric
886
+ own_complexity + child_complexity
887
+ when Proc
888
+ arguments = query.arguments_for(nodes.first, self)
889
+ if arguments.is_a?(GraphQL::ExecutionError)
890
+ return child_complexity
891
+ elsif arguments.respond_to?(:keyword_arguments)
892
+ arguments = arguments.keyword_arguments
893
+ end
894
+
895
+ own_complexity.call(query.context, arguments, child_complexity)
896
+ else
897
+ raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
898
+ end
899
+ end
860
900
  end
861
901
  end
862
902
  end
@@ -71,14 +71,11 @@ module GraphQL
71
71
  elsif inherited_extras
72
72
  inherited_extras
73
73
  else
74
- NO_EXTRAS
74
+ GraphQL::EmptyObjects::EMPTY_ARRAY
75
75
  end
76
76
  end
77
77
  end
78
78
 
79
- NO_EXTRAS = [].freeze
80
- private_constant :NO_EXTRAS
81
-
82
79
  # Called when this extension is attached to a field.
83
80
  # The field definition may be extended during this method.
84
81
  # @return [void]
@@ -2,17 +2,12 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  module FindInheritedValue
5
- module EmptyObjects
6
- EMPTY_HASH = {}.freeze
7
- EMPTY_ARRAY = [].freeze
8
- end
9
-
10
5
  def self.extended(child_cls)
11
- child_cls.singleton_class.include(EmptyObjects)
6
+ child_cls.singleton_class.include(GraphQL::EmptyObjects)
12
7
  end
13
8
 
14
9
  def self.included(child_cls)
15
- child_cls.include(EmptyObjects)
10
+ child_cls.include(GraphQL::EmptyObjects)
16
11
  end
17
12
 
18
13
  private