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
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ module HasSingleInputArgument
6
+ def resolve_with_support(**inputs)
7
+ if inputs[:input].is_a?(InputObject)
8
+ input = inputs[:input].to_kwargs
9
+ else
10
+ input = inputs[:input]
11
+ end
12
+
13
+ new_extras = field ? field.extras : []
14
+ all_extras = self.class.extras + new_extras
15
+
16
+ # Transfer these from the top-level hash to the
17
+ # shortcutted `input:` object
18
+ all_extras.each do |ext|
19
+ # It's possible that the `extra` was not passed along by this point,
20
+ # don't re-add it if it wasn't given here.
21
+ if inputs.key?(ext)
22
+ input[ext] = inputs[ext]
23
+ end
24
+ end
25
+
26
+ if input
27
+ # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
28
+ input_kwargs = input.to_h
29
+ else
30
+ # Relay Classic Mutations with no `argument`s
31
+ # don't require `input:`
32
+ input_kwargs = {}
33
+ end
34
+
35
+ if input_kwargs.any?
36
+ super(**input_kwargs)
37
+ else
38
+ super()
39
+ end
40
+ end
41
+
42
+ def self.included(base)
43
+ base.extend(ClassMethods)
44
+ end
45
+
46
+ module ClassMethods
47
+ def dummy
48
+ @dummy ||= begin
49
+ d = Class.new(GraphQL::Schema::Resolver)
50
+ d.graphql_name "#{self.graphql_name}DummyResolver"
51
+ d.argument_class(self.argument_class)
52
+ # TODO make this lazier?
53
+ d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
54
+ d
55
+ end
56
+ end
57
+
58
+ def field_arguments(context = GraphQL::Query::NullContext.instance)
59
+ dummy.arguments(context)
60
+ end
61
+
62
+ def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
63
+ dummy.get_argument(name, context)
64
+ end
65
+
66
+ def own_field_arguments
67
+ dummy.own_arguments
68
+ end
69
+
70
+ def any_field_arguments?
71
+ dummy.any_arguments?
72
+ end
73
+
74
+ def all_field_argument_definitions
75
+ dummy.all_argument_definitions
76
+ end
77
+
78
+ # Also apply this argument to the input type:
79
+ def argument(*args, own_argument: false, **kwargs, &block)
80
+ it = input_type # make sure any inherited arguments are already added to it
81
+ arg = super(*args, **kwargs, &block)
82
+
83
+ # This definition might be overriding something inherited;
84
+ # if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
85
+ prev_args = it.own_arguments[arg.graphql_name]
86
+ case prev_args
87
+ when GraphQL::Schema::Argument
88
+ if prev_args.owner != self
89
+ it.own_arguments.delete(arg.graphql_name)
90
+ end
91
+ when Array
92
+ prev_args.reject! { |a| a.owner != self }
93
+ if prev_args.empty?
94
+ it.own_arguments.delete(arg.graphql_name)
95
+ end
96
+ end
97
+
98
+ it.add_argument(arg)
99
+ arg
100
+ end
101
+
102
+ # The base class for generated input object types
103
+ # @param new_class [Class] The base class to use for generating input object definitions
104
+ # @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
105
+ def input_object_class(new_class = nil)
106
+ if new_class
107
+ @input_object_class = new_class
108
+ end
109
+ @input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
110
+ end
111
+
112
+ # @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
113
+ # @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
114
+ def input_type(new_input_type = nil)
115
+ if new_input_type
116
+ @input_type = new_input_type
117
+ end
118
+ @input_type ||= generate_input_type
119
+ end
120
+
121
+ private
122
+
123
+ # Generate the input type for the `input:` argument
124
+ # To customize how input objects are generated, override this method
125
+ # @return [Class] a subclass of {.input_object_class}
126
+ def generate_input_type
127
+ mutation_args = all_argument_definitions
128
+ mutation_class = self
129
+ Class.new(input_object_class) do
130
+ class << self
131
+ def default_graphql_name
132
+ "#{self.mutation.graphql_name}Input"
133
+ end
134
+
135
+ def description(new_desc = nil)
136
+ super || "Autogenerated input type of #{self.mutation.graphql_name}"
137
+ end
138
+ end
139
+ mutation(mutation_class)
140
+ # these might be inherited:
141
+ mutation_args.each do |arg|
142
+ add_argument(arg)
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def authorize_arguments(args, values)
151
+ # remove the `input` wrapper to match values
152
+ input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
153
+ input_args = context.types.arguments(input_type)
154
+ super(input_args, values)
155
+ end
156
+ end
157
+ end
158
+ end
@@ -23,7 +23,8 @@ module GraphQL
23
23
  @ruby_style_hash = ruby_kwargs
24
24
  @arguments = arguments
25
25
  # Apply prepares, not great to have it duplicated here.
26
- self.class.arguments(context).each_value do |arg_defn|
26
+ arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
27
+ arg_defns.each do |arg_defn|
27
28
  ruby_kwargs_key = arg_defn.keyword
28
29
  if @ruby_style_hash.key?(ruby_kwargs_key)
29
30
  # Weirdly, procs are applied during coercion, but not methods.
@@ -58,7 +59,7 @@ module GraphQL
58
59
  def self.authorized?(obj, value, ctx)
59
60
  # Authorize each argument (but this doesn't apply if `prepare` is implemented):
60
61
  if value.respond_to?(:key?)
61
- arguments(ctx).each do |_name, input_obj_arg|
62
+ ctx.types.arguments(self).each do |input_obj_arg|
62
63
  if value.key?(input_obj_arg.keyword) &&
63
64
  !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
64
65
  return false
@@ -69,6 +70,19 @@ module GraphQL
69
70
  true
70
71
  end
71
72
 
73
+ def self.one_of
74
+ if !one_of?
75
+ if all_argument_definitions.any? { |arg| arg.type.non_null? }
76
+ raise ArgumentError, "`one_of` may not be used with required arguments -- add `required: false` to argument definitions to use `one_of`"
77
+ end
78
+ directive(GraphQL::Schema::Directive::OneOf)
79
+ end
80
+ end
81
+
82
+ def self.one_of?
83
+ false # Re-defined when `OneOf` is added
84
+ end
85
+
72
86
  def unwrap_value(value)
73
87
  case value
74
88
  when Array
@@ -109,12 +123,21 @@ module GraphQL
109
123
  class << self
110
124
  def argument(*args, **kwargs, &block)
111
125
  argument_defn = super(*args, **kwargs, &block)
126
+ if one_of?
127
+ if argument_defn.type.non_null?
128
+ raise ArgumentError, "Argument '#{argument_defn.path}' must be nullable because it is part of a OneOf type, add `required: false`."
129
+ end
130
+ if argument_defn.default_value?
131
+ raise ArgumentError, "Argument '#{argument_defn.path}' cannot have a default value because it is part of a OneOf type, remove `default_value: ...`."
132
+ end
133
+ end
112
134
  # Add a method access
113
135
  method_name = argument_defn.keyword
114
136
  class_eval <<-RUBY, __FILE__, __LINE__
115
137
  def #{method_name}
116
138
  self[#{method_name.inspect}]
117
139
  end
140
+ alias_method :#{method_name}, :#{method_name}
118
141
  RUBY
119
142
  argument_defn
120
143
  end
@@ -124,10 +147,10 @@ module GraphQL
124
147
  end
125
148
 
126
149
  # @api private
127
- INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
150
+ INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
128
151
 
129
152
  def validate_non_null_input(input, ctx, max_errors: nil)
130
- warden = ctx.warden
153
+ types = ctx.types
131
154
 
132
155
  if input.is_a?(Array)
133
156
  return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
@@ -139,9 +162,9 @@ module GraphQL
139
162
  end
140
163
 
141
164
  # Inject missing required arguments
142
- missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
143
- if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
144
- m[argument_name] = nil
165
+ missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
166
+ if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
167
+ m[argument.graphql_name] = nil
145
168
  end
146
169
 
147
170
  m
@@ -150,7 +173,7 @@ module GraphQL
150
173
  result = nil
151
174
  [input, missing_required_inputs].each do |args_to_validate|
152
175
  args_to_validate.each do |argument_name, value|
153
- argument = warden.get_argument(self, argument_name)
176
+ argument = types.argument(self, argument_name)
154
177
  # Items in the input that are unexpected
155
178
  if argument.nil?
156
179
  result ||= Query::InputValidationResult.new
@@ -166,6 +189,20 @@ module GraphQL
166
189
  end
167
190
  end
168
191
 
192
+ if one_of?
193
+ if input.size == 1
194
+ input.each do |name, value|
195
+ if value.nil?
196
+ result ||= Query::InputValidationResult.new
197
+ result.add_problem("'#{graphql_name}' requires exactly one argument, but '#{name}' was `null`.")
198
+ end
199
+ end
200
+ else
201
+ result ||= Query::InputValidationResult.new
202
+ result.add_problem("'#{graphql_name}' requires exactly one argument, but #{input.size} were provided.")
203
+ end
204
+ end
205
+
169
206
  result
170
207
  end
171
208
 
@@ -176,12 +213,11 @@ module GraphQL
176
213
 
177
214
  arguments = coerce_arguments(nil, value, ctx)
178
215
 
179
- ctx.schema.after_lazy(arguments) do |resolved_arguments|
216
+ ctx.query.after_lazy(arguments) do |resolved_arguments|
180
217
  if resolved_arguments.is_a?(GraphQL::Error)
181
218
  raise resolved_arguments
182
219
  else
183
- input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
184
- input_obj_instance.prepare
220
+ self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
185
221
  end
186
222
  end
187
223
  end
@@ -20,6 +20,15 @@ module GraphQL
20
20
  # - Added as class methods to this interface
21
21
  # - Added as class methods to all child interfaces
22
22
  def definition_methods(&block)
23
+ # Use an instance variable to tell whether it's been included previously or not;
24
+ # You can't use constant detection because constants are brought into scope
25
+ # by `include`, which has already happened at this point.
26
+ if !defined?(@_definition_methods)
27
+ defn_methods_module = Module.new
28
+ @_definition_methods = defn_methods_module
29
+ const_set(:DefinitionMethods, defn_methods_module)
30
+ extend(self::DefinitionMethods)
31
+ end
23
32
  self::DefinitionMethods.module_eval(&block)
24
33
  end
25
34
 
@@ -28,16 +37,6 @@ module GraphQL
28
37
  true
29
38
  end
30
39
 
31
- # The interface is accessible if any of its possible types are accessible
32
- def accessible?(context)
33
- context.schema.possible_types(self, context).each do |type|
34
- if context.schema.accessible?(type, context)
35
- return true
36
- end
37
- end
38
- false
39
- end
40
-
41
40
  def type_membership_class(membership_class = nil)
42
41
  if membership_class
43
42
  @type_membership_class = membership_class
@@ -57,20 +56,11 @@ module GraphQL
57
56
 
58
57
  child_class.type_membership_class(self.type_membership_class)
59
58
  child_class.ancestors.reverse_each do |ancestor|
60
- if ancestor.const_defined?(:DefinitionMethods)
59
+ if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
61
60
  child_class.extend(ancestor::DefinitionMethods)
62
61
  end
63
62
  end
64
63
 
65
- # Use an instance variable to tell whether it's been included previously or not;
66
- # You can't use constant detection because constants are brought into scope
67
- # by `include`, which has already happened at this point.
68
- if !child_class.instance_variable_defined?(:@_definition_methods)
69
- defn_methods_module = Module.new
70
- child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
71
- child_class.const_set(:DefinitionMethods, defn_methods_module)
72
- child_class.extend(child_class::DefinitionMethods)
73
- end
74
64
  child_class.introspection(introspection)
75
65
  child_class.description(description)
76
66
  # If interfaces are mixed into each other, only define this class once
@@ -79,7 +69,11 @@ module GraphQL
79
69
  end
80
70
  elsif child_class < GraphQL::Schema::Object
81
71
  # This is being included into an object type, make sure it's using `implements(...)`
82
- backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
72
+ backtrace_line = caller_locations(0, 10).find do |location|
73
+ location.base_label == "implements" &&
74
+ location.path.end_with?("schema/member/has_interfaces.rb")
75
+ end
76
+
83
77
  if !backtrace_line
84
78
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
85
79
  end
@@ -25,10 +25,10 @@ module GraphQL
25
25
  load_constant(:DirectiveLocationEnum)
26
26
  ]
27
27
  @types = {}
28
- @possible_types = {}
28
+ @possible_types = {}.tap(&:compare_by_identity)
29
29
  type_defns.each do |t|
30
30
  @types[t.graphql_name] = t
31
- @possible_types[t.graphql_name] = [t]
31
+ @possible_types[t] = [t]
32
32
  end
33
33
  @entry_point_fields =
34
34
  if schema.disable_introspection_entry_points?
@@ -39,7 +39,9 @@ module GraphQL
39
39
  entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
40
40
  entry_point_fields
41
41
  end
42
+ @entry_point_fields.each { |k, v| v.dynamic_introspection = true }
42
43
  @dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
44
+ @dynamic_fields.each { |k, v| v.dynamic_introspection = true }
43
45
  end
44
46
 
45
47
  def entry_points
@@ -67,7 +69,7 @@ module GraphQL
67
69
  def resolve_late_bindings
68
70
  @types.each do |name, t|
69
71
  if t.kind.fields?
70
- t.fields.each do |_name, field_defn|
72
+ t.all_field_definitions.each do |field_defn|
71
73
  field_defn.type = resolve_late_binding(field_defn.type)
72
74
  end
73
75
  end
@@ -111,19 +113,7 @@ module GraphQL
111
113
 
112
114
  def get_fields_from_class(class_sym:)
113
115
  object_type_defn = load_constant(class_sym)
114
-
115
- if object_type_defn.is_a?(Module)
116
- object_type_defn.fields
117
- else
118
- extracted_field_defns = {}
119
- object_class = object_type_defn.metadata[:type_class]
120
- object_type_defn.all_fields.each do |field_defn|
121
- inner_resolve = field_defn.resolve_proc
122
- resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
123
- extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
124
- end
125
- extracted_field_defns
126
- end
116
+ object_type_defn.fields
127
117
  end
128
118
 
129
119
  # This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
@@ -155,7 +145,7 @@ module GraphQL
155
145
  if obj.is_a?(GraphQL::Schema::Object)
156
146
  obj = obj.object
157
147
  end
158
- wrapped_object = @object_class.authorized_new(obj, query_ctx)
148
+ wrapped_object = @object_class.wrap(obj, query_ctx)
159
149
  @inner_resolve.call(wrapped_object, args, ctx)
160
150
  end
161
151
  end
@@ -9,6 +9,8 @@ module GraphQL
9
9
  alias :graphql_name :name
10
10
  def initialize(local_name)
11
11
  @name = local_name
12
+ @to_non_null_type = nil
13
+ @to_list_type = nil
12
14
  end
13
15
 
14
16
  def unwrap
@@ -23,10 +25,18 @@ module GraphQL
23
25
  @to_list_type ||= GraphQL::Schema::List.new(self)
24
26
  end
25
27
 
28
+ def to_type_signature
29
+ name
30
+ end
31
+
26
32
  def inspect
27
33
  "#<LateBoundType @name=#{name}>"
28
34
  end
29
35
 
36
+ def non_null?
37
+ false
38
+ end
39
+
30
40
  alias :to_s :inspect
31
41
  end
32
42
  end
@@ -52,7 +52,7 @@ module GraphQL
52
52
  unless item_result.valid?
53
53
  if max_errors
54
54
  if max_errors == 0
55
- add_max_errros_reached_message(result)
55
+ add_max_errors_reached_message(result)
56
56
  break
57
57
  end
58
58
 
@@ -76,7 +76,7 @@ module GraphQL
76
76
  end
77
77
  end
78
78
 
79
- def add_max_errros_reached_message(result)
79
+ def add_max_errors_reached_message(result)
80
80
  message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
81
81
  item_result = GraphQL::Query::InputValidationResult.from_problem(message)
82
82
  result.merge_result!(nil, item_result)
@@ -32,7 +32,8 @@ module GraphQL
32
32
  end
33
33
 
34
34
  Class.new(GraphQL::Schema) do
35
- orphan_types(types.values)
35
+ add_type_and_traverse(types.values, root: false)
36
+ orphan_types(types.values.select { |t| t.kind.object? })
36
37
  directives(directives)
37
38
  description(schema["description"])
38
39
 
@@ -176,7 +177,6 @@ module GraphQL
176
177
  while (of_type = unwrapped_field_hash["ofType"])
177
178
  unwrapped_field_hash = of_type
178
179
  end
179
- type_name = unwrapped_field_hash["name"]
180
180
 
181
181
  type_defn.field(
182
182
  field_hash["name"],
@@ -186,7 +186,6 @@ module GraphQL
186
186
  null: true,
187
187
  camelize: false,
188
188
  connection_extension: nil,
189
- connection: type_name.end_with?("Connection"),
190
189
  ) do
191
190
  if field_hash["args"].any?
192
191
  loader.build_arguments(self, field_hash["args"], type_resolver)
@@ -22,14 +22,10 @@ module GraphQL
22
22
  GraphQL::NameValidator.validate!(new_name)
23
23
  @graphql_name = new_name
24
24
  else
25
- overridden_graphql_name || default_graphql_name
25
+ @graphql_name ||= default_graphql_name
26
26
  end
27
27
  end
28
28
 
29
- def overridden_graphql_name
30
- defined?(@graphql_name) ? @graphql_name : nil
31
- end
32
-
33
29
  # Just a convenience method to point out that people should use graphql_name instead
34
30
  def name(new_name = nil)
35
31
  return super() if new_name.nil?
@@ -50,7 +46,7 @@ module GraphQL
50
46
  elsif defined?(@description)
51
47
  @description
52
48
  else
53
- nil
49
+ @description = nil
54
50
  end
55
51
  end
56
52
 
@@ -60,8 +56,12 @@ module GraphQL
60
56
  def inherited(child_class)
61
57
  child_class.introspection(introspection)
62
58
  child_class.description(description)
63
- if overridden_graphql_name
64
- child_class.graphql_name(overridden_graphql_name)
59
+ child_class.default_graphql_name = nil
60
+
61
+ if defined?(@graphql_name) && @graphql_name && (self.name.nil? || graphql_name != default_graphql_name)
62
+ child_class.graphql_name(graphql_name)
63
+ else
64
+ child_class.graphql_name = nil
65
65
  end
66
66
  super
67
67
  end
@@ -79,7 +79,7 @@ module GraphQL
79
79
  end
80
80
 
81
81
  def introspection?
82
- introspection
82
+ !!@introspection
83
83
  end
84
84
 
85
85
  # The mutation this type was derived from, if it was derived from a mutation
@@ -102,8 +102,8 @@ module GraphQL
102
102
  def default_graphql_name
103
103
  @default_graphql_name ||= begin
104
104
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
105
-
106
- name.split("::").last.sub(/Type\Z/, "")
105
+ g_name = -name.split("::").last
106
+ g_name.end_with?("Type") ? g_name.sub(/Type\Z/, "") : g_name
107
107
  end
108
108
  end
109
109
 
@@ -111,13 +111,17 @@ module GraphQL
111
111
  true
112
112
  end
113
113
 
114
- def accessible?(context)
114
+ def authorized?(object, context)
115
115
  true
116
116
  end
117
117
 
118
- def authorized?(object, context)
119
- true
118
+ def default_relay
119
+ false
120
120
  end
121
+
122
+ protected
123
+
124
+ attr_writer :default_graphql_name, :graphql_name
121
125
  end
122
126
  end
123
127
  end
@@ -109,7 +109,14 @@ module GraphQL
109
109
  to_type_name(something.name)
110
110
  end
111
111
  when String
112
- something.gsub(/\]\[\!/, "").split("::").last
112
+ if something.include?("]") ||
113
+ something.include?("[") ||
114
+ something.include?("!") ||
115
+ something.include?("::")
116
+ something.gsub(/\]\[\!/, "").split("::").last
117
+ else
118
+ something
119
+ end
113
120
  when GraphQL::Schema::NonNull, GraphQL::Schema::List
114
121
  to_type_name(something.unwrap)
115
122
  else
@@ -120,9 +127,10 @@ module GraphQL
120
127
  def camelize(string)
121
128
  return string if string == '_'
122
129
  return string unless string.include?("_")
123
- camelized = string.split('_').map(&:capitalize).join
130
+ camelized = string.split('_').each(&:capitalize!).join
124
131
  camelized[0] = camelized[0].downcase
125
- if (match_data = string.match(/\A(_+)/))
132
+ if string.start_with?("_")
133
+ match_data = string.match(/\A(_+)/)
126
134
  camelized = "#{match_data[0]}#{camelized}"
127
135
  end
128
136
  camelized