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
@@ -3,7 +3,7 @@
3
3
  module GraphQL
4
4
  class Schema
5
5
  class Member
6
- # Shared code for Object and Interface
6
+ # Shared code for Objects, Interfaces, Mutations, Subscriptions
7
7
  module HasFields
8
8
  # Add a field to this object or interface with the given definition
9
9
  # @see {GraphQL::Schema::Field#initialize} for method signature
@@ -15,28 +15,39 @@ module GraphQL
15
15
  end
16
16
 
17
17
  # @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
18
- def fields
18
+ def fields(context = GraphQL::Query::NullContext)
19
+ warden = Warden.from_context(context)
20
+ is_object = self.respond_to?(:kind) && self.kind.object?
19
21
  # Local overrides take precedence over inherited fields
20
- all_fields = {}
21
- ancestors.reverse_each do |ancestor|
22
- if ancestor.respond_to?(:own_fields)
23
- all_fields.merge!(ancestor.own_fields)
22
+ visible_fields = {}
23
+ for ancestor in ancestors
24
+ if ancestor.respond_to?(:own_fields) &&
25
+ (is_object ? visible_interface_implementation?(ancestor, context, warden) : true)
26
+
27
+ ancestor.own_fields.each do |field_name, fields_entry|
28
+ # Choose the most local definition that passes `.visible?` --
29
+ # stop checking for fields by name once one has been found.
30
+ if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
31
+ visible_fields[field_name] = f
32
+ end
33
+ end
24
34
  end
25
35
  end
26
- all_fields
36
+ visible_fields
27
37
  end
28
38
 
29
- def get_field(field_name)
30
- if (f = own_fields[field_name])
31
- f
32
- else
33
- for ancestor in ancestors
34
- if ancestor.respond_to?(:own_fields) && f = ancestor.own_fields[field_name]
35
- return f
36
- end
39
+ def get_field(field_name, context = GraphQL::Query::NullContext)
40
+ warden = Warden.from_context(context)
41
+ is_object = self.respond_to?(:kind) && self.kind.object?
42
+ for ancestor in ancestors
43
+ if ancestor.respond_to?(:own_fields) &&
44
+ (is_object ? visible_interface_implementation?(ancestor, context, warden) : true) &&
45
+ (f_entry = ancestor.own_fields[field_name]) &&
46
+ (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
47
+ return f
37
48
  end
38
- nil
39
49
  end
50
+ nil
40
51
  end
41
52
 
42
53
  # A list of Ruby keywords.
@@ -64,7 +75,19 @@ module GraphQL
64
75
  if method_conflict_warning && CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) && field_defn.original_name == field_defn.resolver_method && field_defn.original_name == field_defn.method_sym
65
76
  warn(conflict_field_name_warning(field_defn))
66
77
  end
67
- own_fields[field_defn.name] = field_defn
78
+ prev_defn = own_fields[field_defn.name]
79
+
80
+ case prev_defn
81
+ when nil
82
+ own_fields[field_defn.name] = field_defn
83
+ when Array
84
+ prev_defn << field_defn
85
+ when GraphQL::Schema::Field
86
+ own_fields[field_defn.name] = [prev_defn, field_defn]
87
+ else
88
+ raise "Invariant: unexpected previous field definition for #{field_defn.name.inspect}: #{prev_defn.inspect}"
89
+ end
90
+
68
91
  nil
69
92
  end
70
93
 
@@ -74,11 +97,8 @@ module GraphQL
74
97
  @field_class = new_field_class
75
98
  elsif defined?(@field_class) && @field_class
76
99
  @field_class
77
- elsif self.is_a?(Class)
78
- superclass.respond_to?(:field_class) ? superclass.field_class : GraphQL::Schema::Field
79
100
  else
80
- ancestor = ancestors[1..-1].find { |a| a.respond_to?(:field_class) && a.field_class }
81
- ancestor ? ancestor.field_class : GraphQL::Schema::Field
101
+ find_inherited_value(:field_class, GraphQL::Schema::Field)
82
102
  end
83
103
  end
84
104
 
@@ -90,13 +110,48 @@ module GraphQL
90
110
  end
91
111
  end
92
112
 
93
- # @return [Array<GraphQL::Schema::Field>] Fields defined on this class _specifically_, not parent classes
113
+ # @return [Hash<String => GraphQL::Schema::Field, Array<GraphQL::Schema::Field>>] Fields defined on this class _specifically_, not parent classes
94
114
  def own_fields
95
115
  @own_fields ||= {}
96
116
  end
97
117
 
118
+ def all_field_definitions
119
+ all_fields = {}
120
+ ancestors.reverse_each do |ancestor|
121
+ if ancestor.respond_to?(:own_fields)
122
+ all_fields.merge!(ancestor.own_fields)
123
+ end
124
+ end
125
+ all_fields = all_fields.values
126
+ all_fields.flatten!
127
+ all_fields
128
+ end
129
+
98
130
  private
99
131
 
132
+ # If `type` is an interface, and `self` has a type membership for `type`, then make sure it's visible.
133
+ def visible_interface_implementation?(type, context, warden)
134
+ if type.respond_to?(:kind) && type.kind.interface?
135
+ implements_this_interface = false
136
+ implementation_is_visible = false
137
+ warden.interface_type_memberships(self, context).each do |tm|
138
+ if tm.abstract_type == type
139
+ implements_this_interface ||= true
140
+ if warden.visible_type_membership?(tm, context)
141
+ implementation_is_visible = true
142
+ break
143
+ end
144
+ end
145
+ end
146
+ # It's possible this interface came by way of `include` in another interface which this
147
+ # object type _does_ implement, and that's ok
148
+ implements_this_interface ? implementation_is_visible : true
149
+ else
150
+ # If there's no implementation, then we're looking at Ruby-style inheritance instead
151
+ true
152
+ end
153
+ end
154
+
100
155
  # @param [GraphQL::Schema::Field]
101
156
  # @return [String] A warning to give when this field definition might conflict with a built-in method
102
157
  def conflict_field_name_warning(field_defn)
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasInterfaces
7
+ def implements(*new_interfaces, **options)
8
+ new_memberships = []
9
+ new_interfaces.each do |int|
10
+ if int.is_a?(Module)
11
+ unless int.include?(GraphQL::Schema::Interface)
12
+ raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
13
+ end
14
+
15
+ new_memberships << int.type_membership_class.new(int, self, **options)
16
+
17
+ # Include the methods here,
18
+ # `.fields` will use the inheritance chain
19
+ # to find inherited fields
20
+ include(int)
21
+
22
+ # If this interface has interfaces of its own, add those, too
23
+ int.interfaces.each do |next_interface|
24
+ implements(next_interface)
25
+ end
26
+ elsif int.is_a?(GraphQL::InterfaceType)
27
+ new_memberships << int.type_membership_class.new(int, self, **options)
28
+ elsif int.is_a?(String) || int.is_a?(GraphQL::Schema::LateBoundType)
29
+ if options.any?
30
+ raise ArgumentError, "`implements(...)` doesn't support options with late-loaded types yet. Remove #{options} and open an issue to request this feature."
31
+ end
32
+ new_memberships << int
33
+ else
34
+ raise ArgumentError, "Unexpected interface definition (expected module): #{int} (#{int.class})"
35
+ end
36
+ end
37
+
38
+ # Remove any String or late-bound interfaces which are being replaced
39
+ own_interface_type_memberships.reject! { |old_i_m|
40
+ if !(old_i_m.respond_to?(:abstract_type) && old_i_m.abstract_type.is_a?(Module))
41
+ old_int_type = old_i_m.respond_to?(:abstract_type) ? old_i_m.abstract_type : old_i_m
42
+ old_name = Schema::Member::BuildType.to_type_name(old_int_type)
43
+
44
+ new_memberships.any? { |new_i_m|
45
+ new_int_type = new_i_m.respond_to?(:abstract_type) ? new_i_m.abstract_type : new_i_m
46
+ new_name = Schema::Member::BuildType.to_type_name(new_int_type)
47
+
48
+ new_name == old_name
49
+ }
50
+ end
51
+ }
52
+ own_interface_type_memberships.concat(new_memberships)
53
+ end
54
+
55
+ def own_interface_type_memberships
56
+ @own_interface_type_memberships ||= []
57
+ end
58
+
59
+ def interface_type_memberships
60
+ own_tms = own_interface_type_memberships
61
+ if (self.is_a?(Class) && superclass.respond_to?(:interface_type_memberships))
62
+ inherited_tms = superclass.interface_type_memberships
63
+ if inherited_tms.size > 0
64
+ own_tms + inherited_tms
65
+ else
66
+ own_tms
67
+ end
68
+ else
69
+ own_tms
70
+ end
71
+ end
72
+
73
+ # param context [Query::Context] If omitted, skip filtering.
74
+ def interfaces(context = GraphQL::Query::NullContext)
75
+ warden = Warden.from_context(context)
76
+ visible_interfaces = []
77
+ own_interface_type_memberships.each do |type_membership|
78
+ # During initialization, `type_memberships` can hold late-bound types
79
+ case type_membership
80
+ when String, Schema::LateBoundType
81
+ visible_interfaces << type_membership
82
+ when Schema::TypeMembership
83
+ if warden.visible_type_membership?(type_membership, context)
84
+ visible_interfaces << type_membership.abstract_type
85
+ end
86
+ else
87
+ raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
88
+ end
89
+ end
90
+
91
+ if self.is_a?(Class) && superclass <= GraphQL::Schema::Object
92
+ visible_interfaces.concat(superclass.interfaces(context))
93
+ end
94
+
95
+ visible_interfaces
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Member
5
+ module HasValidators
6
+ include Schema::FindInheritedValue::EmptyObjects
7
+
8
+ # Build {GraphQL::Schema::Validator}s based on the given configuration
9
+ # and use them for this schema member
10
+ # @param validation_config [Hash{Symbol => Hash}]
11
+ # @return [void]
12
+ def validates(validation_config)
13
+ new_validators = GraphQL::Schema::Validator.from_config(self, validation_config)
14
+ @own_validators ||= []
15
+ @own_validators.concat(new_validators)
16
+ nil
17
+ end
18
+
19
+ # @return [Array<GraphQL::Schema::Validator>]
20
+ def validators
21
+ own_validators = @own_validators || EMPTY_ARRAY
22
+ if self.is_a?(Class) && superclass.respond_to?(:validators) && (inherited_validators = superclass.validators).any?
23
+ inherited_validators + own_validators
24
+ else
25
+ own_validators
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../object.rb
3
2
 
4
3
  module GraphQL
5
4
  class Schema
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  # @return [GraphQL::TypeKinds::TypeKind]
32
32
  def kind
33
- raise GraphQL::RequiredImplementationMissingError
33
+ raise GraphQL::RequiredImplementationMissingError, "No `.kind` defined for #{self}"
34
34
  end
35
35
  end
36
36
  end
@@ -8,11 +8,11 @@ module GraphQL
8
8
  validate_input(val, ctx).valid?
9
9
  end
10
10
 
11
- def validate_input(val, ctx)
11
+ def validate_input(val, ctx, max_errors: nil)
12
12
  if val.nil?
13
13
  GraphQL::Query::InputValidationResult.new
14
14
  else
15
- validate_non_null_input(val, ctx)
15
+ validate_non_null_input(val, ctx, max_errors: max_errors) || Query::InputValidationResult::VALID
16
16
  end
17
17
  end
18
18
 
@@ -4,8 +4,12 @@ require 'graphql/schema/member/base_dsl_methods'
4
4
  require 'graphql/schema/member/cached_graphql_definition'
5
5
  require 'graphql/schema/member/graphql_type_names'
6
6
  require 'graphql/schema/member/has_ast_node'
7
+ require 'graphql/schema/member/has_directives'
8
+ require 'graphql/schema/member/has_deprecation_reason'
9
+ require 'graphql/schema/member/has_interfaces'
7
10
  require 'graphql/schema/member/has_path'
8
11
  require 'graphql/schema/member/has_unresolved_type_error'
12
+ require 'graphql/schema/member/has_validators'
9
13
  require 'graphql/schema/member/relay_shortcuts'
10
14
  require 'graphql/schema/member/scoped'
11
15
  require 'graphql/schema/member/type_system_helpers'
@@ -30,6 +34,7 @@ module GraphQL
30
34
  extend RelayShortcuts
31
35
  extend HasPath
32
36
  extend HasAstNode
37
+ extend HasDirectives
33
38
  end
34
39
  end
35
40
  end
@@ -71,7 +71,7 @@ module GraphQL
71
71
 
72
72
  def wrap(callable)
73
73
  if BackwardsCompatibility.get_arity(callable) == 6
74
- warn("Middleware that takes a next_middleware parameter is deprecated (#{callable.inspect}); instead, accept a block and use yield.")
74
+ GraphQL::Deprecation.warn("Middleware that takes a next_middleware parameter is deprecated (#{callable.inspect}); instead, accept a block and use yield.")
75
75
  MiddlewareWrapper.new(callable)
76
76
  else
77
77
  callable
@@ -8,8 +8,10 @@ module GraphQL
8
8
  class NonNull < 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_non_null_type
14
+ @of_type.graphql_definition(silence_deprecation_warning: true).to_non_null_type
13
15
  end
14
16
 
15
17
  # @return [GraphQL::TypeKinds::NON_NULL]
@@ -35,13 +37,13 @@ module GraphQL
35
37
  "#<#{self.class.name} @of_type=#{@of_type.inspect}>"
36
38
  end
37
39
 
38
- def validate_input(value, ctx)
40
+ def validate_input(value, ctx, max_errors: nil)
39
41
  if value.nil?
40
42
  result = GraphQL::Query::InputValidationResult.new
41
43
  result.add_problem("Expected value to not be null")
42
44
  result
43
45
  else
44
- of_type.validate_input(value, ctx)
46
+ of_type.validate_input(value, ctx, max_errors: max_errors)
45
47
  end
46
48
  end
47
49
 
@@ -51,6 +53,10 @@ module GraphQL
51
53
  end
52
54
 
53
55
  def coerce_input(value, ctx)
56
+ # `.validate_input` above is used for variables, but this method is used for arguments
57
+ if value.nil?
58
+ raise GraphQL::ExecutionError, "`null` is not a valid input for `#{to_type_signature}`, please provide a value for this argument."
59
+ end
54
60
  of_type.coerce_input(value, ctx)
55
61
  end
56
62
 
@@ -7,6 +7,7 @@ module GraphQL
7
7
  class Object < GraphQL::Schema::Member
8
8
  extend GraphQL::Schema::Member::AcceptsDefinition
9
9
  extend GraphQL::Schema::Member::HasFields
10
+ extend GraphQL::Schema::Member::HasInterfaces
10
11
 
11
12
  # @return [Object] the application object this type is wrapping
12
13
  attr_reader :object
@@ -14,6 +15,17 @@ module GraphQL
14
15
  # @return [GraphQL::Query::Context] the context instance for this query
15
16
  attr_reader :context
16
17
 
18
+ # @return [GraphQL::Dataloader]
19
+ def dataloader
20
+ context.dataloader
21
+ end
22
+
23
+ # Call this in a field method to return a value that should be returned to the client
24
+ # without any further handling by GraphQL.
25
+ def raw_value(obj)
26
+ GraphQL::Execution::Interpreter::RawValue.new(obj)
27
+ end
28
+
17
29
  class << self
18
30
  # This is protected so that we can be sure callers use the public method, {.authorized_new}
19
31
  # @see authorized_new to make instances
@@ -37,14 +49,28 @@ module GraphQL
37
49
  # @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
38
50
  # @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
39
51
  def authorized_new(object, context)
40
- auth_val = context.query.with_error_handling do
41
- begin
42
- authorized?(object, context)
43
- rescue GraphQL::UnauthorizedError => err
44
- context.schema.unauthorized_object(err)
52
+ trace_payload = { context: context, type: self, object: object, path: context[:current_path] }
53
+
54
+ maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
55
+ context.query.with_error_handling do
56
+ begin
57
+ authorized?(object, context)
58
+ rescue GraphQL::UnauthorizedError => err
59
+ context.schema.unauthorized_object(err)
60
+ end
45
61
  end
46
62
  end
47
63
 
64
+ auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
65
+ GraphQL::Execution::Lazy.new do
66
+ context.query.trace("authorized_lazy", trace_payload) do
67
+ context.schema.sync_lazy(maybe_lazy_auth_val)
68
+ end
69
+ end
70
+ else
71
+ maybe_lazy_auth_val
72
+ end
73
+
48
74
  context.schema.after_lazy(auth_val) do |is_authorized|
49
75
  if is_authorized
50
76
  self.new(object, context)
@@ -78,84 +104,16 @@ module GraphQL
78
104
  super
79
105
  end
80
106
 
81
- def implements(*new_interfaces, **options)
82
- new_memberships = []
83
- new_interfaces.each do |int|
84
- if int.is_a?(Module)
85
- unless int.include?(GraphQL::Schema::Interface)
86
- raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
87
- end
88
-
89
- new_memberships << int.type_membership_class.new(int, self, **options)
90
-
91
- # Include the methods here,
92
- # `.fields` will use the inheritance chain
93
- # to find inherited fields
94
- include(int)
95
- elsif int.is_a?(GraphQL::InterfaceType)
96
- new_memberships << int.type_membership_class.new(int, self, **options)
97
- elsif int.is_a?(String) || int.is_a?(GraphQL::Schema::LateBoundType)
98
- if options.any?
99
- raise ArgumentError, "`implements(...)` doesn't support options with late-loaded types yet. Remove #{options} and open an issue to request this feature."
100
- end
101
- new_memberships << int
102
- else
103
- raise ArgumentError, "Unexpected interface definition (expected module): #{int} (#{int.class})"
104
- end
105
- end
106
-
107
- # Remove any interfaces which are being replaced (late-bound types are updated in place this way)
108
- own_interface_type_memberships.reject! { |old_i_m|
109
- old_int_type = old_i_m.respond_to?(:abstract_type) ? old_i_m.abstract_type : old_i_m
110
- old_name = Schema::Member::BuildType.to_type_name(old_int_type)
111
-
112
- new_memberships.any? { |new_i_m|
113
- new_int_type = new_i_m.respond_to?(:abstract_type) ? new_i_m.abstract_type : new_i_m
114
- new_name = Schema::Member::BuildType.to_type_name(new_int_type)
115
-
116
- new_name == old_name
117
- }
118
- }
119
- own_interface_type_memberships.concat(new_memberships)
120
- end
121
-
122
- def own_interface_type_memberships
123
- @own_interface_type_memberships ||= []
124
- end
125
-
126
- def interface_type_memberships
127
- own_interface_type_memberships + (superclass.respond_to?(:interface_type_memberships) ? superclass.interface_type_memberships : [])
128
- end
129
-
130
- # param context [Query::Context] If omitted, skip filtering.
131
- def interfaces(context = GraphQL::Query::NullContext)
132
- visible_interfaces = []
133
- unfiltered = context == GraphQL::Query::NullContext
134
- own_interface_type_memberships.each do |type_membership|
135
- # During initialization, `type_memberships` can hold late-bound types
136
- case type_membership
137
- when String, Schema::LateBoundType
138
- visible_interfaces << type_membership
139
- when Schema::TypeMembership
140
- if unfiltered || type_membership.visible?(context)
141
- visible_interfaces << type_membership.abstract_type
142
- end
143
- else
144
- raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
145
- end
146
- end
147
- visible_interfaces + (superclass <= GraphQL::Schema::Object ? superclass.interfaces(context) : [])
148
- end
149
-
150
107
  # @return [Hash<String => GraphQL::Schema::Field>] All of this object's fields, indexed by name
151
108
  # @see get_field A faster way to find one field by name ({#fields} merges hashes of inherited fields; {#get_field} just looks up one field.)
152
- def fields
109
+ def fields(context = GraphQL::Query::NullContext)
153
110
  all_fields = super
111
+ # This adds fields from legacy-style interfaces only.
112
+ # Multi-fields are not supported here.
154
113
  interfaces.each do |int|
155
- # Include legacy-style interfaces, too
156
114
  if int.is_a?(GraphQL::InterfaceType)
157
115
  int_f = {}
158
- int.fields.each do |name, legacy_field|
116
+ int.fields.each do |name, legacy_field| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
159
117
  int_f[name] = field_class.from_options(name, field: legacy_field)
160
118
  end
161
119
  all_fields = int_f.merge(all_fields)
@@ -164,6 +122,8 @@ module GraphQL
164
122
  all_fields
165
123
  end
166
124
 
125
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
126
+
167
127
  # @return [GraphQL::ObjectType]
168
128
  def to_graphql
169
129
  obj_type = GraphQL::ObjectType.new
@@ -173,9 +133,9 @@ module GraphQL
173
133
  obj_type.introspection = introspection
174
134
  obj_type.mutation = mutation
175
135
  obj_type.ast_node = ast_node
176
- fields.each do |field_name, field_inst|
177
- field_defn = field_inst.to_graphql
178
- obj_type.fields[field_defn.name] = field_defn
136
+ fields.each do |field_name, field_inst| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
137
+ field_defn = field_inst.to_graphql(silence_deprecation_warning: true)
138
+ obj_type.fields[field_defn.name] = field_defn # rubocop:disable Development/ContextIsPassedCop -- legacy-related
179
139
  end
180
140
 
181
141
  obj_type.metadata[:type_class] = self
@@ -4,37 +4,32 @@ module GraphQL
4
4
  # Used to convert your {GraphQL::Schema} to a GraphQL schema string
5
5
  #
6
6
  # @example print your schema to standard output (via helper)
7
- # MySchema = GraphQL::Schema.define(query: QueryType)
8
7
  # puts GraphQL::Schema::Printer.print_schema(MySchema)
9
8
  #
10
9
  # @example print your schema to standard output
11
- # MySchema = GraphQL::Schema.define(query: QueryType)
12
10
  # puts GraphQL::Schema::Printer.new(MySchema).print_schema
13
11
  #
14
12
  # @example print a single type to standard output
15
- # query_root = GraphQL::ObjectType.define do
16
- # name "Query"
13
+ # class Types::Query < GraphQL::Schema::Object
17
14
  # description "The query root of this schema"
18
15
  #
19
- # field :post do
20
- # type post_type
21
- # resolve ->(obj, args, ctx) { Post.find(args["id"]) }
22
- # end
16
+ # field :post, Types::Post, null: true
23
17
  # end
24
18
  #
25
- # post_type = GraphQL::ObjectType.define do
26
- # name "Post"
19
+ # class Types::Post < GraphQL::Schema::Object
27
20
  # description "A blog post"
28
21
  #
29
- # field :id, !types.ID
30
- # field :title, !types.String
31
- # field :body, !types.String
22
+ # field :id, ID, null: false
23
+ # field :title, String, null: false
24
+ # field :body, String, null: false
32
25
  # end
33
26
  #
34
- # MySchema = GraphQL::Schema.define(query: query_root)
27
+ # class MySchema < GraphQL::Schema
28
+ # query(Types::Query)
29
+ # end
35
30
  #
36
31
  # printer = GraphQL::Schema::Printer.new(MySchema)
37
- # puts printer.print_type(post_type)
32
+ # puts printer.print_type(Types::Post)
38
33
  #
39
34
  class Printer < GraphQL::Language::Printer
40
35
  attr_reader :schema, :warden
@@ -59,14 +54,15 @@ module GraphQL
59
54
 
60
55
  # Return the GraphQL schema string for the introspection type system
61
56
  def self.print_introspection_schema
62
- query_root = ObjectType.define(name: "Root") do
63
- field :throwaway_field, types.String
57
+ query_root = Class.new(GraphQL::Schema::Object) do
58
+ graphql_name "Root"
59
+ field :throwaway_field, String
64
60
  end
65
- schema = GraphQL::Schema.define(query: query_root)
61
+ schema = Class.new(GraphQL::Schema) { query(query_root) }
66
62
 
67
63
  introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
68
64
  schema,
69
- except: ->(member, _) { member.name == "Root" },
65
+ except: ->(member, _) { member.graphql_name == "Root" },
70
66
  include_introspection_types: true,
71
67
  include_built_in_directives: true,
72
68
  ).document
@@ -86,7 +82,7 @@ module GraphQL
86
82
 
87
83
  # Return a GraphQL schema string for the defined types in the schema
88
84
  def print_schema
89
- print(@document)
85
+ print(@document) + "\n"
90
86
  end
91
87
 
92
88
  def print_type(type)