graphql 2.0.13 → 2.3.10

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

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