graphql 1.8.7 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -7,40 +7,58 @@ module Dummy
7
7
  GraphQL::Field.accepts_definitions(joins: GraphQL::Define.assign_metadata_key(:joins))
8
8
  GraphQL::BaseType.accepts_definitions(class_names: GraphQL::Define.assign_metadata_key(:class_names))
9
9
 
10
- LocalProductInterface = GraphQL::InterfaceType.define do
11
- name "LocalProduct"
12
- description "Something that comes from somewhere"
13
- field :origin, !types.String, "Place the thing comes from"
10
+ class BaseField < GraphQL::Schema::Field
11
+ accepts_definition :joins
14
12
  end
15
13
 
16
- EdibleInterface = GraphQL::InterfaceType.define do
17
- name "Edible"
18
- description "Something you can eat, yum"
19
- field :fatContent, !types.Float, "Percentage which is fat"
20
- field :origin, !types.String, "Place the edible comes from"
21
- field :selfAsEdible, EdibleInterface, resolve: ->(o, a, c) { o }
14
+ module BaseInterface
15
+ include GraphQL::Schema::Interface
22
16
  end
23
17
 
24
- EdibleAsMilkInterface = EdibleInterface.redefine do
25
- name "EdibleAsMilk"
26
- description "Milk :+1:"
27
- resolve_type ->(obj, ctx) { MilkType }
18
+ class BaseObject < GraphQL::Schema::Object
19
+ field_class BaseField
20
+ accepts_definition :class_names
28
21
  end
29
22
 
30
- AnimalProductInterface = GraphQL::InterfaceType.define do
31
- name "AnimalProduct"
32
- description "Comes from an animal, no joke"
33
- field :source, !DairyAnimalEnum, "Animal which produced this product"
23
+ class BaseUnion < GraphQL::Schema::Union
34
24
  end
35
25
 
36
- BeverageUnion = GraphQL::UnionType.define do
37
- name "Beverage"
38
- description "Something you can drink"
39
- possible_types [MilkType]
26
+ class BaseEnum < GraphQL::Schema::Enum
27
+ end
28
+
29
+ class BaseInputObject < GraphQL::Schema::InputObject
30
+ end
31
+
32
+ class BaseScalar < GraphQL::Schema::Scalar
33
+ end
34
+
35
+ module LocalProduct
36
+ include BaseInterface
37
+ description "Something that comes from somewhere"
38
+ field :origin, String, null: false,
39
+ description: "Place the thing comes from"
40
+ end
41
+
42
+ module Edible
43
+ include BaseInterface
44
+ description "Something you can eat, yum"
45
+ field :fat_content, Float, null: false, description: "Percentage which is fat"
46
+ field :origin, String, null: false, description: "Place the edible comes from"
47
+ field :self_as_edible, Edible, null: true
48
+ def self_as_edible
49
+ object
50
+ end
51
+ end
52
+
53
+ module EdibleAsMilk
54
+ include Edible
55
+ description "Milk :+1:"
56
+ def self.resolve_type(obj, ctx)
57
+ Milk
58
+ end
40
59
  end
41
60
 
42
- DairyAnimalEnum = GraphQL::EnumType.define do
43
- name "DairyAnimal"
61
+ class DairyAnimal < BaseEnum
44
62
  description "An animal which can yield milk"
45
63
  value("COW", "Animal with black and white spots", value: 1)
46
64
  value("DONKEY", "Animal with fur", value: :donkey)
@@ -50,433 +68,425 @@ module Dummy
50
68
  value("YAK", "Animal with long hair", deprecation_reason: "Out of fashion")
51
69
  end
52
70
 
53
- CheeseType = GraphQL::ObjectType.define do
54
- name "Cheese"
71
+ module AnimalProduct
72
+ include BaseInterface
73
+ description "Comes from an animal, no joke"
74
+ field :source, DairyAnimal, "Animal which produced this product", null: false
75
+ end
76
+
77
+ class Cheese < BaseObject
55
78
  class_names ["Cheese"]
56
79
  description "Cultured dairy product"
57
- interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
80
+ implements Edible
81
+ implements EdibleAsMilk
82
+ implements AnimalProduct
83
+ implements LocalProduct
58
84
 
59
- # Can have (name, type, desc)
60
- field :id, !types.Int, "Unique identifier"
61
- field :flavor, !types.String, "Kind of Cheese"
62
- field :origin, !types.String, "Place the cheese comes from"
85
+ field :id, Int, "Unique identifier", null: false
86
+ field :flavor, String, "Kind of Cheese", null: false
87
+ field :origin, String, "Place the cheese comes from", null: false
63
88
 
64
- field :source, !DairyAnimalEnum,
65
- "Animal which produced the milk for this cheese"
89
+ field :source, DairyAnimal,
90
+ "Animal which produced the milk for this cheese",
91
+ null: false
66
92
 
67
- # Or can define by block, `resolve ->` should override `property:`
68
- field :similarCheese, CheeseType, "Cheeses like this one", property: :this_should_be_overriden do
93
+ field :similar_cheese, Cheese, "Cheeses like this one", null: true do
69
94
  # metadata test
70
95
  joins [:cheeses, :milks]
71
- argument :source, !types[!DairyAnimalEnum]
72
- argument :nullableSource, types[!DairyAnimalEnum], default_value: [1]
73
- resolve ->(t, a, c) {
74
- # get the strings out:
75
- sources = a["source"]
76
- if sources.include?("YAK")
77
- raise NoSuchDairyError.new("No cheeses are made from Yak milk!")
78
- else
79
- CHEESES.values.find { |cheese| sources.include?(cheese.source) }
80
- end
81
- }
96
+ argument :source, [DairyAnimal], required: true
97
+ argument :nullableSource, [DairyAnimal], required: false, default_value: [1]
98
+ end
99
+
100
+ def similar_cheese(source:, nullable_source:)
101
+ # get the strings out:
102
+ sources = source
103
+ if sources.include?("YAK")
104
+ raise NoSuchDairyError.new("No cheeses are made from Yak milk!")
105
+ else
106
+ CHEESES.values.find { |cheese| sources.include?(cheese.source) }
107
+ end
82
108
  end
83
109
 
84
- field :nullableCheese, CheeseType, "Cheeses like this one" do
85
- argument :source, types[!DairyAnimalEnum]
86
- resolve ->(t, a, c) { raise("NotImplemented") }
110
+ field :nullable_cheese, Cheese, "Cheeses like this one", null: true do
111
+ argument :source, [DairyAnimal], required: false
87
112
  end
113
+ def nullable_cheese; raise("NotImplemented"); end
88
114
 
89
- field :deeplyNullableCheese, CheeseType, "Cheeses like this one" do
90
- argument :source, types[types[DairyAnimalEnum]]
91
- resolve ->(t, a, c) { raise("NotImplemented") }
115
+ field :deeply_nullable_cheese, Cheese, "Cheeses like this one", null: true do
116
+ argument :source, [[DairyAnimal, null: true], null: true], required: false
92
117
  end
118
+ def deeply_nullable_cheese; raise("NotImplemented"); end
93
119
 
94
120
  # Keywords can be used for definition methods
95
- field :fatContent,
96
- property: :fat_content,
97
- type: !GraphQL::FLOAT_TYPE,
121
+ field :fat_content,
122
+ type: GraphQL::FLOAT_TYPE,
123
+ null: false,
98
124
  description: "Percentage which is milkfat",
99
125
  deprecation_reason: "Diet fashion has changed"
100
126
  end
101
127
 
102
- MilkType = GraphQL::ObjectType.define do
103
- name "Milk"
128
+ class Milk < BaseObject
104
129
  description "Dairy beverage"
105
- interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
106
- field :id, !types.ID
107
- field :source, !DairyAnimalEnum, "Animal which produced this milk", hash_key: :source
108
- field :origin, !types.String, "Place the milk comes from"
109
- field :flavors, types[types.String], "Chocolate, Strawberry, etc" do
110
- argument :limit, types.Int
111
- resolve ->(milk, args, ctx) {
112
- args[:limit] ? milk.flavors.first(args.limit) : milk.flavors
113
- }
114
- end
115
- field :executionError do
116
- type GraphQL::STRING_TYPE
117
- resolve ->(t, a, c) { raise(GraphQL::ExecutionError, "There was an execution error") }
130
+ implements Edible
131
+ implements EdibleAsMilk
132
+ implements AnimalProduct
133
+ implements LocalProduct
134
+
135
+ field :id, ID, null: false
136
+ field :source, DairyAnimal, null: false, description: "Animal which produced this milk"
137
+ field :origin, String, null: false, description: "Place the milk comes from"
138
+ field :flavors, [String, null: true], null: true, description: "Chocolate, Strawberry, etc" do
139
+ argument :limit, Int, required: false
118
140
  end
119
141
 
120
- field :allDairy, -> { types[DairyProductUnion] } do
121
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
142
+ def flavors(limit: nil)
143
+ limit ? object.flavors.first(limit) : object.flavors
122
144
  end
145
+
146
+ field :execution_error, String, null: true
147
+ def execution_error; raise(GraphQL::ExecutionError, "There was an execution error"); end
148
+
149
+ field :all_dairy, ["Dummy::DairyProduct", null: true], null: true
150
+ def all_dairy; CHEESES.values + MILKS.values; end
123
151
  end
124
152
 
125
- SweetenerInterface = GraphQL::InterfaceType.define do
126
- name "Sweetener"
127
- field :sweetness, types.Int
153
+ class Beverage < BaseUnion
154
+ description "Something you can drink"
155
+ possible_types Milk
156
+ end
157
+
158
+ module Sweetener
159
+ include BaseInterface
160
+ field :sweetness, Integer, null: true
128
161
  end
129
162
 
130
163
  # No actual data; This type is an "orphan", only accessible through Interfaces
131
- HoneyType = GraphQL::ObjectType.define do
132
- name "Honey"
164
+ class Honey < BaseObject
133
165
  description "Sweet, dehydrated bee barf"
134
- field :flowerType, types.String, "What flower this honey came from"
135
- interfaces [EdibleInterface, AnimalProductInterface, SweetenerInterface]
166
+ field :flower_type, String, "What flower this honey came from", null: true
167
+ implements Edible
168
+ implements AnimalProduct
169
+ implements Sweetener
136
170
  end
137
171
 
138
- DairyType = GraphQL::ObjectType.define do
139
- name "Dairy"
172
+ class Dairy < BaseObject
140
173
  description "A farm where milk is harvested and cheese is produced"
141
- field :id, !types.ID
142
- field :cheese, CheeseType
143
- field :milks, types[MilkType]
174
+ field :id, ID, null: false
175
+ field :cheese, Cheese, null: true
176
+ field :milks, [Milk, null: true], null: true
144
177
  end
145
178
 
146
- MaybeNullType = GraphQL::ObjectType.define do
147
- name "MaybeNull"
179
+ class MaybeNull < BaseObject
148
180
  description "An object whose fields return nil"
149
- field :cheese, CheeseType
181
+ field :cheese, Cheese, null: true
150
182
  end
151
183
 
152
- TracingScalarType = GraphQL::ObjectType.define do
153
- name "TracingScalar"
184
+ class TracingScalar < BaseObject
154
185
  description "An object which has traced scalars"
155
186
 
156
- field :traceNil, types.Int
157
- field :traceFalse, types.Int, trace: false
158
- field :traceTrue, types.Int, trace: true
187
+ field :trace_nil, Integer, null: true
188
+ field :trace_false, Integer, null: true, trace: false
189
+ field :trace_true, Integer, null: true, trace: true
159
190
  end
160
191
 
161
- DairyProductUnion = GraphQL::UnionType.define do
162
- name "DairyProduct"
192
+ class DairyProduct < BaseUnion
163
193
  description "Kinds of food made from milk"
164
194
  # Test that these forms of declaration still work:
165
- possible_types ["Dummy::MilkType", -> { CheeseType }]
195
+ possible_types "Dummy::Milk", Cheese
166
196
  end
167
197
 
168
- CowType = GraphQL::ObjectType.define do
169
- name "Cow"
198
+ class Cow < BaseObject
170
199
  description "A bovine animal that produces milk"
171
- field :id, !types.ID
172
- field :name, types.String
173
- field :last_produced_dairy, DairyProductUnion
200
+ field :id, ID, null: false
201
+ field :name, String, null: true
202
+ field :last_produced_dairy, DairyProduct, null: true
174
203
 
175
- field :cantBeNullButIs do
176
- type !GraphQL::STRING_TYPE
177
- resolve ->(t, a, c) { nil }
178
- end
204
+ field :cant_be_null_but_is, String, null: false
205
+ def cant_be_null_but_is; nil; end
179
206
 
180
- field :cantBeNullButRaisesExecutionError do
181
- type !GraphQL::STRING_TYPE
182
- resolve ->(t, a, c) { raise GraphQL::ExecutionError, "BOOM" }
183
- end
207
+ field :cant_be_null_but_raises_execution_error, String, null: false
208
+ def cant_be_null_but_raises_execution_error; raise(GraphQL::ExecutionError, "BOOM"); end
184
209
  end
185
210
 
186
- GoatType = GraphQL::ObjectType.define do
187
- name "Goat"
211
+ class Goat < BaseObject
188
212
  description "An caprinae animal that produces milk"
189
- field :id, !types.ID
190
- field :name, types.String
191
- field :last_produced_dairy, DairyProductUnion
213
+ field :id, ID, null: false
214
+ field :name, String, null: true
215
+ field :last_produced_dairy, DairyProduct, null: true
192
216
  end
193
217
 
194
- AnimalUnion = GraphQL::UnionType.define do
195
- name "Animal"
218
+ class Animal < BaseUnion
196
219
  description "Species of living things"
197
- possible_types [CowType, GoatType]
220
+ possible_types Cow, Goat
198
221
  end
199
222
 
200
- AnimalAsCowUnion = GraphQL::UnionType.define do
201
- name "AnimalAsCow"
223
+ class AnimalAsCow < BaseUnion
202
224
  description "All animals go mooooo!"
203
- possible_types [CowType]
204
- resolve_type ->(obj, ctx) {
205
- CowType
206
- }
225
+ possible_types Cow
226
+ def self.resolve_type(obj, ctx)
227
+ Cow
228
+ end
207
229
  end
208
230
 
209
- ResourceOrderType = GraphQL::InputObjectType.define {
210
- name "ResourceOrderType"
231
+ class ResourceOrder < BaseInputObject
232
+ graphql_name "ResourceOrderType"
211
233
  description "Properties used to determine ordering"
212
234
 
213
- argument :direction, !types.String do
214
- description "ASC or DESC"
215
- end
216
- }
235
+ argument :direction, String, required: true, description: "ASC or DESC"
236
+ end
217
237
 
218
- DairyProductInputType = GraphQL::InputObjectType.define {
219
- name "DairyProductInput"
238
+ class DairyProductInput < BaseInputObject
220
239
  description "Properties for finding a dairy product"
221
- input_field :source, !DairyAnimalEnum do
222
- # ensure we can define description in block
223
- description "Where it came from"
224
- end
225
-
226
- input_field :originDairy, types.String, "Dairy which produced it", default_value: "Sugar Hollow Dairy"
240
+ argument :source, DairyAnimal, required: true, description: "Where it came from"
241
+ argument :origin_dairy, String, required: false, description: "Dairy which produced it", default_value: "Sugar Hollow Dairy"
242
+ argument :fat_content, Float, required: false, description: "How much fat it has", default_value: 0.3
243
+ argument :organic, Boolean, required: false, default_value: false
244
+ argument :order_by, ResourceOrder, required: false, default_value: { direction: "ASC" }, camelize: false
245
+ end
227
246
 
228
- input_field :fatContent, types.Float, "How much fat it has" do
229
- # ensure we can define default in block
230
- default_value 0.3
247
+ class DeepNonNull < BaseObject
248
+ field :non_null_int, Integer, null: false do
249
+ argument :returning, Integer, required: false
231
250
  end
232
-
233
- # ensure default can be false
234
- input_field :organic, types.Boolean, default_value: false
235
-
236
- input_field :order_by, -> { ResourceOrderType }, default_value: { direction: 'ASC' }
237
- }
238
-
239
- DeepNonNullType = GraphQL::ObjectType.define do
240
- name "DeepNonNull"
241
- field :nonNullInt, !types.Int do
242
- argument :returning, types.Int
243
- resolve ->(obj, args, ctx) { args.returning }
251
+ def non_null_int(returning: nil)
252
+ returning
244
253
  end
245
254
 
246
- field :deepNonNull, DeepNonNullType.to_non_null_type do
247
- resolve ->(obj, args, ctx) { :deepNonNull }
248
- end
255
+ field :deep_non_null, DeepNonNull, null: false
256
+ def deep_non_null; :deep_non_null; end
249
257
  end
250
258
 
251
- TimeType = GraphQL::ScalarType.define do
252
- name "Time"
259
+ class Time < BaseScalar
253
260
  description "Time since epoch in seconds"
254
261
 
255
- coerce_input ->(value, ctx) do
256
- begin
257
- Time.at(Float(value))
258
- rescue ArgumentError
259
- raise GraphQL::CoercionError, 'cannot coerce to Float'
260
- end
262
+ def self.coerce_input(value, ctx)
263
+ Time.at(Float(value))
264
+ rescue ArgumentError
265
+ raise GraphQL::CoercionError, 'cannot coerce to Float'
261
266
  end
262
267
 
263
- coerce_result ->(value, ctx) { value.to_f }
268
+ def self.coerce_result(value, ctx)
269
+ value.to_f
270
+ end
264
271
  end
265
272
 
266
- class FetchItem < GraphQL::Function
267
- attr_reader :type, :description, :arguments
273
+ class FetchItem < GraphQL::Schema::Resolver
274
+ class << self
275
+ attr_accessor :data
276
+ end
268
277
 
269
- def initialize(type:, data:, id_type: !GraphQL::INT_TYPE)
270
- @type = type
271
- @data = data
272
- @description = "Find a #{type.name} by id"
273
- @arguments = self.class.arguments.merge({"id" => GraphQL::Argument.define(name: "id", type: id_type)})
278
+ def self.build(type:, data:, id_type: "Int")
279
+ Class.new(self) do
280
+ self.data = data
281
+ type(type, null: true)
282
+ description("Find a #{type.name} by id")
283
+ argument :id, id_type, required: true
284
+ end
274
285
  end
275
286
 
276
- def call(obj, args, ctx)
277
- id_string = args["id"].to_s # Cheese has Int type, Milk has ID type :(
278
- _id, item = @data.find { |id, _item| id.to_s == id_string }
287
+ def resolve(id:)
288
+ id_string = id.to_s # Cheese has Int type, Milk has ID type :(
289
+ _id, item = self.class.data.find { |item_id, _item| item_id.to_s == id_string }
279
290
  item
280
291
  end
281
292
  end
282
293
 
283
- class GetSingleton < GraphQL::Function
284
- attr_reader :description, :type
294
+ class GetSingleton < GraphQL::Schema::Resolver
295
+ class << self
296
+ attr_accessor :data
297
+ end
285
298
 
286
- def initialize(type:, data:)
287
- @description = "Find the only #{type.name}"
288
- @type = type
289
- @data = data
299
+ def self.build(type:, data:)
300
+ Class.new(self) do
301
+ description("Find the only #{type.name}")
302
+ type(type, null: true)
303
+ self.data = data
304
+ end
290
305
  end
291
306
 
292
- def call(obj, args, ctx)
293
- @data
307
+ def resolve
308
+ self.class.data
294
309
  end
295
310
  end
296
311
 
297
- SourceFieldDefn = Proc.new {
298
- type GraphQL::ListType.new(of_type: CheeseType)
299
- description "Cheese from source"
300
- argument :source, DairyAnimalEnum, default_value: 1
301
- resolve ->(target, arguments, context) {
302
- CHEESES.values.select{ |c| c.source == arguments["source"] }
303
- }
304
- }
312
+ class DairyAppQuery < BaseObject
313
+ graphql_name "Query"
314
+ description "Query root of the system"
315
+ # Returns `root_value:`
316
+ field :root, String, null: true
317
+ def root
318
+ object
319
+ end
320
+ field :cheese, resolver: FetchItem.build(type: Cheese, data: CHEESES)
321
+ field :milk, resolver: FetchItem.build(type: Milk, data: MILKS, id_type: "ID")
322
+ field :dairy, resolver: GetSingleton.build(type: Dairy, data: DAIRY)
323
+ field :from_source, [Cheese, null: true], null: true, description: "Cheese from source" do
324
+ argument :source, DairyAnimal, required: false, default_value: 1
325
+ end
326
+ def from_source(source:)
327
+ CHEESES.values.select { |c| c.source == source }
328
+ end
305
329
 
306
- FavoriteFieldDefn = GraphQL::Field.define do
307
- name "favoriteEdible"
308
- description "My favorite food"
309
- type EdibleInterface
310
- resolve ->(t, a, c) { MILKS[1] }
311
- end
330
+ field :favorite_edible, Edible, null: true, description: "My favorite food"
331
+ def favorite_edible
332
+ MILKS[1]
333
+ end
312
334
 
313
- DairyAppQueryType = GraphQL::ObjectType.define do
314
- name "Query"
315
- description "Query root of the system"
316
- field :root, types.String do
317
- resolve ->(root_value, args, c) { root_value }
318
- end
319
- field :cheese, function: FetchItem.new(type: CheeseType, data: CHEESES)
320
- field :milk, function: FetchItem.new(type: MilkType, data: MILKS, id_type: !types.ID)
321
- field :dairy, function: GetSingleton.new(type: DairyType, data: DAIRY)
322
- field :fromSource, &SourceFieldDefn
323
- field :favoriteEdible, FavoriteFieldDefn
324
- field :cow, function: GetSingleton.new(type: CowType, data: COWS[1])
325
- field :searchDairy do
335
+ field :cow, resolver: GetSingleton.build(type: Cow, data: COWS[1])
336
+ field :search_dairy, DairyProduct, null: false do
326
337
  description "Find dairy products matching a description"
327
- type !DairyProductUnion
328
338
  # This is a list just for testing 😬
329
- argument :product, types[DairyProductInputType], default_value: [{"source" => "SHEEP"}]
330
- argument :expiresAfter, TimeType
331
- resolve ->(t, args, c) {
332
- source = args["product"][0][:source] # String or Sym is ok
333
- products = CHEESES.values + MILKS.values
334
- if !source.nil?
335
- products = products.select { |pr| pr.source == source }
336
- end
337
- products.first
338
- }
339
+ argument :product, [DairyProductInput, null: true], required: false, default_value: [{source: "SHEEP"}]
340
+ argument :expires_after, Time, required: false
339
341
  end
340
342
 
341
- field :allAnimal, !types[AnimalUnion] do
342
- resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
343
+ def search_dairy(product:, expires_after: nil)
344
+ source = product[0][:source]
345
+ products = CHEESES.values + MILKS.values
346
+ if !source.nil?
347
+ products = products.select { |pr| pr.source == source }
348
+ end
349
+ products.first
343
350
  end
344
351
 
345
- field :allAnimalAsCow, !types[AnimalAsCowUnion] do
346
- resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
352
+ field :all_animal, [Animal, null: true], null: false
353
+ def all_animal
354
+ COWS.values + GOATS.values
347
355
  end
348
356
 
349
- field :allDairy, types[DairyProductUnion] do
350
- argument :executionErrorAtIndex, types.Int
351
- resolve ->(obj, args, ctx) {
352
- result = CHEESES.values + MILKS.values
353
- result[args.executionErrorAtIndex] = GraphQL::ExecutionError.new("missing dairy") if args.executionErrorAtIndex
354
- result
355
- }
356
- end
357
+ field :all_animal_as_cow, [AnimalAsCow, null: true], null: false, resolver_method: :all_animal
357
358
 
358
- field :allEdible, types[EdibleInterface] do
359
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
359
+ field :all_dairy, [DairyProduct, null: true], null: true do
360
+ argument :execution_error_at_index, Integer, required: false
361
+ end
362
+ def all_dairy(execution_error_at_index: nil)
363
+ result = CHEESES.values + MILKS.values
364
+ if execution_error_at_index
365
+ result[execution_error_at_index] = GraphQL::ExecutionError.new("missing dairy")
366
+ end
367
+ result
360
368
  end
361
369
 
362
- field :allEdibleAsMilk, types[EdibleAsMilkInterface] do
363
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
370
+ field :all_edible, [Edible, null: true], null: true
371
+ def all_edible
372
+ CHEESES.values + MILKS.values
364
373
  end
365
374
 
366
- field :error do
367
- description "Raise an error"
368
- type GraphQL::STRING_TYPE
369
- resolve ->(t, a, c) { raise("This error was raised on purpose") }
375
+ field :all_edible_as_milk, [EdibleAsMilk, null: true], null: true, resolver_method: :all_edible
376
+
377
+ field :error, String, null: true, description: "Raise an error"
378
+ def error
379
+ raise("This error was raised on purpose")
370
380
  end
371
381
 
372
- field :executionError do
373
- type GraphQL::STRING_TYPE
374
- resolve ->(t, a, c) { raise(GraphQL::ExecutionError, "There was an execution error") }
382
+ field :execution_error, String, null: true
383
+ def execution_error
384
+ raise(GraphQL::ExecutionError, "There was an execution error")
375
385
  end
376
386
 
377
- field :valueWithExecutionError do
378
- type !GraphQL::INT_TYPE
379
- resolve ->(t, a, c) {
380
- c.add_error(GraphQL::ExecutionError.new("Could not fetch latest value"))
381
- return 0
382
- }
387
+ field :value_with_execution_error, Integer, null: false, extras: [:execution_errors]
388
+ def value_with_execution_error(execution_errors:)
389
+ execution_errors.add("Could not fetch latest value")
390
+ 0
383
391
  end
384
392
 
385
- field :multipleErrorsOnNonNullableField do
386
- type !GraphQL::STRING_TYPE
387
- resolve ->(t, a, c) {
388
- [GraphQL::ExecutionError.new("This is an error message for some error."),
389
- GraphQL::ExecutionError.new("This is another error message for a different error.")]
390
- }
393
+ field :multiple_errors_on_non_nullable_field, String, null: false
394
+ def multiple_errors_on_non_nullable_field
395
+ [
396
+ GraphQL::ExecutionError.new("This is an error message for some error."),
397
+ GraphQL::ExecutionError.new("This is another error message for a different error.")
398
+ ]
391
399
  end
392
400
 
393
- field :executionErrorWithOptions do
394
- type GraphQL::INT_TYPE
395
- resolve ->(t, a, c) {
396
- GraphQL::ExecutionError.new("Permission Denied!", options: { "code" => "permission_denied" })
397
- }
401
+ field :execution_error_with_options, Integer, null: true
402
+ def execution_error_with_options
403
+ GraphQL::ExecutionError.new("Permission Denied!", options: { "code" => "permission_denied" })
398
404
  end
399
405
 
400
- field :executionErrorWithExtensions do
401
- type GraphQL::INT_TYPE
402
- resolve ->(t, a, c) {
403
- GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
404
- }
406
+ field :execution_error_with_extensions, Integer, null: true
407
+ def execution_error_with_extensions
408
+ GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
405
409
  end
406
410
 
407
411
  # To test possibly-null fields
408
- field :maybeNull, MaybeNullType do
409
- resolve ->(t, a, c) { OpenStruct.new(cheese: nil) }
412
+ field :maybe_null, MaybeNull, null: true
413
+ def maybe_null
414
+ OpenStruct.new(cheese: nil)
410
415
  end
411
416
 
412
- field :tracingScalar, TracingScalarType do
413
- resolve ->(o, a, c) do
414
- OpenStruct.new(
415
- traceNil: 2,
416
- traceFalse: 3,
417
- tracetrue: 5,
418
- )
419
- end
417
+ field :tracing_scalar, TracingScalar, null: true
418
+ def tracing_scalar
419
+ OpenStruct.new(
420
+ trace_nil: 2,
421
+ trace_false: 3,
422
+ trace_true: 5,
423
+ )
420
424
  end
421
425
 
422
- field :deepNonNull, !DeepNonNullType do
423
- resolve ->(o, a, c) { :deepNonNull }
424
- end
426
+ field :deep_non_null, DeepNonNull, null: false
427
+ def deep_non_null; :deep_non_null; end
425
428
  end
426
429
 
427
430
  GLOBAL_VALUES = []
428
431
 
429
- ReplaceValuesInputType = GraphQL::InputObjectType.define do
430
- name "ReplaceValuesInput"
431
- input_field :values, !types[!types.Int]
432
+ class ReplaceValuesInput < BaseInputObject
433
+ argument :values, [Integer], required: true
432
434
  end
433
435
 
434
- PushValueField = GraphQL::Field.define do
435
- name :pushValue
436
- type !types[!types.Int]
437
- description("Push a value onto a global array :D")
438
- argument :value, !types.Int, as: :val
439
- resolve ->(o, args, ctx) {
440
- GLOBAL_VALUES << args.val
441
- GLOBAL_VALUES
442
- }
443
- end
444
-
445
- class DairyAppMutationType < GraphQL::Schema::Object
436
+ class DairyAppMutation < BaseObject
446
437
  graphql_name "Mutation"
447
438
  description "The root for mutations in this schema"
448
- # Test the `field:` compatibility option
449
- field :pushValue, field: PushValueField
439
+ field :push_value, [Integer], null: false, description: "Push a value onto a global array :D" do
440
+ argument :value, Integer, required: true, as: :val
441
+ end
442
+ def push_value(val:)
443
+ GLOBAL_VALUES << val
444
+ GLOBAL_VALUES
445
+ end
450
446
 
451
447
  field :replaceValues, [Integer], "Replace the global array with new values", null: false do
452
- argument :input, ReplaceValuesInputType, required: true
448
+ argument :input, ReplaceValuesInput, required: true
453
449
  end
454
450
 
455
451
  def replace_values(input:)
456
452
  GLOBAL_VALUES.clear
457
- GLOBAL_VALUES.concat(input["values"])
453
+ GLOBAL_VALUES.concat(input[:values])
458
454
  GLOBAL_VALUES
459
455
  end
460
456
  end
461
457
 
462
- SubscriptionType = GraphQL::ObjectType.define do
463
- name "Subscription"
464
- field :test, types.String do
465
- resolve ->(o, a, c) { "Test" }
466
- end
458
+ class Subscription < BaseObject
459
+ field :test, String, null: true
460
+ def test; "Test"; end
467
461
  end
468
462
 
469
463
  class Schema < GraphQL::Schema
470
- query DairyAppQueryType
471
- mutation DairyAppMutationType
472
- subscription SubscriptionType
464
+ query DairyAppQuery
465
+ mutation DairyAppMutation
466
+ subscription Subscription
473
467
  max_depth 5
474
- orphan_types [HoneyType, BeverageUnion]
468
+ # TODO why is `.graphql_definition` required here?
469
+ orphan_types Honey, Beverage.graphql_definition
475
470
 
476
471
  rescue_from(NoSuchDairyError) { |err| err.message }
477
472
 
478
473
  def self.resolve_type(type, obj, ctx)
479
474
  Schema.types[obj.class.name.split("::").last]
480
475
  end
476
+
477
+ # This is used to confirm that the hook is called:
478
+ MAGIC_INT_COERCE_VALUE = -1
479
+
480
+ def self.type_error(err, ctx)
481
+ if err.is_a?(GraphQL::IntegerEncodingError) && err.integer_value == 99**99
482
+ MAGIC_INT_COERCE_VALUE
483
+ else
484
+ super
485
+ end
486
+ end
487
+
488
+ if TESTING_INTERPRETER
489
+ use GraphQL::Execution::Interpreter
490
+ end
481
491
  end
482
492
  end