graphql 1.11.6 → 1.13.19

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 (293) 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 +17 -7
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/loader_generator.rb +1 -0
  10. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_generator.rb +6 -30
  13. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  14. data/lib/generators/graphql/object_generator.rb +12 -38
  15. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  16. data/lib/generators/graphql/relay.rb +63 -0
  17. data/lib/generators/graphql/relay_generator.rb +21 -0
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  20. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  21. data/lib/generators/graphql/templates/enum.erb +5 -1
  22. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  23. data/lib/generators/graphql/templates/input.erb +9 -0
  24. data/lib/generators/graphql/templates/interface.erb +4 -2
  25. data/lib/generators/graphql/templates/mutation.erb +1 -1
  26. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  27. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  28. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  29. data/lib/generators/graphql/templates/node_type.erb +9 -0
  30. data/lib/generators/graphql/templates/object.erb +5 -3
  31. data/lib/generators/graphql/templates/query_type.erb +1 -3
  32. data/lib/generators/graphql/templates/scalar.erb +3 -1
  33. data/lib/generators/graphql/templates/schema.erb +19 -34
  34. data/lib/generators/graphql/templates/union.erb +4 -2
  35. data/lib/generators/graphql/type_generator.rb +47 -10
  36. data/lib/generators/graphql/union_generator.rb +5 -5
  37. data/lib/graphql/analysis/analyze_query.rb +7 -0
  38. data/lib/graphql/analysis/ast/field_usage.rb +28 -1
  39. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  40. data/lib/graphql/analysis/ast/visitor.rb +14 -5
  41. data/lib/graphql/analysis/ast.rb +11 -2
  42. data/lib/graphql/argument.rb +1 -1
  43. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  44. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  45. data/lib/graphql/backtrace/table.rb +34 -3
  46. data/lib/graphql/backtrace/traced_error.rb +0 -1
  47. data/lib/graphql/backtrace/tracer.rb +40 -10
  48. data/lib/graphql/backtrace.rb +28 -19
  49. data/lib/graphql/backwards_compatibility.rb +2 -1
  50. data/lib/graphql/base_type.rb +6 -4
  51. data/lib/graphql/boolean_type.rb +1 -1
  52. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  53. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  54. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  55. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  56. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  57. data/lib/graphql/dataloader/request.rb +19 -0
  58. data/lib/graphql/dataloader/request_all.rb +19 -0
  59. data/lib/graphql/dataloader/source.rb +155 -0
  60. data/lib/graphql/dataloader.rb +308 -0
  61. data/lib/graphql/date_encoding_error.rb +16 -0
  62. data/lib/graphql/define/assign_global_id_field.rb +1 -1
  63. data/lib/graphql/define/instance_definable.rb +48 -3
  64. data/lib/graphql/define/type_definer.rb +5 -5
  65. data/lib/graphql/deprecated_dsl.rb +18 -5
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  68. data/lib/graphql/directive/include_directive.rb +1 -1
  69. data/lib/graphql/directive/skip_directive.rb +1 -1
  70. data/lib/graphql/directive.rb +1 -5
  71. data/lib/graphql/enum_type.rb +9 -3
  72. data/lib/graphql/execution/errors.rb +110 -7
  73. data/lib/graphql/execution/execute.rb +8 -1
  74. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  75. data/lib/graphql/execution/interpreter/arguments_cache.rb +49 -15
  76. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  77. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  78. data/lib/graphql/execution/interpreter/runtime.rb +670 -294
  79. data/lib/graphql/execution/interpreter.rb +16 -16
  80. data/lib/graphql/execution/lazy.rb +5 -1
  81. data/lib/graphql/execution/lookahead.rb +2 -2
  82. data/lib/graphql/execution/multiplex.rb +39 -23
  83. data/lib/graphql/field.rb +1 -1
  84. data/lib/graphql/float_type.rb +1 -1
  85. data/lib/graphql/function.rb +4 -0
  86. data/lib/graphql/id_type.rb +1 -1
  87. data/lib/graphql/input_object_type.rb +3 -1
  88. data/lib/graphql/int_type.rb +1 -1
  89. data/lib/graphql/integer_decoding_error.rb +17 -0
  90. data/lib/graphql/integer_encoding_error.rb +18 -2
  91. data/lib/graphql/interface_type.rb +4 -2
  92. data/lib/graphql/internal_representation/document.rb +2 -2
  93. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  94. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  95. data/lib/graphql/introspection/directive_type.rb +11 -5
  96. data/lib/graphql/introspection/entry_points.rb +2 -2
  97. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  98. data/lib/graphql/introspection/field_type.rb +3 -3
  99. data/lib/graphql/introspection/input_value_type.rb +10 -4
  100. data/lib/graphql/introspection/schema_type.rb +10 -5
  101. data/lib/graphql/introspection/type_type.rb +18 -12
  102. data/lib/graphql/introspection.rb +5 -2
  103. data/lib/graphql/invalid_null_error.rb +1 -1
  104. data/lib/graphql/language/block_string.rb +2 -6
  105. data/lib/graphql/language/cache.rb +37 -0
  106. data/lib/graphql/language/document_from_schema_definition.rb +60 -26
  107. data/lib/graphql/language/lexer.rb +50 -28
  108. data/lib/graphql/language/lexer.rl +2 -4
  109. data/lib/graphql/language/nodes.rb +14 -4
  110. data/lib/graphql/language/parser.rb +856 -825
  111. data/lib/graphql/language/parser.y +28 -11
  112. data/lib/graphql/language/printer.rb +10 -1
  113. data/lib/graphql/language/sanitized_printer.rb +5 -5
  114. data/lib/graphql/language/token.rb +0 -4
  115. data/lib/graphql/language.rb +1 -0
  116. data/lib/graphql/name_validator.rb +0 -4
  117. data/lib/graphql/object_type.rb +4 -4
  118. data/lib/graphql/pagination/active_record_relation_connection.rb +47 -3
  119. data/lib/graphql/pagination/connection.rb +19 -1
  120. data/lib/graphql/pagination/connections.rb +45 -30
  121. data/lib/graphql/pagination/relation_connection.rb +69 -28
  122. data/lib/graphql/parse_error.rb +0 -1
  123. data/lib/graphql/query/arguments.rb +2 -2
  124. data/lib/graphql/query/arguments_cache.rb +1 -2
  125. data/lib/graphql/query/context.rb +22 -4
  126. data/lib/graphql/query/executor.rb +0 -1
  127. data/lib/graphql/query/input_validation_result.rb +9 -0
  128. data/lib/graphql/query/literal_input.rb +1 -1
  129. data/lib/graphql/query/null_context.rb +21 -9
  130. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  131. data/lib/graphql/query/serial_execution.rb +1 -0
  132. data/lib/graphql/query/validation_pipeline.rb +3 -4
  133. data/lib/graphql/query/variable_validation_error.rb +3 -3
  134. data/lib/graphql/query/variables.rb +35 -4
  135. data/lib/graphql/query.rb +20 -8
  136. data/lib/graphql/railtie.rb +9 -1
  137. data/lib/graphql/rake_task.rb +3 -0
  138. data/lib/graphql/relay/array_connection.rb +2 -2
  139. data/lib/graphql/relay/base_connection.rb +7 -0
  140. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  141. data/lib/graphql/relay/connection_type.rb +16 -3
  142. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  143. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  144. data/lib/graphql/relay/mutation.rb +2 -1
  145. data/lib/graphql/relay/node.rb +3 -0
  146. data/lib/graphql/relay/page_info.rb +1 -1
  147. data/lib/graphql/relay/range_add.rb +14 -5
  148. data/lib/graphql/relay/type_extensions.rb +2 -0
  149. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  150. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  151. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  152. data/lib/graphql/rubocop.rb +4 -0
  153. data/lib/graphql/scalar_type.rb +3 -1
  154. data/lib/graphql/schema/addition.rb +247 -0
  155. data/lib/graphql/schema/argument.rb +177 -21
  156. data/lib/graphql/schema/build_from_definition.rb +150 -55
  157. data/lib/graphql/schema/default_type_error.rb +2 -0
  158. data/lib/graphql/schema/directive/feature.rb +1 -1
  159. data/lib/graphql/schema/directive/flagged.rb +57 -0
  160. data/lib/graphql/schema/directive/include.rb +1 -1
  161. data/lib/graphql/schema/directive/skip.rb +1 -1
  162. data/lib/graphql/schema/directive/transform.rb +14 -2
  163. data/lib/graphql/schema/directive.rb +103 -4
  164. data/lib/graphql/schema/enum.rb +72 -11
  165. data/lib/graphql/schema/enum_value.rb +18 -6
  166. data/lib/graphql/schema/field/connection_extension.rb +4 -2
  167. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  168. data/lib/graphql/schema/field.rb +332 -111
  169. data/lib/graphql/schema/field_extension.rb +89 -2
  170. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  171. data/lib/graphql/schema/finder.rb +5 -5
  172. data/lib/graphql/schema/input_object.rb +79 -55
  173. data/lib/graphql/schema/interface.rb +12 -20
  174. data/lib/graphql/schema/introspection_system.rb +1 -1
  175. data/lib/graphql/schema/list.rb +21 -4
  176. data/lib/graphql/schema/loader.rb +11 -0
  177. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  178. data/lib/graphql/schema/member/base_dsl_methods.rb +5 -16
  179. data/lib/graphql/schema/member/build_type.rb +4 -7
  180. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  181. data/lib/graphql/schema/member/has_arguments.rb +166 -74
  182. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  183. data/lib/graphql/schema/member/has_directives.rb +98 -0
  184. data/lib/graphql/schema/member/has_fields.rb +77 -22
  185. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  186. data/lib/graphql/schema/member/has_validators.rb +31 -0
  187. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  188. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  189. data/lib/graphql/schema/member/validates_input.rb +2 -2
  190. data/lib/graphql/schema/member.rb +5 -0
  191. data/lib/graphql/schema/middleware_chain.rb +1 -1
  192. data/lib/graphql/schema/non_null.rb +9 -3
  193. data/lib/graphql/schema/object.rb +40 -80
  194. data/lib/graphql/schema/printer.rb +16 -20
  195. data/lib/graphql/schema/relay_classic_mutation.rb +38 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -2
  197. data/lib/graphql/schema/resolver.rb +110 -64
  198. data/lib/graphql/schema/scalar.rb +18 -2
  199. data/lib/graphql/schema/subscription.rb +55 -9
  200. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  201. data/lib/graphql/schema/traversal.rb +1 -1
  202. data/lib/graphql/schema/type_expression.rb +1 -1
  203. data/lib/graphql/schema/type_membership.rb +18 -4
  204. data/lib/graphql/schema/union.rb +8 -1
  205. data/lib/graphql/schema/validation.rb +4 -2
  206. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  207. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  208. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  209. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  210. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  211. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  212. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  213. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  214. data/lib/graphql/schema/validator.rb +171 -0
  215. data/lib/graphql/schema/warden.rb +126 -53
  216. data/lib/graphql/schema.rb +262 -281
  217. data/lib/graphql/static_validation/all_rules.rb +2 -0
  218. data/lib/graphql/static_validation/base_visitor.rb +9 -6
  219. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  220. data/lib/graphql/static_validation/error.rb +3 -1
  221. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  222. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -2
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +6 -2
  224. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  225. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  226. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  227. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -47
  229. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  230. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  231. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  232. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  233. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  234. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  235. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  236. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  237. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  238. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  239. data/lib/graphql/static_validation/validation_context.rb +12 -2
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +41 -10
  242. data/lib/graphql/static_validation.rb +1 -0
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/string_type.rb +1 -1
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +39 -8
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +0 -3
  247. data/lib/graphql/subscriptions/event.rb +68 -32
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  249. data/lib/graphql/subscriptions/serialize.rb +34 -5
  250. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  251. data/lib/graphql/subscriptions.rb +34 -39
  252. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
  253. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  254. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  255. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +24 -12
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  260. data/lib/graphql/tracing.rb +2 -2
  261. data/lib/graphql/types/big_int.rb +5 -1
  262. data/lib/graphql/types/int.rb +10 -3
  263. data/lib/graphql/types/iso_8601_date.rb +13 -5
  264. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  265. data/lib/graphql/types/relay/base_connection.rb +6 -91
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  268. data/lib/graphql/types/relay/default_relay.rb +31 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  270. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  271. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  272. data/lib/graphql/types/relay/node.rb +2 -4
  273. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  274. data/lib/graphql/types/relay/node_field.rb +3 -22
  275. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -3
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +1 -1
  281. data/lib/graphql/union_type.rb +3 -1
  282. data/lib/graphql/upgrader/member.rb +1 -0
  283. data/lib/graphql/upgrader/schema.rb +1 -0
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +68 -37
  286. data/readme.md +3 -6
  287. metadata +83 -113
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/types/relay/base_field.rb +0 -22
  290. data/lib/graphql/types/relay/base_interface.rb +0 -29
  291. data/lib/graphql/types/relay/base_object.rb +0 -26
  292. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  293. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -19,6 +19,7 @@ module GraphQL
19
19
  # @return [String]
20
20
  def graphql_name(new_name = nil)
21
21
  if new_name
22
+ GraphQL::NameValidator.validate!(new_name)
22
23
  @graphql_name = new_name
23
24
  else
24
25
  overridden_graphql_name || default_graphql_name
@@ -107,32 +108,20 @@ module GraphQL
107
108
  @default_graphql_name ||= begin
108
109
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
109
110
 
110
- name.split("::").last.sub(/Type\Z/, "")
111
+ -name.split("::").last.sub(/Type\Z/, "")
111
112
  end
112
113
  end
113
114
 
114
115
  def visible?(context)
115
- if @mutation
116
- @mutation.visible?(context)
117
- else
118
- true
119
- end
116
+ true
120
117
  end
121
118
 
122
119
  def accessible?(context)
123
- if @mutation
124
- @mutation.accessible?(context)
125
- else
126
- true
127
- end
120
+ true
128
121
  end
129
122
 
130
123
  def authorized?(object, context)
131
- if @mutation
132
- @mutation.authorized?(object, context)
133
- else
134
- true
135
- end
124
+ true
136
125
  end
137
126
  end
138
127
  end
@@ -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
@@ -60,11 +56,11 @@ module GraphQL
60
56
  parse_type(type_expr.first, null: false)
61
57
  when 2
62
58
  inner_type, nullable_option = type_expr
63
- if nullable_option.keys != [:null] || nullable_option.values != [true]
59
+ if nullable_option.keys != [:null] || (nullable_option[:null] != true && nullable_option[:null] != false)
64
60
  raise ArgumentError, LIST_TYPE_ERROR
65
61
  end
66
62
  list_type = true
67
- parse_type(inner_type, null: true)
63
+ parse_type(inner_type, null: nullable_option[:null])
68
64
  else
69
65
  raise ArgumentError, LIST_TYPE_ERROR
70
66
  end
@@ -75,7 +71,7 @@ module GraphQL
75
71
  if type_expr.respond_to?(:graphql_definition)
76
72
  type_expr
77
73
  else
78
- # Eg `String` => GraphQL::STRING_TYPE
74
+ # Eg `String` => GraphQL::Types::String
79
75
  parse_type(type_expr.name, null: true)
80
76
  end
81
77
  when Proc
@@ -124,6 +120,7 @@ module GraphQL
124
120
  end
125
121
 
126
122
  def camelize(string)
123
+ return string if string == '_'
127
124
  return string unless string.include?("_")
128
125
  camelized = string.split('_').map(&:capitalize).join
129
126
  camelized[0] = camelized[0].downcase
@@ -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
@@ -37,6 +37,40 @@ module GraphQL
37
37
  end
38
38
  arg_defn = self.argument_class.new(*args, **kwargs, &block)
39
39
  add_argument(arg_defn)
40
+
41
+ if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
42
+ method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
43
+ "self."
44
+ elsif self < GraphQL::Schema::Resolver
45
+ ""
46
+ else
47
+ raise "Unexpected argument owner: #{self}"
48
+ end
49
+ if loads && arg_defn.type.list?
50
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
51
+ def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
52
+ argument = get_argument("#{arg_defn.graphql_name}")
53
+ (context || self.context).schema.after_lazy(values) do |values2|
54
+ GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
55
+ end
56
+ end
57
+ RUBY
58
+ elsif loads
59
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
60
+ def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
61
+ argument = get_argument("#{arg_defn.graphql_name}")
62
+ load_application_object(argument, value, context || self.context)
63
+ end
64
+ RUBY
65
+ else
66
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
67
+ def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
68
+ value
69
+ end
70
+ RUBY
71
+ end
72
+ end
73
+ arg_defn
40
74
  end
41
75
 
42
76
  # Register this argument with the class.
@@ -44,30 +78,72 @@ module GraphQL
44
78
  # @return [GraphQL::Schema::Argument]
45
79
  def add_argument(arg_defn)
46
80
  @own_arguments ||= {}
47
- 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
48
92
  arg_defn
49
93
  end
50
94
 
51
95
  # @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
52
- def arguments
53
- 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)
54
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
+
55
108
  if inherited_arguments
56
- 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
57
114
  else
58
- own_arguments
115
+ # might be nil if there are actually no arguments
116
+ own_arguments_that_apply || own_arguments
59
117
  end
60
118
  end
61
119
 
62
- # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
63
- def get_argument(argument_name)
64
- 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
65
135
 
66
- if a || !self.is_a?(Class)
67
- 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)
68
142
  else
69
143
  for ancestor in ancestors
70
- 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))
71
147
  return a
72
148
  end
73
149
  end
@@ -81,81 +157,83 @@ module GraphQL
81
157
  end
82
158
 
83
159
  # @api private
160
+ # If given a block, it will eventually yield the loaded args to the block.
161
+ #
162
+ # If no block is given, it will immediately dataload (but might return a Lazy).
163
+ #
84
164
  # @param values [Hash<String, Object>]
85
165
  # @param context [GraphQL::Query::Context]
86
- # @return [Hash<Symbol, Object>, Execution::Lazy<Hash>]
87
- def coerce_arguments(parent_object, values, context)
88
- argument_values = {}
89
- kwarg_arguments = {}
166
+ # @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
167
+ # @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
168
+ def coerce_arguments(parent_object, values, context, &block)
90
169
  # Cache this hash to avoid re-merging it
91
- arg_defns = self.arguments
92
-
93
- maybe_lazies = []
94
- arg_lazies = arg_defns.map do |arg_name, arg_defn|
95
- arg_key = arg_defn.keyword
96
- has_value = false
97
- default_used = false
98
- if values.key?(arg_name)
99
- has_value = true
100
- value = values[arg_name]
101
- elsif values.key?(arg_key)
102
- has_value = true
103
- value = values[arg_key]
104
- elsif arg_defn.default_value?
105
- has_value = true
106
- value = arg_defn.default_value
107
- default_used = true
108
- end
109
-
110
- if has_value
111
- loads = arg_defn.loads
112
- loaded_value = nil
113
- if loads && !arg_defn.from_resolver?
114
- loaded_value = if arg_defn.type.list?
115
- loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, context) }
116
- context.schema.after_any_lazies(loaded_values) { |result| result }
117
- else
118
- load_application_object(arg_defn, loads, value, context)
119
- end
120
- end
170
+ arg_defns = context.warden.arguments(self)
171
+ total_args_count = arg_defns.size
121
172
 
122
- coerced_value = if loaded_value
123
- loaded_value
124
- else
125
- context.schema.error_handler.with_error_handling(context) do
126
- arg_defn.type.coerce_input(value, context)
127
- end
173
+ finished_args = nil
174
+ prepare_finished_args = -> {
175
+ if total_args_count == 0
176
+ finished_args = GraphQL::Execution::Interpreter::Arguments::EMPTY
177
+ if block_given?
178
+ block.call(finished_args)
128
179
  end
180
+ else
181
+ argument_values = {}
182
+ resolved_args_count = 0
183
+ raised_error = false
184
+ arg_defns.each do |arg_defn|
185
+ context.dataloader.append_job do
186
+ begin
187
+ arg_defn.coerce_into_values(parent_object, values, context, argument_values)
188
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
189
+ raised_error = true
190
+ finished_args = err
191
+ if block_given?
192
+ block.call(finished_args)
193
+ end
194
+ end
129
195
 
130
- context.schema.after_lazy(coerced_value) do |coerced_value|
131
- prepared_value = context.schema.error_handler.with_error_handling(context) do
132
- arg_defn.prepare_value(parent_object, coerced_value, context: context)
196
+ resolved_args_count += 1
197
+ if resolved_args_count == total_args_count && !raised_error
198
+ finished_args = context.schema.after_any_lazies(argument_values.values) {
199
+ GraphQL::Execution::Interpreter::Arguments.new(
200
+ argument_values: argument_values,
201
+ )
202
+ }
203
+ if block_given?
204
+ block.call(finished_args)
205
+ end
206
+ end
133
207
  end
134
-
135
- kwarg_arguments[arg_key] = prepared_value
136
- # TODO code smell to access such a deeply-nested constant in a distant module
137
- argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
138
- value: prepared_value,
139
- definition: arg_defn,
140
- default_used: default_used,
141
- )
142
208
  end
143
209
  end
210
+ }
211
+
212
+ if block_given?
213
+ prepare_finished_args.call
214
+ nil
215
+ else
216
+ # This API returns eagerly, gotta run it now
217
+ context.dataloader.run_isolated(&prepare_finished_args)
218
+ finished_args
144
219
  end
220
+ end
145
221
 
146
- maybe_lazies.concat(arg_lazies)
147
- context.schema.after_any_lazies(maybe_lazies) do
148
- GraphQL::Execution::Interpreter::Arguments.new(
149
- keyword_arguments: kwarg_arguments,
150
- argument_values: argument_values,
151
- )
222
+ # Usually, this is validated statically by RequiredArgumentsArePresent,
223
+ # but not for directives.
224
+ # TODO apply static validations on schema definitions?
225
+ def validate_directive_argument(arg_defn, value)
226
+ if arg_defn.owner.is_a?(Class) && arg_defn.owner < GraphQL::Schema::Directive
227
+ if value.nil? && arg_defn.type.non_null?
228
+ raise ArgumentError, "#{arg_defn.path} is required, but no value was given"
229
+ end
152
230
  end
153
231
  end
154
232
 
155
233
  def arguments_statically_coercible?
156
234
  return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
157
235
 
158
- @arguments_statically_coercible = arguments.each_value.all?(&:statically_coercible?)
236
+ @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
159
237
  end
160
238
 
161
239
  module ArgumentClassAccessor
@@ -182,12 +260,20 @@ module GraphQL
182
260
  context.schema.object_from_id(id, context)
183
261
  end
184
262
 
185
- def load_application_object(argument, lookup_as_type, id, context)
263
+ def load_application_object(argument, id, context)
186
264
  # See if any object can be found for this ID
187
265
  if id.nil?
188
266
  return nil
189
267
  end
190
- loaded_application_object = object_from_id(lookup_as_type, id, context)
268
+ object_from_id(argument.loads, id, context)
269
+ end
270
+
271
+ def load_and_authorize_application_object(argument, id, context)
272
+ loaded_application_object = load_application_object(argument, id, context)
273
+ authorize_application_object(argument, id, context, loaded_application_object)
274
+ end
275
+
276
+ def authorize_application_object(argument, id, context, loaded_application_object)
191
277
  context.schema.after_lazy(loaded_application_object) do |application_object|
192
278
  if application_object.nil?
193
279
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
@@ -195,9 +281,9 @@ module GraphQL
195
281
  end
196
282
  # Double-check that the located object is actually of this type
197
283
  # (Don't want to allow arbitrary access to objects this way)
198
- resolved_application_object_type = context.schema.resolve_type(lookup_as_type, application_object, context)
284
+ resolved_application_object_type = context.schema.resolve_type(argument.loads, application_object, context)
199
285
  context.schema.after_lazy(resolved_application_object_type) do |application_object_type|
200
- possible_object_types = context.warden.possible_types(lookup_as_type)
286
+ possible_object_types = context.warden.possible_types(argument.loads)
201
287
  if !possible_object_types.include?(application_object_type)
202
288
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
203
289
  load_application_object_failed(err)
@@ -210,11 +296,17 @@ module GraphQL
210
296
  if authed
211
297
  application_object
212
298
  else
213
- raise GraphQL::UnauthorizedError.new(
299
+ err = GraphQL::UnauthorizedError.new(
214
300
  object: application_object,
215
301
  type: class_based_type,
216
302
  context: context,
217
303
  )
304
+ if self.respond_to?(:unauthorized_object)
305
+ err.set_backtrace(caller)
306
+ unauthorized_object(err)
307
+ else
308
+ raise err
309
+ end
218
310
  end
219
311
  end
220
312
  else
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDeprecationReason
7
+ # @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
8
+ def deprecation_reason
9
+ dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
10
+ dir && dir.arguments[:reason] # rubocop:disable Development/ContextIsPassedCop -- definition-related
11
+ end
12
+
13
+ # Set the deprecation reason for this member, or remove it by assigning `nil`
14
+ # @param text [String, nil]
15
+ def deprecation_reason=(text)
16
+ if text.nil?
17
+ remove_directive(GraphQL::Schema::Directive::Deprecated)
18
+ else
19
+ directive(GraphQL::Schema::Directive::Deprecated, reason: text)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDirectives
7
+ # Create an instance of `dir_class` for `self`, using `options`.
8
+ #
9
+ # It removes a previously-attached instance of `dir_class`, if there is one.
10
+ #
11
+ # @return [void]
12
+ def directive(dir_class, **options)
13
+ @own_directives ||= []
14
+ remove_directive(dir_class)
15
+ @own_directives << dir_class.new(self, **options)
16
+ nil
17
+ end
18
+
19
+ # Remove an attached instance of `dir_class`, if there is one
20
+ # @param dir_class [Class<GraphQL::Schema::Directive>]
21
+ # @return [viod]
22
+ def remove_directive(dir_class)
23
+ @own_directives && @own_directives.reject! { |d| d.is_a?(dir_class) }
24
+ nil
25
+ end
26
+
27
+ NO_DIRECTIVES = [].freeze
28
+
29
+ def directives
30
+ case self
31
+ when Class
32
+ inherited_directives = if superclass.respond_to?(:directives)
33
+ superclass.directives
34
+ else
35
+ NO_DIRECTIVES
36
+ end
37
+ if inherited_directives.any? && @own_directives
38
+ dirs = []
39
+ merge_directives(dirs, inherited_directives)
40
+ merge_directives(dirs, @own_directives)
41
+ dirs
42
+ elsif @own_directives
43
+ @own_directives
44
+ elsif inherited_directives.any?
45
+ inherited_directives
46
+ else
47
+ NO_DIRECTIVES
48
+ end
49
+ when Module
50
+ dirs = nil
51
+ self.ancestors.reverse_each do |ancestor|
52
+ if ancestor.respond_to?(:own_directives) &&
53
+ (anc_dirs = ancestor.own_directives).any?
54
+ dirs ||= []
55
+ merge_directives(dirs, anc_dirs)
56
+ end
57
+ end
58
+ if own_directives
59
+ dirs ||= []
60
+ merge_directives(dirs, own_directives)
61
+ end
62
+ dirs || NO_DIRECTIVES
63
+ when HasDirectives
64
+ @own_directives || NO_DIRECTIVES
65
+ else
66
+ raise "Invariant: how could #{self} not be a Class, Module, or instance of HasDirectives?"
67
+ end
68
+ end
69
+
70
+ protected
71
+
72
+ def own_directives
73
+ @own_directives
74
+ end
75
+
76
+ private
77
+
78
+ # Modify `target` by adding items from `dirs` such that:
79
+ # - Any name conflict is overriden by the incoming member of `dirs`
80
+ # - Any other member of `dirs` is appended
81
+ # @param target [Array<GraphQL::Schema::Directive>]
82
+ # @param dirs [Array<GraphQL::Schema::Directive>]
83
+ # @return [void]
84
+ def merge_directives(target, dirs)
85
+ dirs.each do |dir|
86
+ if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
87
+ target.slice!(idx)
88
+ target.insert(idx, dir)
89
+ else
90
+ target << dir
91
+ end
92
+ end
93
+ nil
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end