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
@@ -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