graphql 2.4.3 → 2.5.2

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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +2 -1
  3. data/lib/graphql/analysis/visitor.rb +38 -41
  4. data/lib/graphql/analysis.rb +15 -12
  5. data/lib/graphql/autoload.rb +38 -0
  6. data/lib/graphql/backtrace/table.rb +118 -55
  7. data/lib/graphql/backtrace.rb +1 -19
  8. data/lib/graphql/current.rb +6 -1
  9. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  10. data/lib/graphql/dashboard/installable.rb +22 -0
  11. data/lib/graphql/dashboard/limiters.rb +93 -0
  12. data/lib/graphql/dashboard/operation_store.rb +199 -0
  13. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  14. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  15. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  16. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  17. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  18. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  19. data/lib/graphql/dashboard/statics/icon.png +0 -0
  20. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  21. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  22. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  23. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  24. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  25. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  26. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  27. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  28. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  29. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  30. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  31. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  36. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  37. data/lib/graphql/dashboard.rb +158 -0
  38. data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
  39. data/lib/graphql/dataloader/active_record_source.rb +26 -0
  40. data/lib/graphql/dataloader/async_dataloader.rb +21 -9
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/source.rb +3 -3
  43. data/lib/graphql/dataloader.rb +43 -14
  44. data/lib/graphql/execution/interpreter/resolve.rb +3 -3
  45. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +34 -4
  46. data/lib/graphql/execution/interpreter/runtime.rb +94 -51
  47. data/lib/graphql/execution/interpreter.rb +16 -7
  48. data/lib/graphql/execution/multiplex.rb +1 -5
  49. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  50. data/lib/graphql/invalid_name_error.rb +1 -1
  51. data/lib/graphql/invalid_null_error.rb +5 -15
  52. data/lib/graphql/language/cache.rb +13 -0
  53. data/lib/graphql/language/document_from_schema_definition.rb +8 -7
  54. data/lib/graphql/language/lexer.rb +11 -4
  55. data/lib/graphql/language/nodes.rb +3 -0
  56. data/lib/graphql/language/parser.rb +15 -8
  57. data/lib/graphql/language/printer.rb +8 -8
  58. data/lib/graphql/language/static_visitor.rb +37 -33
  59. data/lib/graphql/language/visitor.rb +59 -55
  60. data/lib/graphql/pagination/connection.rb +1 -1
  61. data/lib/graphql/query/context/scoped_context.rb +1 -1
  62. data/lib/graphql/query/context.rb +6 -5
  63. data/lib/graphql/query/variable_validation_error.rb +1 -1
  64. data/lib/graphql/query.rb +19 -23
  65. data/lib/graphql/railtie.rb +7 -0
  66. data/lib/graphql/schema/addition.rb +1 -1
  67. data/lib/graphql/schema/argument.rb +7 -8
  68. data/lib/graphql/schema/build_from_definition.rb +99 -53
  69. data/lib/graphql/schema/directive/flagged.rb +3 -1
  70. data/lib/graphql/schema/directive.rb +2 -2
  71. data/lib/graphql/schema/enum.rb +36 -1
  72. data/lib/graphql/schema/enum_value.rb +1 -1
  73. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  74. data/lib/graphql/schema/field.rb +27 -13
  75. data/lib/graphql/schema/field_extension.rb +1 -1
  76. data/lib/graphql/schema/has_single_input_argument.rb +3 -1
  77. data/lib/graphql/schema/input_object.rb +77 -40
  78. data/lib/graphql/schema/interface.rb +3 -2
  79. data/lib/graphql/schema/loader.rb +1 -1
  80. data/lib/graphql/schema/member/has_arguments.rb +25 -17
  81. data/lib/graphql/schema/member/has_dataloader.rb +60 -0
  82. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  83. data/lib/graphql/schema/member/has_directives.rb +4 -4
  84. data/lib/graphql/schema/member/has_fields.rb +19 -1
  85. data/lib/graphql/schema/member/has_interfaces.rb +5 -5
  86. data/lib/graphql/schema/member/has_validators.rb +1 -1
  87. data/lib/graphql/schema/member/scoped.rb +1 -1
  88. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  89. data/lib/graphql/schema/member.rb +1 -0
  90. data/lib/graphql/schema/object.rb +25 -8
  91. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  92. data/lib/graphql/schema/resolver.rb +12 -10
  93. data/lib/graphql/schema/subscription.rb +52 -6
  94. data/lib/graphql/schema/union.rb +1 -1
  95. data/lib/graphql/schema/validator/required_validator.rb +23 -6
  96. data/lib/graphql/schema/validator.rb +1 -1
  97. data/lib/graphql/schema/visibility/migration.rb +1 -0
  98. data/lib/graphql/schema/visibility/profile.rb +95 -243
  99. data/lib/graphql/schema/visibility/visit.rb +190 -0
  100. data/lib/graphql/schema/visibility.rb +169 -28
  101. data/lib/graphql/schema/warden.rb +18 -5
  102. data/lib/graphql/schema.rb +93 -44
  103. data/lib/graphql/static_validation/all_rules.rb +1 -1
  104. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  105. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
  106. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  107. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  108. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  109. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  110. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  111. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  112. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  113. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  114. data/lib/graphql/static_validation/validation_context.rb +1 -0
  115. data/lib/graphql/static_validation/validator.rb +6 -1
  116. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  117. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  118. data/lib/graphql/subscriptions/event.rb +12 -1
  119. data/lib/graphql/subscriptions/serialize.rb +1 -1
  120. data/lib/graphql/subscriptions.rb +1 -1
  121. data/lib/graphql/testing/helpers.rb +7 -4
  122. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  123. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  124. data/lib/graphql/tracing/appoptics_trace.rb +9 -1
  125. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  126. data/lib/graphql/tracing/appsignal_trace.rb +32 -55
  127. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  128. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  129. data/lib/graphql/tracing/data_dog_trace.rb +46 -158
  130. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  131. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  132. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  133. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  134. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  135. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  136. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  137. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  138. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  139. data/lib/graphql/tracing/notifications_trace.rb +182 -34
  140. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  141. data/lib/graphql/tracing/null_trace.rb +9 -0
  142. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  143. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  144. data/lib/graphql/tracing/perfetto_trace.rb +734 -0
  145. data/lib/graphql/tracing/platform_trace.rb +5 -0
  146. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  147. data/lib/graphql/tracing/prometheus_trace.rb +72 -68
  148. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  149. data/lib/graphql/tracing/scout_trace.rb +32 -55
  150. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  151. data/lib/graphql/tracing/sentry_trace.rb +62 -94
  152. data/lib/graphql/tracing/statsd_trace.rb +33 -41
  153. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  154. data/lib/graphql/tracing/trace.rb +111 -1
  155. data/lib/graphql/tracing.rb +31 -30
  156. data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
  157. data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
  158. data/lib/graphql/types.rb +18 -11
  159. data/lib/graphql/version.rb +1 -1
  160. data/lib/graphql.rb +55 -47
  161. metadata +146 -11
  162. data/lib/graphql/backtrace/inspect_result.rb +0 -38
  163. data/lib/graphql/backtrace/trace.rb +0 -93
  164. data/lib/graphql/backtrace/tracer.rb +0 -80
  165. data/lib/graphql/schema/null_mask.rb +0 -11
  166. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/query/context/scoped_context"
3
2
 
4
3
  module GraphQL
5
4
  class Query
@@ -104,7 +103,7 @@ module GraphQL
104
103
  if key == :current_path
105
104
  current_path
106
105
  else
107
- (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
106
+ (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
108
107
  (query_runtime_state = current_runtime_state[@query]) &&
109
108
  (query_runtime_state.public_send(key))
110
109
  end
@@ -144,7 +143,7 @@ module GraphQL
144
143
  end
145
144
 
146
145
  def current_path
147
- current_runtime_state = Thread.current[:__graphql_runtime_info]
146
+ current_runtime_state = Fiber[:__graphql_runtime_info]
148
147
  query_runtime_state = current_runtime_state && current_runtime_state[@query]
149
148
 
150
149
  path = query_runtime_state &&
@@ -169,7 +168,7 @@ module GraphQL
169
168
 
170
169
  def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
171
170
  if RUNTIME_METADATA_KEYS.include?(key)
172
- (runtime = Thread.current[:__graphql_runtime_info]) &&
171
+ (runtime = Fiber[:__graphql_runtime_info]) &&
173
172
  (query_runtime_state = runtime[@query]) &&
174
173
  (query_runtime_state.public_send(key))
175
174
  elsif @scoped_context.key?(key)
@@ -187,7 +186,7 @@ module GraphQL
187
186
 
188
187
  def dig(key, *other_keys)
189
188
  if RUNTIME_METADATA_KEYS.include?(key)
190
- (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
189
+ (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
191
190
  (query_runtime_state = current_runtime_state[@query]) &&
192
191
  (obj = query_runtime_state.public_send(key)) &&
193
192
  if other_keys.empty?
@@ -289,3 +288,5 @@ module GraphQL
289
288
  end
290
289
  end
291
290
  end
291
+
292
+ require "graphql/query/context/scoped_context"
@@ -10,7 +10,7 @@ module GraphQL
10
10
 
11
11
  msg ||= "Variable $#{variable_ast.name} of type #{type.to_type_signature} was provided invalid value"
12
12
 
13
- if problem_fields.any?
13
+ if !problem_fields.empty?
14
14
  msg += " for #{problem_fields.join(", ")}"
15
15
  end
16
16
 
data/lib/graphql/query.rb CHANGED
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/query/context"
3
- require "graphql/query/fingerprint"
4
- require "graphql/query/null_context"
5
- require "graphql/query/result"
6
- require "graphql/query/variables"
7
- require "graphql/query/input_validation_result"
8
- require "graphql/query/variable_validation_error"
9
- require "graphql/query/validation_pipeline"
10
2
 
11
3
  module GraphQL
12
4
  # A combination of query string and {Schema} instance which can be reduced to a {#result}.
13
5
  class Query
6
+ extend Autoload
14
7
  include Tracing::Traceable
15
8
  extend Forwardable
16
9
 
10
+ autoload :Context, "graphql/query/context"
11
+ autoload :Fingerprint, "graphql/query/fingerprint"
12
+ autoload :NullContext, "graphql/query/null_context"
13
+ autoload :Result, "graphql/query/result"
14
+ autoload :Variables, "graphql/query/variables"
15
+ autoload :InputValidationResult, "graphql/query/input_validation_result"
16
+ autoload :VariableValidationError, "graphql/query/variable_validation_error"
17
+ autoload :ValidationPipeline, "graphql/query/validation_pipeline"
18
+
17
19
  class OperationNameMissingError < GraphQL::ExecutionError
18
20
  def initialize(name)
19
21
  msg = if name.nil?
@@ -95,21 +97,23 @@ module GraphQL
95
97
  # @param root_value [Object] the object used to resolve fields on the root type
96
98
  # @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
97
99
  # @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
98
- # @param visibility_profile [Symbol]
99
- def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
100
+ # @param visibility_profile [Symbol] Another way to assign `context[:visibility_profile]`
101
+ def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, multiplex: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
100
102
  # Even if `variables: nil` is passed, use an empty hash for simpler logic
101
103
  variables ||= {}
104
+ @multiplex = multiplex
102
105
  @schema = schema
103
106
  @context = schema.context_class.new(query: self, values: context)
107
+ if visibility_profile
108
+ @context[:visibility_profile] ||= visibility_profile
109
+ end
104
110
 
105
111
  if use_visibility_profile.nil?
106
112
  use_visibility_profile = warden ? false : schema.use_visibility_profile?
107
113
  end
108
114
 
109
- @visibility_profile = visibility_profile
110
-
111
115
  if use_visibility_profile
112
- @visibility_profile = @schema.visibility.profile_for(@context, visibility_profile)
116
+ @visibility_profile = @schema.visibility.profile_for(@context)
113
117
  @warden = Schema::Warden::NullWarden.new(context: @context, schema: @schema)
114
118
  else
115
119
  @visibility_profile = nil
@@ -125,15 +129,7 @@ module GraphQL
125
129
  context_tracers = (context ? context.fetch(:tracers, []) : [])
126
130
  @tracers = schema.tracers + context_tracers
127
131
 
128
- # Support `ctx[:backtrace] = true` for wrapping backtraces
129
- if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
130
- if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
131
- context_tracers += [GraphQL::Backtrace::Tracer]
132
- @tracers << GraphQL::Backtrace::Tracer
133
- end
134
- end
135
-
136
- if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
132
+ if !context_tracers.empty? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
137
133
  raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
138
134
  end
139
135
 
@@ -479,7 +475,7 @@ module GraphQL
479
475
  @mutation = false
480
476
  @subscription = false
481
477
  operation_name_error = nil
482
- if @operations.any?
478
+ if !@operations.empty?
483
479
  @selected_operation = find_operation(@operations, @operation_name)
484
480
  if @selected_operation.nil?
485
481
  operation_name_error = GraphQL::Query::OperationNameMissingError.new(@operation_name)
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphQL
4
+ # Support {GraphQL::Parser::Cache} and {GraphQL.eager_load!}
5
+ #
6
+ # @example Enable the parser cache with default directory
7
+ #
8
+ # config.graphql.parser_cache = true
9
+ #
4
10
  class Railtie < Rails::Railtie
5
11
  config.graphql = ActiveSupport::OrderedOptions.new
6
12
  config.graphql.parser_cache = false
13
+ config.eager_load_namespaces << GraphQL
7
14
 
8
15
  initializer("graphql.cache") do |app|
9
16
  if config.graphql.parser_cache
@@ -40,7 +40,7 @@ module GraphQL
40
40
  end
41
41
 
42
42
  def add_directives_from(owner)
43
- if (dir_instances = owner.directives).any?
43
+ if !(dir_instances = owner.directives).empty?
44
44
  dirs = dir_instances.map(&:class)
45
45
  @directives.merge(dirs)
46
46
  add_type_and_traverse(dirs)
@@ -53,6 +53,7 @@ module GraphQL
53
53
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, comment: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
54
54
  arg_name ||= name
55
55
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
56
+ NameValidator.validate!(@name)
56
57
  @type_expr = type_expr || type
57
58
  @description = desc || description
58
59
  @comment = comment
@@ -89,11 +90,8 @@ module GraphQL
89
90
  end
90
91
 
91
92
  if definition_block
92
- if definition_block.arity == 1
93
- instance_exec(self, &definition_block)
94
- else
95
- instance_eval(&definition_block)
96
- end
93
+ # `self` will still be self, it will also be the first argument to the block:
94
+ instance_exec(self, &definition_block)
97
95
  end
98
96
  end
99
97
 
@@ -219,7 +217,7 @@ module GraphQL
219
217
  # @api private
220
218
  def prepare_value(obj, value, context: nil)
221
219
  if type.unwrap.kind.input_object?
222
- value = recursively_prepare_input_object(value, type)
220
+ value = recursively_prepare_input_object(value, type, context)
223
221
  end
224
222
 
225
223
  Schema::Validator.validate!(validators, obj, context, value)
@@ -400,15 +398,16 @@ module GraphQL
400
398
 
401
399
  private
402
400
 
403
- def recursively_prepare_input_object(value, type)
401
+ def recursively_prepare_input_object(value, type, context)
404
402
  if type.non_null?
405
403
  type = type.of_type
406
404
  end
407
405
 
408
406
  if type.list? && !value.nil?
409
407
  inner_type = type.of_type
410
- value.map { |v| recursively_prepare_input_object(v, inner_type) }
408
+ value.map { |v| recursively_prepare_input_object(v, inner_type, context) }
411
409
  elsif value.is_a?(GraphQL::Schema::InputObject)
410
+ value.validate_for(context)
412
411
  value.prepare
413
412
  else
414
413
  value
@@ -20,8 +20,8 @@ module GraphQL
20
20
  from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
21
21
  end
22
22
 
23
- def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
24
- Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
23
+ def from_document(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay: false)
24
+ Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using, base_types: base_types)
25
25
  end
26
26
  end
27
27
 
@@ -30,9 +30,18 @@ module GraphQL
30
30
  include GraphQL::EmptyObjects
31
31
  extend self
32
32
 
33
- def build(schema_superclass, document, default_resolve:, using: {}, relay:)
33
+ def build(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay:)
34
34
  raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
35
35
 
36
+ base_types = {
37
+ object: GraphQL::Schema::Object,
38
+ interface: GraphQL::Schema::Interface,
39
+ union: GraphQL::Schema::Union,
40
+ scalar: GraphQL::Schema::Scalar,
41
+ enum: GraphQL::Schema::Enum,
42
+ input_object: GraphQL::Schema::InputObject,
43
+ }.merge!(base_types)
44
+
36
45
  if default_resolve.is_a?(Hash)
37
46
  default_resolve = ResolveMap.new(default_resolve)
38
47
  end
@@ -53,7 +62,7 @@ module GraphQL
53
62
  types[type_name] ||= begin
54
63
  defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
55
64
  if defn
56
- build_definition_from_node(defn, directive_type_resolver, default_resolve)
65
+ build_definition_from_node(defn, directive_type_resolver, default_resolve, base_types)
57
66
  elsif (built_in_defn = GraphQL::Schema::BUILT_IN_TYPES[type_name])
58
67
  built_in_defn
59
68
  else
@@ -77,14 +86,20 @@ module GraphQL
77
86
  case definition
78
87
  when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
79
88
  nil # already handled
80
- when GraphQL::Language::Nodes::SchemaExtension
89
+ when GraphQL::Language::Nodes::SchemaExtension,
90
+ GraphQL::Language::Nodes::ScalarTypeExtension,
91
+ GraphQL::Language::Nodes::ObjectTypeExtension,
92
+ GraphQL::Language::Nodes::InterfaceTypeExtension,
93
+ GraphQL::Language::Nodes::UnionTypeExtension,
94
+ GraphQL::Language::Nodes::EnumTypeExtension,
95
+ GraphQL::Language::Nodes::InputObjectTypeExtension
81
96
  schema_extensions ||= []
82
97
  schema_extensions << definition
83
98
  else
84
99
  # It's possible that this was already loaded by the directives
85
100
  prev_type = types[definition.name]
86
101
  if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
87
- types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
102
+ types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve, base_types)
88
103
  end
89
104
  end
90
105
  end
@@ -124,6 +139,34 @@ module GraphQL
124
139
 
125
140
  raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
126
141
 
142
+ schema_extensions&.each do |ext|
143
+ next if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
144
+
145
+ built_type = types[ext.name]
146
+
147
+ case ext
148
+ when GraphQL::Language::Nodes::ScalarTypeExtension
149
+ build_directives(built_type, ext, type_resolver)
150
+ when GraphQL::Language::Nodes::ObjectTypeExtension
151
+ build_directives(built_type, ext, type_resolver)
152
+ build_fields(built_type, ext.fields, type_resolver, default_resolve: true)
153
+ build_interfaces(built_type, ext.interfaces, type_resolver)
154
+ when GraphQL::Language::Nodes::InterfaceTypeExtension
155
+ build_directives(built_type, ext, type_resolver)
156
+ build_fields(built_type, ext.fields, type_resolver, default_resolve: nil)
157
+ build_interfaces(built_type, ext.interfaces, type_resolver)
158
+ when GraphQL::Language::Nodes::UnionTypeExtension
159
+ build_directives(built_type, ext, type_resolver)
160
+ built_type.possible_types(*ext.types.map { |type_name| type_resolver.call(type_name) })
161
+ when GraphQL::Language::Nodes::EnumTypeExtension
162
+ build_directives(built_type, ext, type_resolver)
163
+ build_values(built_type, ext.values, type_resolver)
164
+ when GraphQL::Language::Nodes::InputObjectTypeExtension
165
+ build_directives(built_type, ext, type_resolver)
166
+ build_arguments(built_type, ext.fields, type_resolver)
167
+ end
168
+ end
169
+
127
170
  builder = self
128
171
 
129
172
  found_types = types.values
@@ -192,8 +235,8 @@ module GraphQL
192
235
  end
193
236
  end
194
237
 
195
- if schema_extensions
196
- schema_extensions.each do |ext|
238
+ schema_extensions&.each do |ext|
239
+ if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
197
240
  build_directives(schema_class, ext, type_resolver)
198
241
  end
199
242
  end
@@ -205,20 +248,20 @@ module GraphQL
205
248
  raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
206
249
  }
207
250
 
208
- def build_definition_from_node(definition, type_resolver, default_resolve)
251
+ def build_definition_from_node(definition, type_resolver, default_resolve, base_types)
209
252
  case definition
210
253
  when GraphQL::Language::Nodes::EnumTypeDefinition
211
- build_enum_type(definition, type_resolver)
254
+ build_enum_type(definition, type_resolver, base_types[:enum])
212
255
  when GraphQL::Language::Nodes::ObjectTypeDefinition
213
- build_object_type(definition, type_resolver)
256
+ build_object_type(definition, type_resolver, base_types[:object])
214
257
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
215
- build_interface_type(definition, type_resolver)
258
+ build_interface_type(definition, type_resolver, base_types[:interface])
216
259
  when GraphQL::Language::Nodes::UnionTypeDefinition
217
- build_union_type(definition, type_resolver)
260
+ build_union_type(definition, type_resolver, base_types[:union])
218
261
  when GraphQL::Language::Nodes::ScalarTypeDefinition
219
- build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
262
+ build_scalar_type(definition, type_resolver, base_types[:scalar], default_resolve: default_resolve)
220
263
  when GraphQL::Language::Nodes::InputObjectTypeDefinition
221
- build_input_object_type(definition, type_resolver)
264
+ build_input_object_type(definition, type_resolver, base_types[:input_object])
222
265
  end
223
266
  end
224
267
 
@@ -284,22 +327,26 @@ module GraphQL
284
327
  end
285
328
  end
286
329
 
287
- def build_enum_type(enum_type_definition, type_resolver)
330
+ def build_enum_type(enum_type_definition, type_resolver, base_type)
288
331
  builder = self
289
- Class.new(GraphQL::Schema::Enum) do
332
+ Class.new(base_type) do
290
333
  graphql_name(enum_type_definition.name)
291
334
  builder.build_directives(self, enum_type_definition, type_resolver)
292
335
  description(enum_type_definition.description)
293
336
  ast_node(enum_type_definition)
294
- enum_type_definition.values.each do |enum_value_definition|
295
- value(enum_value_definition.name,
296
- value: enum_value_definition.name,
297
- deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
298
- description: enum_value_definition.description,
299
- directives: builder.prepare_directives(enum_value_definition, type_resolver),
300
- ast_node: enum_value_definition,
301
- )
302
- end
337
+ builder.build_values(self, enum_type_definition.values, type_resolver)
338
+ end
339
+ end
340
+
341
+ def build_values(type_class, enum_value_definitions, type_resolver)
342
+ enum_value_definitions.each do |enum_value_definition|
343
+ type_class.value(enum_value_definition.name,
344
+ value: enum_value_definition.name,
345
+ deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
346
+ description: enum_value_definition.description,
347
+ directives: prepare_directives(enum_value_definition, type_resolver),
348
+ ast_node: enum_value_definition,
349
+ )
303
350
  end
304
351
  end
305
352
 
@@ -313,9 +360,9 @@ module GraphQL
313
360
  reason.value
314
361
  end
315
362
 
316
- def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
363
+ def build_scalar_type(scalar_type_definition, type_resolver, base_type, default_resolve:)
317
364
  builder = self
318
- Class.new(GraphQL::Schema::Scalar) do
365
+ Class.new(base_type) do
319
366
  graphql_name(scalar_type_definition.name)
320
367
  description(scalar_type_definition.description)
321
368
  ast_node(scalar_type_definition)
@@ -336,9 +383,9 @@ module GraphQL
336
383
  end
337
384
  end
338
385
 
339
- def build_union_type(union_type_definition, type_resolver)
386
+ def build_union_type(union_type_definition, type_resolver, base_type)
340
387
  builder = self
341
- Class.new(GraphQL::Schema::Union) do
388
+ Class.new(base_type) do
342
389
  graphql_name(union_type_definition.name)
343
390
  description(union_type_definition.description)
344
391
  possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
@@ -347,27 +394,28 @@ module GraphQL
347
394
  end
348
395
  end
349
396
 
350
- def build_object_type(object_type_definition, type_resolver)
397
+ def build_object_type(object_type_definition, type_resolver, base_type)
351
398
  builder = self
352
399
 
353
- Class.new(GraphQL::Schema::Object) do
400
+ Class.new(base_type) do
354
401
  graphql_name(object_type_definition.name)
355
402
  description(object_type_definition.description)
356
403
  ast_node(object_type_definition)
357
404
  builder.build_directives(self, object_type_definition, type_resolver)
358
-
359
- object_type_definition.interfaces.each do |interface_name|
360
- interface_defn = type_resolver.call(interface_name)
361
- implements(interface_defn)
362
- end
363
-
405
+ builder.build_interfaces(self, object_type_definition.interfaces, type_resolver)
364
406
  builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
365
407
  end
366
408
  end
367
409
 
368
- def build_input_object_type(input_object_type_definition, type_resolver)
410
+ def build_interfaces(type_class, interface_names, type_resolver)
411
+ interface_names.each do |interface_name|
412
+ type_class.implements(type_resolver.call(interface_name))
413
+ end
414
+ end
415
+
416
+ def build_input_object_type(input_object_type_definition, type_resolver, base_type)
369
417
  builder = self
370
- Class.new(GraphQL::Schema::InputObject) do
418
+ Class.new(base_type) do
371
419
  graphql_name(input_object_type_definition.name)
372
420
  description(input_object_type_definition.description)
373
421
  ast_node(input_object_type_definition)
@@ -427,16 +475,13 @@ module GraphQL
427
475
  end
428
476
  end
429
477
 
430
- def build_interface_type(interface_type_definition, type_resolver)
478
+ def build_interface_type(interface_type_definition, type_resolver, base_type)
431
479
  builder = self
432
480
  Module.new do
433
- include GraphQL::Schema::Interface
481
+ include base_type
434
482
  graphql_name(interface_type_definition.name)
435
483
  description(interface_type_definition.description)
436
- interface_type_definition.interfaces.each do |interface_name|
437
- interface_defn = type_resolver.call(interface_name)
438
- implements(interface_defn)
439
- end
484
+ builder.build_interfaces(self, interface_type_definition.interfaces, type_resolver)
440
485
  ast_node(interface_type_definition)
441
486
  builder.build_directives(self, interface_type_definition, type_resolver)
442
487
 
@@ -467,17 +512,18 @@ module GraphQL
467
512
 
468
513
  # Don't do this for interfaces
469
514
  if default_resolve
470
- owner.class_eval <<-RUBY, __FILE__, __LINE__
471
- # frozen_string_literal: true
472
- def #{resolve_method_name}(**args)
473
- field_instance = self.class.get_field("#{field_definition.name}")
474
- context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
475
- end
476
- RUBY
515
+ define_field_resolve_method(owner, resolve_method_name, field_definition.name)
477
516
  end
478
517
  end
479
518
  end
480
519
 
520
+ def define_field_resolve_method(owner, method_name, field_name)
521
+ owner.define_method(method_name) { |**args|
522
+ field_instance = self.class.get_field(field_name)
523
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
524
+ }
525
+ end
526
+
481
527
  def build_resolve_type(lookup_hash, directives, missing_type_handler)
482
528
  resolve_type_proc = nil
483
529
  resolve_type_proc = ->(ast_node) {
@@ -37,6 +37,8 @@ module GraphQL
37
37
 
38
38
  argument :by, [String], "Flags to check for this schema member"
39
39
 
40
+ repeatable(true)
41
+
40
42
  module VisibleByFlag
41
43
  def self.included(schema_class)
42
44
  schema_class.extend(self)
@@ -45,7 +47,7 @@ module GraphQL
45
47
  def visible?(context)
46
48
  if dir = self.directives.find { |d| d.is_a?(Flagged) }
47
49
  relevant_flags = (f = context[:flags]) && dir.arguments[:by] & f # rubocop:disable Development/ContextIsPassedCop -- definition-related
48
- relevant_flags && relevant_flags.any? && super
50
+ relevant_flags && !relevant_flags.empty? && super
49
51
  else
50
52
  super
51
53
  end
@@ -29,7 +29,7 @@ module GraphQL
29
29
  end
30
30
 
31
31
  def locations(*new_locations)
32
- if new_locations.any?
32
+ if !new_locations.empty?
33
33
  new_locations.each do |new_loc|
34
34
  if !LOCATIONS.include?(new_loc.to_sym)
35
35
  raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
@@ -99,7 +99,7 @@ module GraphQL
99
99
 
100
100
  def inherited(subclass)
101
101
  super
102
- subclass.class_eval do
102
+ subclass.class_exec do
103
103
  @default_graphql_name ||= nil
104
104
  end
105
105
  end
@@ -61,12 +61,19 @@ module GraphQL
61
61
  # @option kwargs [String] :description, the GraphQL description for this value, present in documentation
62
62
  # @option kwargs [String] :comment, the GraphQL comment for this value, present in documentation
63
63
  # @option kwargs [::Object] :value the translated Ruby value for this object (defaults to `graphql_name`)
64
+ # @option kwargs [::Object] :value_method, the method name to fetch `graphql_name` (defaults to `graphql_name.downcase`)
64
65
  # @option kwargs [String] :deprecation_reason if this object is deprecated, include a message here
66
+ # @param value_method [Symbol, false] A method to generate for this value, or `false` to skip generation
65
67
  # @return [void]
66
68
  # @see {Schema::EnumValue} which handles these inputs by default
67
- def value(*args, **kwargs, &block)
69
+ def value(*args, value_method: nil, **kwargs, &block)
68
70
  kwargs[:owner] = self
69
71
  value = enum_value_class.new(*args, **kwargs, &block)
72
+
73
+ if value_method || (value_methods && value_method != false)
74
+ generate_value_method(value, value_method)
75
+ end
76
+
70
77
  key = value.graphql_name
71
78
  prev_value = own_values[key]
72
79
  case prev_value
@@ -154,6 +161,18 @@ module GraphQL
154
161
  end
155
162
  end
156
163
 
164
+ def value_methods(new_value = NOT_CONFIGURED)
165
+ if NOT_CONFIGURED.equal?(new_value)
166
+ if @value_methods != nil
167
+ @value_methods
168
+ else
169
+ find_inherited_value(:value_methods, false)
170
+ end
171
+ else
172
+ @value_methods = new_value
173
+ end
174
+ end
175
+
157
176
  def kind
158
177
  GraphQL::TypeKinds::ENUM
159
178
  end
@@ -215,6 +234,7 @@ module GraphQL
215
234
  # because they would end up with names like `#<Class0x1234>::UnresolvedValueError` which messes up bug trackers
216
235
  child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
217
236
  end
237
+ child_class.class_exec { @value_methods = nil }
218
238
  super
219
239
  end
220
240
 
@@ -223,6 +243,21 @@ module GraphQL
223
243
  def own_values
224
244
  @own_values ||= {}
225
245
  end
246
+
247
+ def generate_value_method(value, configured_value_method)
248
+ return if configured_value_method == false
249
+
250
+ value_method_name = configured_value_method || value.graphql_name.downcase
251
+
252
+ if respond_to?(value_method_name.to_sym)
253
+ warn "Failed to define value method for :#{value_method_name}, because " \
254
+ "#{value.owner.name || value.owner.graphql_name} already responds to that method. Use `value_method:` to override the method name " \
255
+ "or `value_method: false` to disable Enum value method generation."
256
+ return
257
+ end
258
+
259
+ define_singleton_method(value_method_name) { value.graphql_name }
260
+ end
226
261
  end
227
262
 
228
263
  enum_value_class(GraphQL::Schema::EnumValue)
@@ -48,7 +48,7 @@ module GraphQL
48
48
  end
49
49
 
50
50
  if block_given?
51
- instance_eval(&block)
51
+ instance_exec(self, &block)
52
52
  end
53
53
  end
54
54
 
@@ -12,7 +12,7 @@ module GraphQL
12
12
  if ret_type.respond_to?(:scope_items)
13
13
  scoped_items = ret_type.scope_items(value, context)
14
14
  if !scoped_items.equal?(value) && !ret_type.reauthorize_scoped_objects
15
- if (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
15
+ if (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
16
16
  (query_runtime_state = current_runtime_state[context.query])
17
17
  query_runtime_state.was_authorized_by_scope_items = true
18
18
  end