graphql 1.8.7 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +2 -1
  3. data/lib/generators/graphql/scalar_generator.rb +20 -0
  4. data/lib/generators/graphql/templates/base_scalar.erb +4 -0
  5. data/lib/generators/graphql/templates/scalar.erb +13 -0
  6. data/lib/graphql/analysis/ast/analyzer.rb +62 -0
  7. data/lib/graphql/analysis/ast/field_usage.rb +28 -0
  8. data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
  9. data/lib/graphql/analysis/ast/max_query_depth.rb +18 -0
  10. data/lib/graphql/analysis/ast/query_complexity.rb +114 -0
  11. data/lib/graphql/analysis/ast/query_depth.rb +66 -0
  12. data/lib/graphql/analysis/ast/visitor.rb +255 -0
  13. data/lib/graphql/analysis/ast.rb +82 -0
  14. data/lib/graphql/analysis.rb +1 -0
  15. data/lib/graphql/argument.rb +5 -0
  16. data/lib/graphql/authorization.rb +1 -0
  17. data/lib/graphql/backwards_compatibility.rb +1 -1
  18. data/lib/graphql/base_type.rb +1 -1
  19. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
  20. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -6
  21. data/lib/graphql/dig.rb +19 -0
  22. data/lib/graphql/directive/include_directive.rb +1 -7
  23. data/lib/graphql/directive/skip_directive.rb +1 -8
  24. data/lib/graphql/directive.rb +13 -1
  25. data/lib/graphql/enum_type.rb +8 -0
  26. data/lib/graphql/execution/execute.rb +36 -17
  27. data/lib/graphql/execution/instrumentation.rb +2 -0
  28. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  29. data/lib/graphql/execution/interpreter/hash_response.rb +46 -0
  30. data/lib/graphql/execution/interpreter/resolve.rb +58 -0
  31. data/lib/graphql/execution/interpreter/runtime.rb +597 -0
  32. data/lib/graphql/execution/interpreter.rb +99 -0
  33. data/lib/graphql/execution/lazy.rb +8 -1
  34. data/lib/graphql/execution/lookahead.rb +351 -0
  35. data/lib/graphql/execution/multiplex.rb +37 -29
  36. data/lib/graphql/execution.rb +2 -0
  37. data/lib/graphql/execution_error.rb +1 -1
  38. data/lib/graphql/field.rb +1 -7
  39. data/lib/graphql/integer_encoding_error.rb +12 -0
  40. data/lib/graphql/internal_representation/rewrite.rb +127 -142
  41. data/lib/graphql/introspection/dynamic_fields.rb +8 -2
  42. data/lib/graphql/introspection/entry_points.rb +11 -6
  43. data/lib/graphql/introspection/enum_value_type.rb +4 -0
  44. data/lib/graphql/introspection/schema_type.rb +7 -2
  45. data/lib/graphql/introspection/type_type.rb +9 -5
  46. data/lib/graphql/invalid_null_error.rb +1 -1
  47. data/lib/graphql/language/block_string.rb +37 -0
  48. data/lib/graphql/language/document_from_schema_definition.rb +10 -7
  49. data/lib/graphql/language/lexer.rb +55 -36
  50. data/lib/graphql/language/lexer.rl +8 -3
  51. data/lib/graphql/language/nodes.rb +440 -362
  52. data/lib/graphql/language/parser.rb +56 -56
  53. data/lib/graphql/language/parser.y +12 -12
  54. data/lib/graphql/language/printer.rb +2 -2
  55. data/lib/graphql/language/visitor.rb +158 -15
  56. data/lib/graphql/language.rb +0 -1
  57. data/lib/graphql/literal_validation_error.rb +6 -0
  58. data/lib/graphql/query/arguments.rb +3 -2
  59. data/lib/graphql/query/arguments_cache.rb +1 -1
  60. data/lib/graphql/query/context.rb +14 -5
  61. data/lib/graphql/query/executor.rb +1 -1
  62. data/lib/graphql/query/result.rb +1 -1
  63. data/lib/graphql/query/validation_pipeline.rb +35 -11
  64. data/lib/graphql/query/variable_validation_error.rb +10 -1
  65. data/lib/graphql/query.rb +16 -2
  66. data/lib/graphql/relay/base_connection.rb +2 -0
  67. data/lib/graphql/relay/connection_instrumentation.rb +3 -1
  68. data/lib/graphql/relay/connection_resolve.rb +1 -1
  69. data/lib/graphql/relay/node.rb +2 -28
  70. data/lib/graphql/relay/relation_connection.rb +1 -1
  71. data/lib/graphql/schema/argument.rb +13 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +4 -4
  73. data/lib/graphql/schema/build_from_definition.rb +2 -4
  74. data/lib/graphql/schema/default_type_error.rb +1 -1
  75. data/lib/graphql/schema/directive/feature.rb +66 -0
  76. data/lib/graphql/schema/directive/include.rb +25 -0
  77. data/lib/graphql/schema/directive/skip.rb +25 -0
  78. data/lib/graphql/schema/directive/transform.rb +48 -0
  79. data/lib/graphql/schema/directive.rb +103 -0
  80. data/lib/graphql/schema/enum_value.rb +3 -2
  81. data/lib/graphql/schema/field/connection_extension.rb +50 -0
  82. data/lib/graphql/schema/field/scope_extension.rb +18 -0
  83. data/lib/graphql/schema/field.rb +273 -64
  84. data/lib/graphql/schema/field_extension.rb +69 -0
  85. data/lib/graphql/schema/input_object.rb +16 -8
  86. data/lib/graphql/schema/interface.rb +1 -0
  87. data/lib/graphql/schema/loader.rb +22 -16
  88. data/lib/graphql/schema/member/base_dsl_methods.rb +8 -2
  89. data/lib/graphql/schema/member/build_type.rb +33 -1
  90. data/lib/graphql/schema/member/has_arguments.rb +6 -2
  91. data/lib/graphql/schema/member/has_fields.rb +18 -70
  92. data/lib/graphql/schema/member/has_path.rb +25 -0
  93. data/lib/graphql/schema/member/instrumentation.rb +10 -7
  94. data/lib/graphql/schema/member.rb +2 -0
  95. data/lib/graphql/schema/mutation.rb +6 -48
  96. data/lib/graphql/schema/non_null.rb +5 -1
  97. data/lib/graphql/schema/object.rb +18 -4
  98. data/lib/graphql/schema/printer.rb +1 -1
  99. data/lib/graphql/schema/relay_classic_mutation.rb +42 -9
  100. data/lib/graphql/schema/resolver/has_payload_type.rb +65 -0
  101. data/lib/graphql/schema/resolver.rb +45 -20
  102. data/lib/graphql/schema/subscription.rb +97 -0
  103. data/lib/graphql/schema/traversal.rb +11 -7
  104. data/lib/graphql/schema.rb +186 -38
  105. data/lib/graphql/static_validation/all_rules.rb +3 -2
  106. data/lib/graphql/static_validation/base_visitor.rb +199 -0
  107. data/lib/graphql/static_validation/default_visitor.rb +15 -0
  108. data/lib/graphql/static_validation/definition_dependencies.rb +62 -68
  109. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  110. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  111. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  112. data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
  113. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +87 -16
  114. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  115. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +11 -11
  116. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  117. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +52 -8
  118. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  119. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -15
  120. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  121. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +19 -14
  122. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  123. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +17 -19
  124. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  125. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +30 -14
  126. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  127. data/lib/graphql/static_validation/rules/fields_will_merge.rb +356 -29
  128. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  129. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +20 -13
  130. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  131. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +37 -29
  132. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  133. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +25 -17
  134. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  135. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +12 -10
  136. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  137. data/lib/graphql/static_validation/rules/fragments_are_named.rb +7 -11
  138. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  139. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +16 -16
  140. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  141. data/lib/graphql/static_validation/rules/fragments_are_used.rb +21 -14
  142. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  143. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +10 -14
  144. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  145. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +30 -30
  146. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  147. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +25 -17
  148. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  149. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +17 -18
  150. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  151. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  152. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  153. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +10 -14
  154. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  155. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +28 -17
  156. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  157. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +35 -27
  158. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  159. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +15 -14
  160. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  161. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -30
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +18 -14
  164. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  165. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +73 -65
  166. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  167. data/lib/graphql/static_validation/validation_context.rb +8 -51
  168. data/lib/graphql/static_validation/validator.rb +23 -15
  169. data/lib/graphql/static_validation.rb +5 -3
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -2
  171. data/lib/graphql/subscriptions/event.rb +28 -5
  172. data/lib/graphql/subscriptions/subscription_root.rb +66 -0
  173. data/lib/graphql/subscriptions.rb +16 -2
  174. data/lib/graphql/tracing/active_support_notifications_tracing.rb +0 -1
  175. data/lib/graphql/tracing/appsignal_tracing.rb +1 -1
  176. data/lib/graphql/tracing/data_dog_tracing.rb +1 -1
  177. data/lib/graphql/tracing/new_relic_tracing.rb +3 -3
  178. data/lib/graphql/tracing/platform_tracing.rb +17 -1
  179. data/lib/graphql/tracing/prometheus_tracing.rb +1 -1
  180. data/lib/graphql/tracing/scout_tracing.rb +1 -1
  181. data/lib/graphql/tracing/skylight_tracing.rb +3 -3
  182. data/lib/graphql/tracing.rb +8 -8
  183. data/lib/graphql/types/float.rb +1 -1
  184. data/lib/graphql/types/int.rb +11 -2
  185. data/lib/graphql/types/iso_8601_date_time.rb +15 -1
  186. data/lib/graphql/types/relay/base_connection.rb +15 -1
  187. data/lib/graphql/types/relay/node.rb +0 -1
  188. data/lib/graphql/types/relay/node_field.rb +43 -0
  189. data/lib/graphql/types/relay/nodes_field.rb +45 -0
  190. data/lib/graphql/types/relay.rb +2 -0
  191. data/lib/graphql/unauthorized_error.rb +4 -0
  192. data/lib/graphql/unauthorized_field_error.rb +23 -0
  193. data/lib/graphql/upgrader/member.rb +5 -0
  194. data/lib/graphql/version.rb +1 -1
  195. data/lib/graphql.rb +6 -1
  196. data/readme.md +7 -7
  197. data/spec/dummy/Gemfile +1 -1
  198. data/spec/dummy/Gemfile.lock +157 -0
  199. data/spec/dummy/app/channels/graphql_channel.rb +22 -11
  200. data/spec/dummy/config/locales/en.yml +1 -1
  201. data/spec/dummy/log/test.log +199 -0
  202. data/spec/dummy/test/test_helper.rb +1 -0
  203. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
  204. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +1 -0
  205. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +1 -0
  206. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +1 -0
  207. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +3 -0
  208. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
  209. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +2 -0
  210. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +2 -0
  211. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
  212. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
  213. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +1 -0
  214. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
  215. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +1 -0
  216. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +3 -0
  217. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +1 -0
  218. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +1 -0
  219. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
  220. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +1 -0
  221. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
  222. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  223. data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
  224. data/spec/graphql/analysis/ast/field_usage_spec.rb +51 -0
  225. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +120 -0
  226. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +114 -0
  227. data/spec/graphql/analysis/ast/query_complexity_spec.rb +299 -0
  228. data/spec/graphql/analysis/ast/query_depth_spec.rb +108 -0
  229. data/spec/graphql/analysis/ast_spec.rb +269 -0
  230. data/spec/graphql/authorization_spec.rb +120 -23
  231. data/spec/graphql/base_type_spec.rb +6 -4
  232. data/spec/graphql/enum_type_spec.rb +6 -1
  233. data/spec/graphql/execution/execute_spec.rb +9 -9
  234. data/spec/graphql/execution/instrumentation_spec.rb +19 -0
  235. data/spec/graphql/execution/interpreter_spec.rb +485 -0
  236. data/spec/graphql/execution/lazy_spec.rb +67 -1
  237. data/spec/graphql/execution/lookahead_spec.rb +363 -0
  238. data/spec/graphql/execution/multiplex_spec.rb +31 -3
  239. data/spec/graphql/execution/typecast_spec.rb +20 -20
  240. data/spec/graphql/execution_error_spec.rb +110 -96
  241. data/spec/graphql/field_spec.rb +1 -1
  242. data/spec/graphql/input_object_type_spec.rb +13 -352
  243. data/spec/graphql/int_type_spec.rb +19 -0
  244. data/spec/graphql/interface_type_spec.rb +4 -4
  245. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -0
  246. data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
  247. data/spec/graphql/introspection/type_type_spec.rb +1 -2
  248. data/spec/graphql/language/document_from_schema_definition_spec.rb +2 -2
  249. data/spec/graphql/language/lexer_spec.rb +72 -3
  250. data/spec/graphql/language/nodes_spec.rb +20 -0
  251. data/spec/graphql/language/printer_spec.rb +18 -6
  252. data/spec/graphql/language/visitor_spec.rb +320 -14
  253. data/spec/graphql/non_null_type_spec.rb +1 -1
  254. data/spec/graphql/object_type_spec.rb +32 -27
  255. data/spec/graphql/query/arguments_spec.rb +21 -0
  256. data/spec/graphql/query/context_spec.rb +28 -0
  257. data/spec/graphql/query/executor_spec.rb +40 -36
  258. data/spec/graphql/query_spec.rb +12 -6
  259. data/spec/graphql/schema/argument_spec.rb +35 -1
  260. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  261. data/spec/graphql/schema/catchall_middleware_spec.rb +16 -15
  262. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  263. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  264. data/spec/graphql/schema/enum_spec.rb +12 -3
  265. data/spec/graphql/schema/enum_value_spec.rb +11 -0
  266. data/spec/graphql/schema/field_extension_spec.rb +115 -0
  267. data/spec/graphql/schema/field_spec.rb +47 -7
  268. data/spec/graphql/schema/input_object_spec.rb +95 -0
  269. data/spec/graphql/schema/instrumentation_spec.rb +3 -0
  270. data/spec/graphql/schema/interface_spec.rb +8 -2
  271. data/spec/graphql/schema/introspection_system_spec.rb +9 -1
  272. data/spec/graphql/schema/loader_spec.rb +5 -0
  273. data/spec/graphql/schema/member/accepts_definition_spec.rb +4 -0
  274. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  275. data/spec/graphql/schema/member/scoped_spec.rb +19 -3
  276. data/spec/graphql/schema/mutation_spec.rb +5 -3
  277. data/spec/graphql/schema/object_spec.rb +9 -1
  278. data/spec/graphql/schema/printer_spec.rb +255 -93
  279. data/spec/graphql/schema/relay_classic_mutation_spec.rb +133 -0
  280. data/spec/graphql/schema/resolver_spec.rb +173 -9
  281. data/spec/graphql/schema/scalar_spec.rb +6 -0
  282. data/spec/graphql/schema/subscription_spec.rb +416 -0
  283. data/spec/graphql/schema/traversal_spec.rb +10 -10
  284. data/spec/graphql/schema/type_expression_spec.rb +2 -2
  285. data/spec/graphql/schema/union_spec.rb +7 -0
  286. data/spec/graphql/schema/validation_spec.rb +1 -1
  287. data/spec/graphql/schema/warden_spec.rb +145 -88
  288. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +213 -73
  289. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  290. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  291. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  292. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  293. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  294. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  295. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +131 -5
  296. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  297. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  298. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  299. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  300. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  301. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  302. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  303. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  304. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  305. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  306. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  307. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  308. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  309. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  310. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  311. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  312. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +23 -3
  313. data/spec/graphql/static_validation/type_stack_spec.rb +10 -19
  314. data/spec/graphql/static_validation/validator_spec.rb +50 -2
  315. data/spec/graphql/subscriptions_spec.rb +27 -16
  316. data/spec/graphql/tracing/new_relic_tracing_spec.rb +16 -0
  317. data/spec/graphql/tracing/platform_tracing_spec.rb +59 -37
  318. data/spec/graphql/tracing/prometheus_tracing_spec.rb +3 -0
  319. data/spec/graphql/tracing/skylight_tracing_spec.rb +16 -0
  320. data/spec/graphql/types/iso_8601_date_time_spec.rb +29 -2
  321. data/spec/graphql/union_type_spec.rb +2 -2
  322. data/spec/graphql/upgrader/member_spec.rb +67 -0
  323. data/spec/{graphql → integration/mongoid/graphql}/relay/mongo_relation_connection_spec.rb +11 -22
  324. data/spec/integration/mongoid/spec_helper.rb +2 -0
  325. data/spec/{support → integration/mongoid}/star_trek/data.rb +0 -0
  326. data/spec/{support → integration/mongoid}/star_trek/schema.rb +56 -34
  327. data/spec/{support/star_wars → integration/rails}/data.rb +1 -0
  328. data/spec/{support → integration/rails/generators}/base_generator_test.rb +0 -0
  329. data/spec/{generators → integration/rails/generators}/graphql/enum_generator_spec.rb +0 -0
  330. data/spec/{generators → integration/rails/generators}/graphql/install_generator_spec.rb +1 -1
  331. data/spec/{generators → integration/rails/generators}/graphql/interface_generator_spec.rb +0 -0
  332. data/spec/{generators → integration/rails/generators}/graphql/loader_generator_spec.rb +0 -0
  333. data/spec/{generators → integration/rails/generators}/graphql/mutation_generator_spec.rb +0 -0
  334. data/spec/{generators → integration/rails/generators}/graphql/object_generator_spec.rb +0 -0
  335. data/spec/integration/rails/generators/graphql/scalar_generator_spec.rb +28 -0
  336. data/spec/{generators → integration/rails/generators}/graphql/union_generator_spec.rb +0 -0
  337. data/spec/integration/rails/graphql/input_object_type_spec.rb +364 -0
  338. data/spec/{graphql → integration/rails/graphql}/query/variables_spec.rb +7 -7
  339. data/spec/{graphql → integration/rails/graphql}/relay/array_connection_spec.rb +9 -9
  340. data/spec/{graphql → integration/rails/graphql}/relay/base_connection_spec.rb +11 -3
  341. data/spec/{graphql → integration/rails/graphql}/relay/connection_instrumentation_spec.rb +19 -22
  342. data/spec/{graphql → integration/rails/graphql}/relay/connection_resolve_spec.rb +16 -0
  343. data/spec/{graphql → integration/rails/graphql}/relay/connection_type_spec.rb +0 -0
  344. data/spec/{graphql → integration/rails/graphql}/relay/edge_spec.rb +0 -0
  345. data/spec/{graphql → integration/rails/graphql}/relay/mutation_spec.rb +48 -0
  346. data/spec/{graphql → integration/rails/graphql}/relay/node_spec.rb +0 -0
  347. data/spec/{graphql → integration/rails/graphql}/relay/page_info_spec.rb +22 -22
  348. data/spec/{graphql → integration/rails/graphql}/relay/range_add_spec.rb +4 -4
  349. data/spec/{graphql → integration/rails/graphql}/relay/relation_connection_spec.rb +56 -27
  350. data/spec/{graphql → integration/rails/graphql}/schema_spec.rb +15 -11
  351. data/spec/{graphql → integration/rails/graphql}/tracing/active_support_notifications_tracing_spec.rb +16 -9
  352. data/spec/integration/rails/spec_helper.rb +25 -0
  353. data/spec/integration/tmp/app/graphql/types/family_type.rb +9 -0
  354. data/spec/spec_helper.rb +23 -39
  355. data/spec/support/dummy/data.rb +20 -17
  356. data/spec/support/dummy/schema.rb +315 -305
  357. data/spec/support/error_bubbling_helpers.rb +23 -0
  358. data/spec/support/jazz.rb +213 -46
  359. data/spec/support/lazy_helpers.rb +69 -27
  360. data/spec/support/new_relic.rb +3 -0
  361. data/spec/support/skylight.rb +3 -0
  362. data/spec/support/star_wars/schema.rb +131 -81
  363. data/spec/support/static_validation_helpers.rb +9 -5
  364. metadata +418 -261
  365. data/lib/graphql/language/comments.rb +0 -45
  366. data/lib/graphql/static_validation/arguments_validator.rb +0 -50
  367. data/spec/graphql/schema/member/has_fields_spec.rb +0 -129
  368. data/spec/rails_dependency_sanity_spec.rb +0 -14
@@ -5,12 +5,17 @@ module GraphQL
5
5
  extend GraphQL::Schema::Member::AcceptsDefinition
6
6
  extend Forwardable
7
7
  extend GraphQL::Schema::Member::HasArguments
8
+ include GraphQL::Dig
8
9
 
9
- def initialize(values, context:, defaults_used:)
10
+ def initialize(values = nil, ruby_kwargs: nil, context:, defaults_used:)
10
11
  @context = context
11
- @arguments = self.class.arguments_class.new(values, context: context, defaults_used: defaults_used)
12
- # Symbolized, underscored hash:
13
- @ruby_style_hash = @arguments.to_kwargs
12
+ if ruby_kwargs
13
+ @ruby_style_hash = ruby_kwargs
14
+ else
15
+ @arguments = self.class.arguments_class.new(values, context: context, defaults_used: defaults_used)
16
+ # Symbolized, underscored hash:
17
+ @ruby_style_hash = @arguments.to_kwargs
18
+ end
14
19
  # Apply prepares, not great to have it duplicated here.
15
20
  self.class.arguments.each do |name, arg_defn|
16
21
  ruby_kwargs_key = arg_defn.keyword
@@ -56,13 +61,15 @@ module GraphQL
56
61
  def [](key)
57
62
  if @ruby_style_hash.key?(key)
58
63
  @ruby_style_hash[key]
59
- else
64
+ elsif @arguments
60
65
  @arguments[key]
66
+ else
67
+ nil
61
68
  end
62
69
  end
63
70
 
64
71
  def key?(key)
65
- @ruby_style_hash.key?(key) || @arguments.key?(key)
72
+ @ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key))
66
73
  end
67
74
 
68
75
  # A copy of the Ruby-style hash
@@ -78,8 +85,9 @@ module GraphQL
78
85
  argument_defn = super
79
86
  # Add a method access
80
87
  arg_name = argument_defn.graphql_definition.name
81
- define_method(Member::BuildType.underscore(arg_name)) do
82
- @arguments.public_send(arg_name)
88
+ method_name = Member::BuildType.underscore(arg_name).to_sym
89
+ define_method(method_name) do
90
+ @ruby_style_hash[method_name]
83
91
  end
84
92
  end
85
93
 
@@ -9,6 +9,7 @@ module GraphQL
9
9
  include GraphQL::Schema::Member::BaseDSLMethods
10
10
  include GraphQL::Schema::Member::TypeSystemHelpers
11
11
  include GraphQL::Schema::Member::HasFields
12
+ include GraphQL::Schema::Member::HasPath
12
13
  include GraphQL::Schema::Member::RelayShortcuts
13
14
  include GraphQL::Schema::Member::Scoped
14
15
 
@@ -55,6 +55,27 @@ module GraphQL
55
55
  end
56
56
  end
57
57
 
58
+ def extract_default_value(default_value_str, input_value_ast)
59
+ case input_value_ast
60
+ when String, Integer, Float, TrueClass, FalseClass
61
+ input_value_ast
62
+ when GraphQL::Language::Nodes::Enum
63
+ input_value_ast.name
64
+ when GraphQL::Language::Nodes::NullValue
65
+ nil
66
+ when GraphQL::Language::Nodes::InputObject
67
+ input_value_ast.to_h
68
+ when Array
69
+ input_value_ast.map { |element| extract_default_value(default_value_str, element) }
70
+ else
71
+ raise(
72
+ "Encountered unexpected type when loading default value. "\
73
+ "input_value_ast.class is #{input_value_ast.class} "\
74
+ "default_value is #{default_value_str}"
75
+ )
76
+ end
77
+ end
78
+
58
79
  def define_type(type, type_resolver)
59
80
  case type.fetch("kind")
60
81
  when "ENUM"
@@ -119,22 +140,7 @@ module GraphQL
119
140
  # Reach into the AST for the default value:
120
141
  input_value_ast = dummy_query_ast.definitions.first.variables.first.default_value
121
142
 
122
- case input_value_ast
123
- when String, Integer, Float, TrueClass, FalseClass, Array
124
- input_value_ast
125
- when GraphQL::Language::Nodes::Enum
126
- input_value_ast.name
127
- when GraphQL::Language::Nodes::NullValue
128
- nil
129
- when GraphQL::Language::Nodes::InputObject
130
- input_value_ast.to_h
131
- else
132
- raise(
133
- "Encountered unexpected type when loading default value. "\
134
- "input_value_ast.class is #{input_value_ast.class} "\
135
- "default_value is #{default_value_str}"
136
- )
137
- end
143
+ extract_default_value(default_value_str, input_value_ast)
138
144
  end
139
145
  end
140
146
 
@@ -55,6 +55,10 @@ module GraphQL
55
55
  end
56
56
  end
57
57
 
58
+ def introspection?
59
+ introspection
60
+ end
61
+
58
62
  # The mutation this type was derived from, if it was derived from a mutation
59
63
  # @return [Class]
60
64
  def mutation(mutation_class = nil)
@@ -79,9 +83,11 @@ module GraphQL
79
83
  # The default name is the Ruby constant name,
80
84
  # without any namespaces and with any `-Type` suffix removed
81
85
  def default_graphql_name
82
- raise NotImplementedError, 'Anonymous class should declare a `graphql_name`' if name.nil?
86
+ @default_graphql_name ||= begin
87
+ raise NotImplementedError, 'Anonymous class should declare a `graphql_name`' if name.nil?
83
88
 
84
- name.split("::").last.sub(/Type\Z/, "")
89
+ name.split("::").last.sub(/Type\Z/, "")
90
+ end
85
91
  end
86
92
 
87
93
  def visible?(context)
@@ -33,7 +33,7 @@ module GraphQL
33
33
  null = false
34
34
  parse_type(type_expr[0..-2], null: true)
35
35
  else
36
- maybe_type = Object.const_get(type_expr)
36
+ maybe_type = constantize(type_expr)
37
37
  case maybe_type
38
38
  when GraphQL::BaseType
39
39
  maybe_type
@@ -125,6 +125,38 @@ module GraphQL
125
125
  camelized
126
126
  end
127
127
 
128
+ # Resolves constant from string (based on Rails `ActiveSupport::Inflector.constantize`)
129
+ def constantize(string)
130
+ names = string.split('::')
131
+
132
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
133
+ Object.const_get(string) if names.empty?
134
+
135
+ # Remove the first blank element in case of '::ClassName' notation.
136
+ names.shift if names.size > 1 && names.first.empty?
137
+
138
+ names.inject(Object) do |constant, name|
139
+ if constant == Object
140
+ constant.const_get(name)
141
+ else
142
+ candidate = constant.const_get(name)
143
+ next candidate if constant.const_defined?(name, false)
144
+ next candidate unless Object.const_defined?(name)
145
+
146
+ # Go down the ancestors to check if it is owned directly. The check
147
+ # stops when we reach Object or the end of ancestors tree.
148
+ constant = constant.ancestors.inject do |const, ancestor|
149
+ break const if ancestor == Object
150
+ break ancestor if ancestor.const_defined?(name, false)
151
+ const
152
+ end
153
+
154
+ # Owner is in Object, so raise.
155
+ constant.const_get(name, false)
156
+ end
157
+ end
158
+ end
159
+
128
160
  def underscore(string)
129
161
  string
130
162
  .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
@@ -29,9 +29,13 @@ module GraphQL
29
29
 
30
30
  # @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
31
31
  def arguments
32
- inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments : {})
32
+ inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments : nil)
33
33
  # Local definitions override inherited ones
34
- inherited_arguments.merge(own_arguments)
34
+ if inherited_arguments
35
+ inherited_arguments.merge(own_arguments)
36
+ else
37
+ own_arguments
38
+ end
35
39
  end
36
40
 
37
41
  # @param new_arg_class [Class] A class to use for building argument definitions
@@ -4,47 +4,6 @@ module GraphQL
4
4
  class Member
5
5
  # Shared code for Object and Interface
6
6
  module HasFields
7
- class << self
8
- # When this module is added to a class,
9
- # add a place for that class's default behaviors
10
- def self.extended(child_class)
11
- add_default_resolve_module(child_class)
12
- super
13
- end
14
-
15
- # Create a module which will have instance methods for implementing fields.
16
- # These will be `super` methods for fields in interfaces, objects and mutations.
17
- # Use an instance variable on the class instead of a constant
18
- # so that module namespaces won't be an issue. (If we used constants,
19
- # `child_class::DefaultResolve` might find a constant from an included module.)
20
- def add_default_resolve_module(child_class)
21
- if child_class.instance_variable_get(:@_default_resolve)
22
- # This can happen when an object implements an interface,
23
- # since that interface has the `included` hook above.
24
- return
25
- end
26
-
27
- default_resolve_module = Module.new
28
- child_class.instance_variable_set(:@_default_resolve, default_resolve_module)
29
- child_class.include(default_resolve_module)
30
- end
31
- end
32
-
33
- # When this is included into interfaces,
34
- # add a place for default field behaviors
35
- def included(child_class)
36
- HasFields.add_default_resolve_module(child_class)
37
- # Also, prepare a place for default field implementations
38
- super
39
- end
40
-
41
- # When a subclass of objects are created,
42
- # add a place for that subclass's default field behaviors
43
- def inherited(child_class)
44
- HasFields.add_default_resolve_module(child_class)
45
- super
46
- end
47
-
48
7
  # Add a field to this object or interface with the given definition
49
8
  # @see {GraphQL::Schema::Field#initialize} for method signature
50
9
  # @return [void]
@@ -66,16 +25,24 @@ module GraphQL
66
25
  all_fields
67
26
  end
68
27
 
28
+ def get_field(field_name)
29
+ if (f = own_fields[field_name])
30
+ f
31
+ else
32
+ for ancestor in ancestors
33
+ if ancestor.respond_to?(:own_fields) && f = ancestor.own_fields[field_name]
34
+ return f
35
+ end
36
+ end
37
+ nil
38
+ end
39
+ end
40
+
69
41
  # Register this field with the class, overriding a previous one if needed.
70
- # Also, add a parent method for resolving this field.
71
42
  # @param field_defn [GraphQL::Schema::Field]
72
43
  # @return [void]
73
44
  def add_field(field_defn)
74
45
  own_fields[field_defn.name] = field_defn
75
- if !method_defined?(field_defn.method_sym)
76
- # Only add the super method if there isn't one already.
77
- add_super_method(field_defn.name.inspect, field_defn.method_sym)
78
- end
79
46
  nil
80
47
  end
81
48
 
@@ -94,36 +61,17 @@ module GraphQL
94
61
  end
95
62
 
96
63
  def global_id_field(field_name)
97
- field field_name, "ID", null: false, resolve: GraphQL::Relay::GlobalIdResolve.new(type: self)
64
+ id_resolver = GraphQL::Relay::GlobalIdResolve.new(type: self)
65
+ field field_name, "ID", null: false
66
+ define_method(field_name) do
67
+ id_resolver.call(object, {}, context)
68
+ end
98
69
  end
99
70
 
100
71
  # @return [Array<GraphQL::Schema::Field>] Fields defined on this class _specifically_, not parent classes
101
72
  def own_fields
102
73
  @own_fields ||= {}
103
74
  end
104
-
105
- private
106
- # Find the magic module for holding super methods,
107
- # and add a field named `method_name` for implementing the field
108
- # called `field_name`.
109
- # It will be the `super` method if the method is overwritten in the class definition.
110
- def add_super_method(field_key, method_name)
111
- default_resolve_module = @_default_resolve
112
- if default_resolve_module.nil?
113
- # This should have been set up in one of the inherited or included hooks above,
114
- # if it wasn't, it's because those hooks weren't called because `super` wasn't present.
115
- raise <<-ERR
116
- Uh oh! #{self} doesn't have a default resolve module. This probably means that an `inherited` hook didn't call super.
117
- Check `inherited` on #{self}'s superclasses.
118
- ERR
119
- end
120
- default_resolve_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
121
- def #{method_name}(**args)
122
- field_inst = self.class.fields[#{field_key}] || raise(%|Failed to find field #{field_key} for \#{self.class} among \#{self.class.fields.keys}|)
123
- field_inst.resolve_field_method(self, args, context)
124
- end
125
- RUBY
126
- end
127
75
  end
128
76
  end
129
77
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasPath
7
+ # @return [String] A description of this member's place in the GraphQL schema
8
+ def path
9
+ path_str = if self.respond_to?(:graphql_name)
10
+ self.graphql_name
11
+ elsif self.class.respond_to?(:graphql_name)
12
+ # Instances of resolvers
13
+ self.class.graphql_name
14
+ end
15
+
16
+ if self.respond_to?(:owner) && owner.respond_to?(:path)
17
+ path_str = "#{owner.path}.#{path_str}"
18
+ end
19
+
20
+ path_str
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -91,7 +91,7 @@ module GraphQL
91
91
  # For lists with nil, we need another nil check here
92
92
  nil
93
93
  else
94
- concrete_type = case @inner_return_type
94
+ concrete_type_or_lazy = case @inner_return_type
95
95
  when GraphQL::UnionType, GraphQL::InterfaceType
96
96
  ctx.query.resolve_type(@inner_return_type, inner_obj)
97
97
  when GraphQL::ObjectType
@@ -100,12 +100,15 @@ module GraphQL
100
100
  raise "unexpected proxying type #{@inner_return_type} for #{inner_obj} at #{ctx.owner_type}.#{ctx.field.name}"
101
101
  end
102
102
 
103
- if concrete_type && (object_class = concrete_type.metadata[:type_class])
104
- # use the query-level context here, since it won't be field-specific anyways
105
- query_ctx = ctx.query.context
106
- object_class.authorized_new(inner_obj, query_ctx)
107
- else
108
- inner_obj
103
+ # .resolve_type may have returned a lazy
104
+ ctx.schema.after_lazy(concrete_type_or_lazy) do |concrete_type|
105
+ if concrete_type && (object_class = concrete_type.metadata[:type_class])
106
+ # use the query-level context here, since it won't be field-specific anyways
107
+ query_ctx = ctx.query.context
108
+ object_class.authorized_new(inner_obj, query_ctx)
109
+ else
110
+ inner_obj
111
+ end
109
112
  end
110
113
  end
111
114
  end
@@ -3,6 +3,7 @@ require 'graphql/schema/member/accepts_definition'
3
3
  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
+ require 'graphql/schema/member/has_path'
6
7
  require 'graphql/schema/member/relay_shortcuts'
7
8
  require 'graphql/schema/member/scoped'
8
9
  require 'graphql/schema/member/type_system_helpers'
@@ -22,6 +23,7 @@ module GraphQL
22
23
  extend TypeSystemHelpers
23
24
  extend Scoped
24
25
  extend RelayShortcuts
26
+ extend HasPath
25
27
  end
26
28
  end
27
29
  end
@@ -60,71 +60,29 @@ module GraphQL
60
60
  #
61
61
  class Mutation < GraphQL::Schema::Resolver
62
62
  extend GraphQL::Schema::Member::HasFields
63
+ extend GraphQL::Schema::Resolver::HasPayloadType
63
64
 
64
65
  class << self
65
66
  # Override this method to handle legacy-style usages of `MyMutation.field`
66
67
  def field(*args, &block)
67
- if args.none?
68
+ if args.empty?
68
69
  raise ArgumentError, "#{name}.field is used for adding fields to this mutation. Use `mutation: #{name}` to attach this mutation instead."
69
70
  else
70
71
  super
71
72
  end
72
73
  end
73
74
 
74
- # Call this method to get the derived return type of the mutation,
75
- # or use it as a configuration method to assign a return type
76
- # instead of generating one.
77
- # @param new_payload_type [Class, nil] If a type definition class is provided, it will be used as the return type of the mutation field
78
- # @return [Class] The object type which this mutation returns.
79
- def payload_type(new_payload_type = nil)
80
- if new_payload_type
81
- @payload_type = new_payload_type
82
- end
83
- @payload_type ||= generate_payload_type
84
- end
85
-
86
- alias :type :payload_type
87
- alias :type_expr :payload_type
88
-
89
- def field_class(new_class = nil)
90
- if new_class
91
- @field_class = new_class
92
- else
93
- @field_class || find_inherited_method(:field_class, GraphQL::Schema::Field)
94
- end
95
- end
96
-
97
- # An object class to use for deriving return types
98
- # @param new_class [Class, nil] Defaults to {GraphQL::Schema::Object}
99
- # @return [Class]
100
- def object_class(new_class = nil)
101
- if new_class
102
- @object_class = new_class
103
- end
104
- @object_class || (superclass.respond_to?(:object_class) ? superclass.object_class : GraphQL::Schema::Object)
105
- end
106
-
107
75
  def visible?(context)
108
76
  true
109
77
  end
110
78
 
111
79
  private
112
80
 
113
- # Build a subclass of {.object_class} based on `self`.
114
- # This value will be cached as `{.payload_type}`.
115
- # Override this hook to customize return type generation.
81
+ # Override this to attach self as `mutation`
116
82
  def generate_payload_type
117
- mutation_name = graphql_name
118
- mutation_fields = fields
119
- mutation_class = self
120
- Class.new(object_class) do
121
- graphql_name("#{mutation_name}Payload")
122
- description("Autogenerated return type of #{mutation_name}")
123
- mutation(mutation_class)
124
- mutation_fields.each do |name, f|
125
- field(name, field: f)
126
- end
127
- end
83
+ payload_class = super
84
+ payload_class.mutation(self)
85
+ payload_class
128
86
  end
129
87
  end
130
88
  end
@@ -24,10 +24,14 @@ module GraphQL
24
24
  def list?
25
25
  @of_type.list?
26
26
  end
27
-
27
+
28
28
  def to_type_signature
29
29
  "#{@of_type.to_type_signature}!"
30
30
  end
31
+
32
+ def inspect
33
+ "#<#{self.class.name} @of_type=#{@of_type.inspect}>"
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -35,19 +35,33 @@ module GraphQL
35
35
  # @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
36
36
  # @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
37
37
  def authorized_new(object, context)
38
- context.schema.after_lazy(authorized?(object, context)) do |is_authorized|
38
+ auth_val = begin
39
+ authorized?(object, context)
40
+ # rescue GraphQL::UnauthorizedError => err
41
+ # context.schema.unauthorized_object(err)
42
+ end
43
+
44
+ context.schema.after_lazy(auth_val) do |is_authorized|
39
45
  if is_authorized
40
46
  self.new(object, context)
41
47
  else
42
48
  # It failed the authorization check, so go to the schema's authorized object hook
43
49
  err = GraphQL::UnauthorizedError.new(object: object, type: self, context: context)
44
50
  # If a new value was returned, wrap that instead of the original value
45
- new_obj = context.schema.unauthorized_object(err)
46
- if new_obj
47
- self.new(new_obj, context)
51
+ begin
52
+ new_obj = context.schema.unauthorized_object(err)
53
+ if new_obj
54
+ self.new(new_obj, context)
55
+ else
56
+ nil
57
+ end
58
+ # rescue GraphQL::ExecutionError => err
59
+ # err
48
60
  end
49
61
  end
50
62
  end
63
+ # rescue GraphQL::ExecutionError => err
64
+ # err
51
65
  end
52
66
  end
53
67
 
@@ -89,7 +89,7 @@ module GraphQL
89
89
  end
90
90
 
91
91
  def print_type(type)
92
- node = @document_from_schema.build_object_type_node(type)
92
+ node = @document_from_schema.build_type_definition_node(type)
93
93
  print(node)
94
94
  end
95
95
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/types/string"
2
3
 
3
4
  module GraphQL
4
5
  class Schema
@@ -25,19 +26,51 @@ module GraphQL
25
26
  # Relay classic default:
26
27
  null(true)
27
28
 
28
- # Override {GraphQL::Schema::Mutation#resolve_mutation} to
29
+ # Override {GraphQL::Schema::Resolver#resolve_with_support} to
29
30
  # delete `client_mutation_id` from the kwargs.
30
- def resolve_mutation(**kwargs)
31
- # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
32
- kwargs.delete(:client_mutation_id)
33
- if kwargs.any?
34
- resolve(**kwargs)
31
+ def resolve_with_support(**inputs)
32
+ # Without the interpreter, the inputs are unwrapped by an instrumenter.
33
+ # But when using the interpreter, no instrumenters are applied.
34
+ if context.interpreter?
35
+ input = inputs[:input].to_h
36
+ # Transfer these from the top-level hash to the
37
+ # shortcutted `input:` object
38
+ self.class.extras.each do |ext|
39
+ input[ext] = inputs[ext]
40
+ end
35
41
  else
36
- resolve
42
+ input = inputs
43
+ end
44
+
45
+ if input
46
+ # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
47
+ input_kwargs = input.to_h
48
+ client_mutation_id = input_kwargs.delete(:client_mutation_id)
49
+ else
50
+ # Relay Classic Mutations with no `argument`s
51
+ # don't require `input:`
52
+ input_kwargs = {}
53
+ end
54
+
55
+ return_value = if input_kwargs.any?
56
+ super(input_kwargs)
57
+ else
58
+ super()
37
59
  end
38
- end
39
60
 
40
- resolve_method(:resolve_mutation)
61
+ # Again, this is done by an instrumenter when using non-interpreter execution.
62
+ if context.interpreter?
63
+ context.schema.after_lazy(return_value) do |return_hash|
64
+ # It might be an error
65
+ if return_hash.is_a?(Hash)
66
+ return_hash[:client_mutation_id] = client_mutation_id
67
+ end
68
+ return_hash
69
+ end
70
+ else
71
+ return_value
72
+ end
73
+ end
41
74
 
42
75
  class << self
43
76
  # The base class for generated input object types
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Resolver
6
+ # Adds `field(...)` helper to resolvers so that they can
7
+ # generate payload types.
8
+ #
9
+ # Or, an already-defined one can be attached with `payload_type(...)`.
10
+ module HasPayloadType
11
+ # Call this method to get the derived return type of the mutation,
12
+ # or use it as a configuration method to assign a return type
13
+ # instead of generating one.
14
+ # @param new_payload_type [Class, nil] If a type definition class is provided, it will be used as the return type of the mutation field
15
+ # @return [Class] The object type which this mutation returns.
16
+ def payload_type(new_payload_type = nil)
17
+ if new_payload_type
18
+ @payload_type = new_payload_type
19
+ end
20
+ @payload_type ||= generate_payload_type
21
+ end
22
+
23
+ alias :type :payload_type
24
+ alias :type_expr :payload_type
25
+
26
+ def field_class(new_class = nil)
27
+ if new_class
28
+ @field_class = new_class
29
+ else
30
+ @field_class || find_inherited_method(:field_class, GraphQL::Schema::Field)
31
+ end
32
+ end
33
+
34
+ # An object class to use for deriving return types
35
+ # @param new_class [Class, nil] Defaults to {GraphQL::Schema::Object}
36
+ # @return [Class]
37
+ def object_class(new_class = nil)
38
+ if new_class
39
+ @object_class = new_class
40
+ end
41
+ @object_class || (superclass.respond_to?(:object_class) ? superclass.object_class : GraphQL::Schema::Object)
42
+ end
43
+
44
+ private
45
+
46
+ # Build a subclass of {.object_class} based on `self`.
47
+ # This value will be cached as `{.payload_type}`.
48
+ # Override this hook to customize return type generation.
49
+ def generate_payload_type
50
+ resolver_name = graphql_name
51
+ resolver_fields = fields
52
+ Class.new(object_class) do
53
+ graphql_name("#{resolver_name}Payload")
54
+ description("Autogenerated return type of #{resolver_name}")
55
+ resolver_fields.each do |name, f|
56
+ # Reattach the already-defined field here
57
+ # (The field's `.owner` will still point to the mutation, not the object type, I think)
58
+ add_field(f)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end