graphql 1.12.24 → 1.13.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/install_generator.rb +10 -3
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  10. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_generator.rb +5 -30
  12. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  13. data/lib/generators/graphql/object_generator.rb +8 -37
  14. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  15. data/lib/generators/graphql/scalar_generator.rb +4 -2
  16. data/lib/generators/graphql/templates/enum.erb +5 -1
  17. data/lib/generators/graphql/templates/input.erb +9 -0
  18. data/lib/generators/graphql/templates/interface.erb +4 -2
  19. data/lib/generators/graphql/templates/mutation.erb +1 -1
  20. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  21. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  22. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  23. data/lib/generators/graphql/templates/object.erb +4 -2
  24. data/lib/generators/graphql/templates/scalar.erb +3 -1
  25. data/lib/generators/graphql/templates/union.erb +4 -2
  26. data/lib/generators/graphql/type_generator.rb +46 -10
  27. data/lib/generators/graphql/union_generator.rb +5 -5
  28. data/lib/graphql/analysis/ast/field_usage.rb +2 -2
  29. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  30. data/lib/graphql/analysis/ast/visitor.rb +5 -4
  31. data/lib/graphql/argument.rb +1 -1
  32. data/lib/graphql/backtrace/table.rb +1 -1
  33. data/lib/graphql/base_type.rb +5 -3
  34. data/lib/graphql/boolean_type.rb +1 -1
  35. data/lib/graphql/dataloader/source.rb +2 -2
  36. data/lib/graphql/dataloader.rb +55 -22
  37. data/lib/graphql/date_encoding_error.rb +16 -0
  38. data/lib/graphql/define/instance_definable.rb +15 -0
  39. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  40. data/lib/graphql/directive/include_directive.rb +1 -1
  41. data/lib/graphql/directive/skip_directive.rb +1 -1
  42. data/lib/graphql/directive.rb +1 -5
  43. data/lib/graphql/enum_type.rb +7 -3
  44. data/lib/graphql/execution/errors.rb +1 -0
  45. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  46. data/lib/graphql/execution/interpreter/arguments_cache.rb +6 -4
  47. data/lib/graphql/execution/interpreter/runtime.rb +66 -38
  48. data/lib/graphql/execution/lookahead.rb +2 -2
  49. data/lib/graphql/execution/multiplex.rb +4 -1
  50. data/lib/graphql/field.rb +1 -1
  51. data/lib/graphql/float_type.rb +1 -1
  52. data/lib/graphql/id_type.rb +1 -1
  53. data/lib/graphql/input_object_type.rb +1 -1
  54. data/lib/graphql/int_type.rb +1 -1
  55. data/lib/graphql/interface_type.rb +1 -1
  56. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  57. data/lib/graphql/introspection/directive_type.rb +5 -3
  58. data/lib/graphql/introspection/entry_points.rb +2 -2
  59. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  60. data/lib/graphql/introspection/field_type.rb +3 -3
  61. data/lib/graphql/introspection/input_value_type.rb +4 -4
  62. data/lib/graphql/introspection/schema_type.rb +9 -4
  63. data/lib/graphql/introspection/type_type.rb +18 -12
  64. data/lib/graphql/introspection.rb +4 -1
  65. data/lib/graphql/language/block_string.rb +2 -6
  66. data/lib/graphql/language/document_from_schema_definition.rb +11 -4
  67. data/lib/graphql/language/lexer.rb +50 -28
  68. data/lib/graphql/language/lexer.rl +2 -4
  69. data/lib/graphql/language/nodes.rb +4 -3
  70. data/lib/graphql/language/parser.rb +841 -820
  71. data/lib/graphql/language/parser.y +13 -6
  72. data/lib/graphql/language/printer.rb +10 -1
  73. data/lib/graphql/language/sanitized_printer.rb +5 -5
  74. data/lib/graphql/language/token.rb +0 -4
  75. data/lib/graphql/name_validator.rb +0 -4
  76. data/lib/graphql/object_type.rb +2 -2
  77. data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
  78. data/lib/graphql/pagination/relation_connection.rb +59 -29
  79. data/lib/graphql/query/arguments.rb +1 -1
  80. data/lib/graphql/query/arguments_cache.rb +1 -1
  81. data/lib/graphql/query/context.rb +15 -2
  82. data/lib/graphql/query/input_validation_result.rb +9 -0
  83. data/lib/graphql/query/literal_input.rb +1 -1
  84. data/lib/graphql/query/null_context.rb +12 -7
  85. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  86. data/lib/graphql/query/validation_pipeline.rb +2 -3
  87. data/lib/graphql/query/variable_validation_error.rb +2 -2
  88. data/lib/graphql/query/variables.rb +35 -4
  89. data/lib/graphql/query.rb +0 -1
  90. data/lib/graphql/relay/connection_type.rb +15 -2
  91. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  92. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  93. data/lib/graphql/relay/mutation.rb +1 -1
  94. data/lib/graphql/relay/page_info.rb +1 -1
  95. data/lib/graphql/relay/range_add.rb +4 -0
  96. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  97. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  98. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  99. data/lib/graphql/rubocop.rb +4 -0
  100. data/lib/graphql/scalar_type.rb +1 -1
  101. data/lib/graphql/schema/addition.rb +37 -28
  102. data/lib/graphql/schema/argument.rb +30 -15
  103. data/lib/graphql/schema/build_from_definition.rb +6 -5
  104. data/lib/graphql/schema/directive/feature.rb +1 -1
  105. data/lib/graphql/schema/directive/flagged.rb +2 -2
  106. data/lib/graphql/schema/directive/include.rb +1 -1
  107. data/lib/graphql/schema/directive/skip.rb +1 -1
  108. data/lib/graphql/schema/directive/transform.rb +1 -1
  109. data/lib/graphql/schema/directive.rb +23 -4
  110. data/lib/graphql/schema/enum.rb +61 -12
  111. data/lib/graphql/schema/enum_value.rb +6 -0
  112. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  113. data/lib/graphql/schema/field.rb +261 -83
  114. data/lib/graphql/schema/field_extension.rb +89 -2
  115. data/lib/graphql/schema/find_inherited_value.rb +1 -0
  116. data/lib/graphql/schema/finder.rb +5 -5
  117. data/lib/graphql/schema/input_object.rb +24 -7
  118. data/lib/graphql/schema/interface.rb +11 -20
  119. data/lib/graphql/schema/introspection_system.rb +1 -1
  120. data/lib/graphql/schema/list.rb +21 -4
  121. data/lib/graphql/schema/loader.rb +3 -0
  122. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  123. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
  124. data/lib/graphql/schema/member/build_type.rb +0 -4
  125. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  126. data/lib/graphql/schema/member/has_arguments.rb +56 -14
  127. data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
  128. data/lib/graphql/schema/member/has_fields.rb +76 -18
  129. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  130. data/lib/graphql/schema/member/validates_input.rb +2 -2
  131. data/lib/graphql/schema/member.rb +1 -0
  132. data/lib/graphql/schema/non_null.rb +9 -3
  133. data/lib/graphql/schema/object.rb +10 -75
  134. data/lib/graphql/schema/printer.rb +1 -1
  135. data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
  136. data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
  137. data/lib/graphql/schema/resolver.rb +37 -17
  138. data/lib/graphql/schema/scalar.rb +15 -1
  139. data/lib/graphql/schema/subscription.rb +11 -1
  140. data/lib/graphql/schema/traversal.rb +1 -1
  141. data/lib/graphql/schema/type_expression.rb +1 -1
  142. data/lib/graphql/schema/type_membership.rb +18 -4
  143. data/lib/graphql/schema/union.rb +8 -1
  144. data/lib/graphql/schema/validator/format_validator.rb +0 -4
  145. data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
  146. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  147. data/lib/graphql/schema/validator.rb +4 -7
  148. data/lib/graphql/schema/warden.rb +126 -53
  149. data/lib/graphql/schema.rb +120 -24
  150. data/lib/graphql/static_validation/all_rules.rb +1 -0
  151. data/lib/graphql/static_validation/base_visitor.rb +6 -6
  152. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  153. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  154. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  155. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  156. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  157. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  158. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  159. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  160. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  161. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  163. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  164. data/lib/graphql/static_validation/validation_context.rb +4 -0
  165. data/lib/graphql/string_type.rb +1 -1
  166. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
  167. data/lib/graphql/subscriptions/event.rb +20 -12
  168. data/lib/graphql/subscriptions/serialize.rb +22 -2
  169. data/lib/graphql/subscriptions.rb +17 -19
  170. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  171. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  172. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  173. data/lib/graphql/tracing/platform_tracing.rb +20 -10
  174. data/lib/graphql/types/iso_8601_date.rb +13 -5
  175. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  176. data/lib/graphql/types/relay/connection_behaviors.rb +28 -10
  177. data/lib/graphql/types/relay/default_relay.rb +5 -1
  178. data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
  179. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  180. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  181. data/lib/graphql/types/relay/node_field.rb +2 -3
  182. data/lib/graphql/types/relay/nodes_field.rb +19 -3
  183. data/lib/graphql/types/string.rb +1 -1
  184. data/lib/graphql/union_type.rb +1 -1
  185. data/lib/graphql/version.rb +1 -1
  186. data/lib/graphql.rb +22 -32
  187. metadata +31 -11
  188. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  189. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -15,23 +15,110 @@ module GraphQL
15
15
  # @return [Object]
16
16
  attr_reader :options
17
17
 
18
+ # @return [Array<Symbol>, nil] `default_argument`s added, if any were added (otherwise, `nil`)
19
+ attr_reader :added_default_arguments
20
+
18
21
  # Called when the extension is mounted with `extension(name, options)`.
19
- # The instance is frozen to avoid improper use of state during execution.
22
+ # The instance will be frozen to avoid improper use of state during execution.
20
23
  # @param field [GraphQL::Schema::Field] The field where this extension was mounted
21
24
  # @param options [Object] The second argument to `extension`, or `{}` if nothing was passed.
22
25
  def initialize(field:, options:)
23
26
  @field = field
24
27
  @options = options || {}
28
+ @added_default_arguments = nil
25
29
  apply
26
- freeze
27
30
  end
28
31
 
32
+ class << self
33
+ # @return [Array(Array, Hash), nil] A list of default argument configs, or `nil` if there aren't any
34
+ def default_argument_configurations
35
+ args = superclass.respond_to?(:default_argument_configurations) ? superclass.default_argument_configurations : nil
36
+ if @own_default_argument_configurations
37
+ if args
38
+ args.concat(@own_default_argument_configurations)
39
+ else
40
+ args = @own_default_argument_configurations.dup
41
+ end
42
+ end
43
+ args
44
+ end
45
+
46
+ # @see Argument#initialize
47
+ # @see HasArguments#argument
48
+ def default_argument(*argument_args, **argument_kwargs)
49
+ configs = @own_default_argument_configurations ||= []
50
+ configs << [argument_args, argument_kwargs]
51
+ end
52
+
53
+ # If configured, these `extras` will be added to the field if they aren't already present,
54
+ # but removed by from `arguments` before the field's `resolve` is called.
55
+ # (The extras _will_ be present for other extensions, though.)
56
+ #
57
+ # @param new_extras [Array<Symbol>] If provided, assign extras used by this extension
58
+ # @return [Array<Symbol>] any extras assigned to this extension
59
+ def extras(new_extras = nil)
60
+ if new_extras
61
+ @own_extras = new_extras
62
+ end
63
+
64
+ inherited_extras = self.superclass.respond_to?(:extras) ? superclass.extras : nil
65
+ if @own_extras
66
+ if inherited_extras
67
+ inherited_extras + @own_extras
68
+ else
69
+ @own_extras
70
+ end
71
+ elsif inherited_extras
72
+ inherited_extras
73
+ else
74
+ NO_EXTRAS
75
+ end
76
+ end
77
+ end
78
+
79
+ NO_EXTRAS = [].freeze
80
+ private_constant :NO_EXTRAS
81
+
29
82
  # Called when this extension is attached to a field.
30
83
  # The field definition may be extended during this method.
31
84
  # @return [void]
32
85
  def apply
33
86
  end
34
87
 
88
+ # Called after the field's definition block has been executed.
89
+ # (Any arguments from the block are present on `field`)
90
+ # @return [void]
91
+ def after_define
92
+ end
93
+
94
+ # @api private
95
+ def after_define_apply
96
+ after_define
97
+ if (configs = self.class.default_argument_configurations)
98
+ existing_keywords = field.all_argument_definitions.map(&:keyword)
99
+ existing_keywords.uniq!
100
+ @added_default_arguments = []
101
+ configs.each do |config|
102
+ argument_args, argument_kwargs = config
103
+ arg_name = argument_args[0]
104
+ if !existing_keywords.include?(arg_name)
105
+ @added_default_arguments << arg_name
106
+ field.argument(*argument_args, **argument_kwargs)
107
+ end
108
+ end
109
+ end
110
+ if (extras = self.class.extras).any?
111
+ @added_extras = extras - field.extras
112
+ field.extras(@added_extras)
113
+ else
114
+ @added_extras = nil
115
+ end
116
+ freeze
117
+ end
118
+
119
+ # @api private
120
+ attr_reader :added_extras
121
+
35
122
  # Called before resolving {#field}. It should either:
36
123
  #
37
124
  # - `yield` values to continue execution; OR
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Schema
3
4
  module FindInheritedValue
@@ -38,7 +38,7 @@ module GraphQL
38
38
 
39
39
  find_in_directive(directive, path: path)
40
40
  else
41
- type = schema.get_type(type_or_directive)
41
+ type = schema.get_type(type_or_directive) # rubocop:disable Development/ContextIsPassedCop -- build-time
42
42
 
43
43
  if type.nil?
44
44
  raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
@@ -56,7 +56,7 @@ module GraphQL
56
56
 
57
57
  def find_in_directive(directive, path:)
58
58
  argument_name = path.shift
59
- argument = directive.arguments[argument_name]
59
+ argument = directive.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
60
60
 
61
61
  if argument.nil?
62
62
  raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
@@ -102,7 +102,7 @@ module GraphQL
102
102
 
103
103
  def find_in_field(field, path:)
104
104
  argument_name = path.shift
105
- argument = field.arguments[argument_name]
105
+ argument = field.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
106
106
 
107
107
  if argument.nil?
108
108
  raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
@@ -119,7 +119,7 @@ module GraphQL
119
119
 
120
120
  def find_in_input_object(input_object, path:)
121
121
  field_name = path.shift
122
- input_field = input_object.arguments[field_name]
122
+ input_field = input_object.get_argument(field_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
123
123
 
124
124
  if input_field.nil?
125
125
  raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
@@ -136,7 +136,7 @@ module GraphQL
136
136
 
137
137
  def find_in_enum_type(enum_type, path:)
138
138
  value_name = path.shift
139
- enum_value = enum_type.values[value_name]
139
+ enum_value = enum_type.enum_values.find { |v| v.graphql_name == value_name } # rubocop:disable Development/ContextIsPassedCop -- build-time, not runtime
140
140
 
141
141
  if enum_value.nil?
142
142
  raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
@@ -31,7 +31,7 @@ module GraphQL
31
31
  end
32
32
  # Apply prepares, not great to have it duplicated here.
33
33
  maybe_lazies = []
34
- self.class.arguments.each_value do |arg_defn|
34
+ self.class.arguments(context).each_value do |arg_defn|
35
35
  ruby_kwargs_key = arg_defn.keyword
36
36
 
37
37
  if @ruby_style_hash.key?(ruby_kwargs_key)
@@ -79,6 +79,21 @@ module GraphQL
79
79
  end
80
80
  end
81
81
 
82
+ def self.authorized?(obj, value, ctx)
83
+ # Authorize each argument (but this doesn't apply if `prepare` is implemented):
84
+ if value.respond_to?(:key?)
85
+ arguments(ctx).each do |_name, input_obj_arg|
86
+ input_obj_arg = input_obj_arg.type_class
87
+ if value.key?(input_obj_arg.keyword) &&
88
+ !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
89
+ return false
90
+ end
91
+ end
92
+ end
93
+ # It didn't early-return false:
94
+ true
95
+ end
96
+
82
97
  def unwrap_value(value)
83
98
  case value
84
99
  when Array
@@ -129,8 +144,11 @@ module GraphQL
129
144
  self[#{method_name.inspect}]
130
145
  end
131
146
  RUBY
147
+ argument_defn
132
148
  end
133
149
 
150
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
151
+
134
152
  def to_graphql
135
153
  type_defn = GraphQL::InputObjectType.new
136
154
  type_defn.name = graphql_name
@@ -138,8 +156,8 @@ module GraphQL
138
156
  type_defn.metadata[:type_class] = self
139
157
  type_defn.mutation = mutation
140
158
  type_defn.ast_node = ast_node
141
- arguments.each do |name, arg|
142
- type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
159
+ all_argument_definitions.each do |arg|
160
+ type_defn.arguments[arg.graphql_definition(silence_deprecation_warning: true).name] = arg.graphql_definition(silence_deprecation_warning: true) # rubocop:disable Development/ContextIsPassedCop -- legacy-related
143
161
  end
144
162
  # Make a reference to a classic-style Arguments class
145
163
  self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
@@ -155,9 +173,8 @@ module GraphQL
155
173
  # @api private
156
174
  INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
157
175
 
158
- def validate_non_null_input(input, ctx)
176
+ def validate_non_null_input(input, ctx, max_errors: nil)
159
177
  result = GraphQL::Query::InputValidationResult.new
160
-
161
178
  warden = ctx.warden
162
179
 
163
180
  if input.is_a?(Array)
@@ -172,7 +189,7 @@ module GraphQL
172
189
  end
173
190
 
174
191
  # Inject missing required arguments
175
- missing_required_inputs = self.arguments.reduce({}) do |m, (argument_name, argument)|
192
+ missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
176
193
  if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
177
194
  m[argument_name] = nil
178
195
  end
@@ -223,7 +240,7 @@ module GraphQL
223
240
 
224
241
  result = {}
225
242
 
226
- arguments.each do |input_key, input_field_defn|
243
+ arguments(ctx).each do |input_key, input_field_defn|
227
244
  input_value = value[input_key]
228
245
  if value.key?(input_key)
229
246
  result[input_key] = if input_value.nil?
@@ -16,6 +16,7 @@ module GraphQL
16
16
  include GraphQL::Schema::Member::HasAstNode
17
17
  include GraphQL::Schema::Member::HasUnresolvedTypeError
18
18
  include GraphQL::Schema::Member::HasDirectives
19
+ include GraphQL::Schema::Member::HasInterfaces
19
20
 
20
21
  # Methods defined in this block will be:
21
22
  # - Added as class methods to this interface
@@ -57,9 +58,10 @@ module GraphQL
57
58
  child_class.extend(Schema::Interface::DefinitionMethods)
58
59
 
59
60
  child_class.type_membership_class(self.type_membership_class)
60
- child_class.own_interfaces << self
61
- child_class.interfaces.reverse_each do |interface_defn|
62
- child_class.extend(interface_defn::DefinitionMethods)
61
+ child_class.ancestors.reverse_each do |ancestor|
62
+ if ancestor.const_defined?(:DefinitionMethods)
63
+ child_class.extend(ancestor::DefinitionMethods)
64
+ end
63
65
  end
64
66
 
65
67
  # Use an instance variable to tell whether it's been included previously or not;
@@ -73,16 +75,13 @@ module GraphQL
73
75
  end
74
76
  child_class.introspection(introspection)
75
77
  child_class.description(description)
76
- if overridden_graphql_name
77
- child_class.graphql_name(overridden_graphql_name)
78
- end
79
78
  # If interfaces are mixed into each other, only define this class once
80
79
  if !child_class.const_defined?(:UnresolvedTypeError, false)
81
80
  add_unresolved_type_error(child_class)
82
81
  end
83
82
  elsif child_class < GraphQL::Schema::Object
84
83
  # This is being included into an object type, make sure it's using `implements(...)`
85
- backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
84
+ backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
86
85
  if !backtrace_line
87
86
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
88
87
  end
@@ -101,6 +100,8 @@ module GraphQL
101
100
  end
102
101
  end
103
102
 
103
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
104
+
104
105
  def to_graphql
105
106
  type_defn = GraphQL::InterfaceType.new
106
107
  type_defn.name = graphql_name
@@ -108,9 +109,9 @@ module GraphQL
108
109
  type_defn.orphan_types = orphan_types
109
110
  type_defn.type_membership_class = self.type_membership_class
110
111
  type_defn.ast_node = ast_node
111
- fields.each do |field_name, field_inst|
112
- field_defn = field_inst.graphql_definition
113
- type_defn.fields[field_defn.name] = field_defn
112
+ fields.each do |field_name, field_inst| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
113
+ field_defn = field_inst.graphql_definition(silence_deprecation_warning: true)
114
+ type_defn.fields[field_defn.name] = field_defn # rubocop:disable Development/ContextIsPassedCop -- legacy-related
114
115
  end
115
116
  type_defn.metadata[:type_class] = self
116
117
  if respond_to?(:resolve_type)
@@ -122,16 +123,6 @@ module GraphQL
122
123
  def kind
123
124
  GraphQL::TypeKinds::INTERFACE
124
125
  end
125
-
126
- protected
127
-
128
- def own_interfaces
129
- @own_interfaces ||= []
130
- end
131
-
132
- def interfaces
133
- own_interfaces + (own_interfaces.map { |i| i.own_interfaces }).flatten
134
- end
135
126
  end
136
127
 
137
128
  # Extend this _after_ `DefinitionMethods` is defined, so it will be used
@@ -107,7 +107,7 @@ module GraphQL
107
107
  dup_type_class(const)
108
108
  else
109
109
  # Use `.to_graphql` to get a freshly-made version, not shared between schemas
110
- const.to_graphql
110
+ const.deprecated_to_graphql
111
111
  end
112
112
  rescue NameError
113
113
  # Dup the built-in so that the cached fields aren't shared
@@ -8,8 +8,10 @@ module GraphQL
8
8
  class List < GraphQL::Schema::Wrapper
9
9
  include Schema::Member::ValidatesInput
10
10
 
11
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
12
+
11
13
  def to_graphql
12
- @of_type.graphql_definition.to_list_type
14
+ @of_type.graphql_definition(silence_deprecation_warning: true).to_list_type
13
15
  end
14
16
 
15
17
  # @return [GraphQL::TypeKinds::LIST]
@@ -49,15 +51,24 @@ module GraphQL
49
51
  end
50
52
  end
51
53
 
52
- def validate_non_null_input(value, ctx)
54
+ def validate_non_null_input(value, ctx, max_errors: nil)
53
55
  result = GraphQL::Query::InputValidationResult.new
54
56
  ensure_array(value).each_with_index do |item, index|
55
57
  item_result = of_type.validate_input(item, ctx)
56
- if !item_result.valid?
58
+ unless item_result.valid?
59
+ if max_errors
60
+ if max_errors == 0
61
+ add_max_errros_reached_message(result)
62
+ break
63
+ end
64
+
65
+ max_errors -= 1
66
+ end
67
+
57
68
  result.merge_result!(index, item_result)
58
69
  end
59
70
  end
60
- result
71
+ result.valid? ? nil : result
61
72
  end
62
73
 
63
74
  private
@@ -70,6 +81,12 @@ module GraphQL
70
81
  [value]
71
82
  end
72
83
  end
84
+
85
+ def add_max_errros_reached_message(result)
86
+ message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
87
+ item_result = GraphQL::Query::InputValidationResult.from_problem(message)
88
+ result.merge_result!(nil, item_result)
89
+ end
73
90
  end
74
91
  end
75
92
  end
@@ -34,6 +34,7 @@ module GraphQL
34
34
  Class.new(GraphQL::Schema) do
35
35
  orphan_types(types.values)
36
36
  directives(directives)
37
+ description(schema["description"])
37
38
 
38
39
  def self.resolve_type(*)
39
40
  raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
@@ -141,6 +142,7 @@ module GraphQL
141
142
  Class.new(GraphQL::Schema::Scalar) do
142
143
  graphql_name(type["name"])
143
144
  description(type["description"])
145
+ specified_by_url(type["specifiedByUrl"])
144
146
  end
145
147
  end
146
148
  when "UNION"
@@ -160,6 +162,7 @@ module GraphQL
160
162
  graphql_name(directive["name"])
161
163
  description(directive["description"])
162
164
  locations(*directive["locations"].map(&:to_sym))
165
+ repeatable(directive["isRepeatable"])
163
166
  loader.build_arguments(self, directive["args"], type_resolver)
164
167
  end
165
168
  end
@@ -85,8 +85,15 @@ module GraphQL
85
85
  define_method(name) do |*args|
86
86
  if args.any?
87
87
  instance_variable_set(ivar_name, args)
88
+ else
89
+ if (v = instance_variable_get(ivar_name))
90
+ v
91
+ elsif (ancestor = ancestors.find { |i| i.respond_to?(name) && i != self })
92
+ ancestor.public_send(name)
93
+ else
94
+ nil
95
+ end
88
96
  end
89
- instance_variable_get(ivar_name) || ((int = interfaces.first { |i| i.respond_to?()}) && int.public_send(name))
90
97
  end
91
98
  end
92
99
  end
@@ -116,8 +123,13 @@ module GraphQL
116
123
  end
117
124
 
118
125
  module ToGraphQLExtension
119
- def to_graphql
120
- defn = super
126
+ def to_graphql(*args, **kwargs)
127
+
128
+ defn = if args.empty? && kwargs.empty?
129
+ super()
130
+ else
131
+ super
132
+ end
121
133
  accepts_definition_methods.each do |method_name|
122
134
  value = public_send(method_name)
123
135
  if !value.nil?
@@ -108,7 +108,7 @@ module GraphQL
108
108
  @default_graphql_name ||= begin
109
109
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
110
110
 
111
- name.split("::").last.sub(/Type\Z/, "")
111
+ -name.split("::").last.sub(/Type\Z/, "")
112
112
  end
113
113
  end
114
114
 
@@ -4,10 +4,6 @@ module GraphQL
4
4
  class Member
5
5
  # @api private
6
6
  module BuildType
7
- if !String.method_defined?(:match?)
8
- using GraphQL::StringMatchBackport
9
- end
10
-
11
7
  LIST_TYPE_ERROR = "Use an array of [T] or [T, null: true] for list types; other arrays are not supported"
12
8
 
13
9
  module_function
@@ -11,8 +11,24 @@ module GraphQL
11
11
  # A cached result of {.to_graphql}.
12
12
  # It's cached here so that user-overridden {.to_graphql} implementations
13
13
  # are also cached
14
- def graphql_definition
15
- @graphql_definition ||= to_graphql
14
+ def graphql_definition(silence_deprecation_warning: false)
15
+ @graphql_definition ||= begin
16
+ unless silence_deprecation_warning
17
+ message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Remove `.graphql_definition` to use a class-based definition instead."
18
+ caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
19
+ GraphQL::Deprecation.warn(message + caller_message)
20
+ end
21
+ deprecated_to_graphql
22
+ end
23
+ end
24
+
25
+ def deprecated_to_graphql
26
+ case method(:to_graphql).arity
27
+ when 0
28
+ to_graphql
29
+ else
30
+ to_graphql(silence_deprecation_warning: true)
31
+ end
16
32
  end
17
33
 
18
34
  # This is for a common interface with .define-based types
@@ -25,6 +41,17 @@ module GraphQL
25
41
  super
26
42
  @graphql_definition = nil
27
43
  end
44
+
45
+ module DeprecatedToGraphQL
46
+ def to_graphql(silence_deprecation_warning: false)
47
+ unless silence_deprecation_warning
48
+ message = "Legacy `.to_graphql` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Remove `.to_graphql` to use a class-based definition instead."
49
+ caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
50
+ GraphQL::Deprecation.warn(message + caller_message)
51
+ end
52
+ super()
53
+ end
54
+ end
28
55
  end
29
56
  end
30
57
  end
@@ -78,30 +78,72 @@ module GraphQL
78
78
  # @return [GraphQL::Schema::Argument]
79
79
  def add_argument(arg_defn)
80
80
  @own_arguments ||= {}
81
- own_arguments[arg_defn.name] = arg_defn
81
+ prev_defn = own_arguments[arg_defn.name]
82
+ case prev_defn
83
+ when nil
84
+ own_arguments[arg_defn.name] = arg_defn
85
+ when Array
86
+ prev_defn << arg_defn
87
+ when GraphQL::Schema::Argument
88
+ own_arguments[arg_defn.name] = [prev_defn, arg_defn]
89
+ else
90
+ raise "Invariant: unexpected `@own_arguments[#{arg_defn.name.inspect}]`: #{prev_defn.inspect}"
91
+ end
82
92
  arg_defn
83
93
  end
84
94
 
85
95
  # @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
86
- def arguments
87
- inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments : nil)
96
+ def arguments(context = GraphQL::Query::NullContext)
97
+ inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments(context) : nil)
88
98
  # Local definitions override inherited ones
99
+ if own_arguments.any?
100
+ own_arguments_that_apply = {}
101
+ own_arguments.each do |name, args_entry|
102
+ if (visible_defn = Warden.visible_entry?(:visible_argument?, args_entry, context))
103
+ own_arguments_that_apply[visible_defn.graphql_name] = visible_defn
104
+ end
105
+ end
106
+ end
107
+
89
108
  if inherited_arguments
90
- inherited_arguments.merge(own_arguments)
109
+ if own_arguments_that_apply
110
+ inherited_arguments.merge(own_arguments_that_apply)
111
+ else
112
+ inherited_arguments
113
+ end
91
114
  else
92
- own_arguments
115
+ # might be nil if there are actually no arguments
116
+ own_arguments_that_apply || own_arguments
93
117
  end
94
118
  end
95
119
 
96
- # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
97
- def get_argument(argument_name)
98
- a = own_arguments[argument_name]
120
+ def all_argument_definitions
121
+ if self.is_a?(Class)
122
+ all_defns = {}
123
+ ancestors.reverse_each do |ancestor|
124
+ if ancestor.respond_to?(:own_arguments)
125
+ all_defns.merge!(ancestor.own_arguments)
126
+ end
127
+ end
128
+ else
129
+ all_defns = own_arguments
130
+ end
131
+ all_defns = all_defns.values
132
+ all_defns.flatten!
133
+ all_defns
134
+ end
99
135
 
100
- if a || !self.is_a?(Class)
101
- a
136
+ # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
137
+ def get_argument(argument_name, context = GraphQL::Query::NullContext)
138
+ warden = Warden.from_context(context)
139
+ if !self.is_a?(Class)
140
+ a = own_arguments[argument_name]
141
+ a && Warden.visible_entry?(:visible_argument?, a, context, warden)
102
142
  else
103
143
  for ancestor in ancestors
104
- if ancestor.respond_to?(:own_arguments) && a = ancestor.own_arguments[argument_name]
144
+ if ancestor.respond_to?(:own_arguments) &&
145
+ (a = ancestor.own_arguments[argument_name]) &&
146
+ (a = Warden.visible_entry?(:visible_argument?, a, context, warden))
105
147
  return a
106
148
  end
107
149
  end
@@ -125,7 +167,7 @@ module GraphQL
125
167
  # @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
126
168
  def coerce_arguments(parent_object, values, context, &block)
127
169
  # Cache this hash to avoid re-merging it
128
- arg_defns = self.arguments
170
+ arg_defns = context.warden.arguments(self)
129
171
  total_args_count = arg_defns.size
130
172
 
131
173
  finished_args = nil
@@ -139,7 +181,7 @@ module GraphQL
139
181
  argument_values = {}
140
182
  resolved_args_count = 0
141
183
  raised_error = false
142
- arg_defns.each do |arg_name, arg_defn|
184
+ arg_defns.each do |arg_defn|
143
185
  context.dataloader.append_job do
144
186
  begin
145
187
  arg_defn.coerce_into_values(parent_object, values, context, argument_values)
@@ -191,7 +233,7 @@ module GraphQL
191
233
  def arguments_statically_coercible?
192
234
  return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
193
235
 
194
- @arguments_statically_coercible = arguments.each_value.all?(&:statically_coercible?)
236
+ @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
195
237
  end
196
238
 
197
239
  module ArgumentClassAccessor
@@ -7,7 +7,7 @@ module GraphQL
7
7
  # @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
8
8
  def deprecation_reason
9
9
  dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
10
- dir && dir.arguments[:reason]
10
+ dir && dir.arguments[:reason] # rubocop:disable Development/ContextIsPassedCop -- definition-related
11
11
  end
12
12
 
13
13
  # Set the deprecation reason for this member, or remove it by assigning `nil`