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
@@ -0,0 +1,485 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Execution::Interpreter do
5
+ module InterpreterTest
6
+ class Box
7
+ def initialize(value: nil, &block)
8
+ @value = value
9
+ @block = block
10
+ end
11
+
12
+ def value
13
+ if @block
14
+ @value = @block.call
15
+ @block = nil
16
+ end
17
+ @value
18
+ end
19
+ end
20
+
21
+ class Expansion < GraphQL::Schema::Object
22
+ field :sym, String, null: false
23
+ field :lazy_sym, String, null: false
24
+ field :name, String, null: false
25
+ field :cards, ["InterpreterTest::Card"], null: false
26
+
27
+ def self.authorized?(expansion, ctx)
28
+ if expansion.sym == "NOPE"
29
+ false
30
+ else
31
+ true
32
+ end
33
+ end
34
+
35
+ def cards
36
+ Query::CARDS.select { |c| c.expansion_sym == @object.sym }
37
+ end
38
+
39
+ def lazy_sym
40
+ Box.new(value: object.sym)
41
+ end
42
+
43
+ field :null_union_field_test, Integer, null: false
44
+ def null_union_field_test
45
+ 1
46
+ end
47
+ end
48
+
49
+ class Card < GraphQL::Schema::Object
50
+ field :name, String, null: false
51
+ field :colors, "[InterpreterTest::Color]", null: false
52
+ field :expansion, Expansion, null: false
53
+
54
+ def expansion
55
+ Query::EXPANSIONS.find { |e| e.sym == @object.expansion_sym }
56
+ end
57
+
58
+ field :null_union_field_test, Integer, null: true
59
+ def null_union_field_test
60
+ nil
61
+ end
62
+ end
63
+
64
+ class Color < GraphQL::Schema::Enum
65
+ value "WHITE"
66
+ value "BLUE"
67
+ value "BLACK"
68
+ value "RED"
69
+ value "GREEN"
70
+ end
71
+
72
+ class Entity < GraphQL::Schema::Union
73
+ possible_types Card, Expansion
74
+
75
+ def self.resolve_type(obj, ctx)
76
+ obj.sym ? Expansion : Card
77
+ end
78
+ end
79
+
80
+ class FieldCounter < GraphQL::Schema::Object
81
+ implements GraphQL::Types::Relay::Node
82
+
83
+ field :field_counter, FieldCounter, null: false
84
+ def field_counter; :field_counter; end
85
+
86
+ field :calls, Integer, null: false do
87
+ argument :expected, Integer, required: true
88
+ end
89
+
90
+ def calls(expected:)
91
+ c = context[:calls] += 1
92
+ if c != expected
93
+ raise "Expected #{expected} calls but had #{c} so far"
94
+ else
95
+ c
96
+ end
97
+ end
98
+
99
+ field :runtime_info, String, null: false
100
+ def runtime_info
101
+ "#{context.namespace(:interpreter)[:current_path]} -> #{context.namespace(:interpreter)[:current_field].path}"
102
+ end
103
+
104
+ field :lazy_runtime_info, String, null: false
105
+ def lazy_runtime_info
106
+ Box.new {
107
+ "#{context.namespace(:interpreter)[:current_path]} -> #{context.namespace(:interpreter)[:current_field].path}"
108
+ }
109
+ end
110
+ end
111
+
112
+ class Query < GraphQL::Schema::Object
113
+ # Try a root-level authorized hook that returns a lazy value
114
+ def self.authorized?(obj, ctx)
115
+ Box.new(value: true)
116
+ end
117
+
118
+ field :card, Card, null: true do
119
+ argument :name, String, required: true
120
+ end
121
+
122
+ def card(name:)
123
+ Box.new(value: CARDS.find { |c| c.name == name })
124
+ end
125
+
126
+ field :expansion, Expansion, null: true do
127
+ argument :sym, String, required: true
128
+ end
129
+
130
+ def expansion(sym:)
131
+ EXPANSIONS.find { |e| e.sym == sym }
132
+ end
133
+
134
+ field :expansions, [Expansion], null: false
135
+ def expansions
136
+ EXPANSIONS
137
+ end
138
+
139
+ CARDS = [
140
+ OpenStruct.new(name: "Dark Confidant", colors: ["BLACK"], expansion_sym: "RAV"),
141
+ ]
142
+
143
+ EXPANSIONS = [
144
+ OpenStruct.new(name: "Ravnica, City of Guilds", sym: "RAV"),
145
+ # This data has an error, for testing null propagation
146
+ OpenStruct.new(name: nil, sym: "XYZ"),
147
+ # This is not allowed by .authorized?,
148
+ OpenStruct.new(name: nil, sym: "NOPE"),
149
+ ]
150
+
151
+ field :find, [Entity], null: false do
152
+ argument :id, [ID], required: true
153
+ end
154
+
155
+ def find(id:)
156
+ id.map do |ent_id|
157
+ Query::EXPANSIONS.find { |e| e.sym == ent_id } ||
158
+ Query::CARDS.find { |c| c.name == ent_id }
159
+ end
160
+ end
161
+
162
+ field :findMany, [Entity, null: true], null: false do
163
+ argument :ids, [ID], required: true
164
+ end
165
+
166
+ def find_many(ids:)
167
+ find(id: ids).map { |e| Box.new(value: e) }
168
+ end
169
+
170
+ field :field_counter, FieldCounter, null: false
171
+ def field_counter; :field_counter; end
172
+
173
+ field :node, field: GraphQL::Relay::Node.field
174
+ field :nodes, field: GraphQL::Relay::Node.plural_field
175
+ end
176
+
177
+ class Counter < GraphQL::Schema::Object
178
+ field :value, Integer, null: false
179
+ field :lazy_value, Integer, null: false
180
+
181
+ def lazy_value
182
+ Box.new { object.value }
183
+ end
184
+
185
+ field :increment, Counter, null: false
186
+
187
+ def increment
188
+ object.value += 1
189
+ object
190
+ end
191
+ end
192
+
193
+
194
+ class Mutation < GraphQL::Schema::Object
195
+ field :increment_counter, Counter, null: false
196
+
197
+ def increment_counter
198
+ counter = context[:counter]
199
+ counter.value += 1
200
+ counter
201
+ end
202
+ end
203
+
204
+ class Schema < GraphQL::Schema
205
+ use GraphQL::Execution::Interpreter
206
+ use GraphQL::Analysis::AST
207
+ query(Query)
208
+ mutation(Mutation)
209
+ lazy_resolve(Box, :value)
210
+
211
+ def self.object_from_id(id, ctx)
212
+ OpenStruct.new(id: id)
213
+ end
214
+
215
+ def self.resolve_type(type, obj, ctx)
216
+ FieldCounter
217
+ end
218
+ end
219
+ end
220
+
221
+ it "runs a query" do
222
+ query_string = <<-GRAPHQL
223
+ query($expansion: String!, $id1: ID!, $id2: ID!){
224
+ card(name: "Dark Confidant") {
225
+ colors
226
+ expansion {
227
+ ... {
228
+ name
229
+ }
230
+ cards {
231
+ name
232
+ }
233
+ }
234
+ }
235
+ expansion(sym: $expansion) {
236
+ ... ExpansionFields
237
+ }
238
+ find(id: [$id1, $id2]) {
239
+ __typename
240
+ ... on Card {
241
+ name
242
+ }
243
+ ... on Expansion {
244
+ sym
245
+ }
246
+ }
247
+ }
248
+
249
+ fragment ExpansionFields on Expansion {
250
+ cards {
251
+ name
252
+ }
253
+ }
254
+ GRAPHQL
255
+
256
+ vars = {expansion: "RAV", id1: "Dark Confidant", id2: "RAV"}
257
+ result = InterpreterTest::Schema.execute(query_string, variables: vars)
258
+ assert_equal ["BLACK"], result["data"]["card"]["colors"]
259
+ assert_equal "Ravnica, City of Guilds", result["data"]["card"]["expansion"]["name"]
260
+ assert_equal [{"name" => "Dark Confidant"}], result["data"]["card"]["expansion"]["cards"]
261
+ assert_equal [{"name" => "Dark Confidant"}], result["data"]["expansion"]["cards"]
262
+ expected_abstract_list = [
263
+ {"__typename" => "Card", "name" => "Dark Confidant"},
264
+ {"__typename" => "Expansion", "sym" => "RAV"},
265
+ ]
266
+ assert_equal expected_abstract_list, result["data"]["find"]
267
+ end
268
+
269
+ it "runs mutation roots atomically and sequentially" do
270
+ query_str = <<-GRAPHQL
271
+ mutation {
272
+ i1: incrementCounter { value lazyValue
273
+ i2: increment { value lazyValue }
274
+ i3: increment { value lazyValue }
275
+ }
276
+ i4: incrementCounter { value lazyValue }
277
+ i5: incrementCounter { value lazyValue }
278
+ }
279
+ GRAPHQL
280
+
281
+ result = InterpreterTest::Schema.execute(query_str, context: { counter: OpenStruct.new(value: 0) })
282
+ expected_data = {
283
+ "i1" => {
284
+ "value" => 1,
285
+ # All of these get `3` as lazy value. They're resolved together,
286
+ # since they aren't _root_ mutation fields.
287
+ "lazyValue" => 3,
288
+ "i2" => { "value" => 2, "lazyValue" => 3 },
289
+ "i3" => { "value" => 3, "lazyValue" => 3 },
290
+ },
291
+ "i4" => { "value" => 4, "lazyValue" => 4},
292
+ "i5" => { "value" => 5, "lazyValue" => 5},
293
+ }
294
+ assert_equal expected_data, result["data"]
295
+ end
296
+
297
+ it "runs skip and include" do
298
+ query_str = <<-GRAPHQL
299
+ query($truthy: Boolean!, $falsey: Boolean!){
300
+ exp1: expansion(sym: "RAV") @skip(if: true) { name }
301
+ exp2: expansion(sym: "RAV") @skip(if: false) { name }
302
+ exp3: expansion(sym: "RAV") @include(if: true) { name }
303
+ exp4: expansion(sym: "RAV") @include(if: false) { name }
304
+ exp5: expansion(sym: "RAV") @include(if: $truthy) { name }
305
+ exp6: expansion(sym: "RAV") @include(if: $falsey) { name }
306
+ }
307
+ GRAPHQL
308
+
309
+ vars = {truthy: true, falsey: false}
310
+ result = InterpreterTest::Schema.execute(query_str, variables: vars)
311
+ expected_data = {
312
+ "exp2" => {"name" => "Ravnica, City of Guilds"},
313
+ "exp3" => {"name" => "Ravnica, City of Guilds"},
314
+ "exp5" => {"name" => "Ravnica, City of Guilds"},
315
+ }
316
+ assert_equal expected_data, result["data"]
317
+ end
318
+
319
+ describe "temporary interpreter flag" do
320
+ it "is set" do
321
+ # This can be removed later, just a sanity check during migration
322
+ res = InterpreterTest::Schema.execute("{ __typename }")
323
+ assert_equal true, res.context.interpreter?
324
+ end
325
+ end
326
+
327
+ describe "runtime info in context" do
328
+ it "is available" do
329
+ res = InterpreterTest::Schema.execute <<-GRAPHQL
330
+ {
331
+ fieldCounter {
332
+ runtimeInfo
333
+ fieldCounter {
334
+ runtimeInfo
335
+ lazyRuntimeInfo
336
+ }
337
+ }
338
+ }
339
+ GRAPHQL
340
+
341
+ assert_equal '["fieldCounter", "runtimeInfo"] -> FieldCounter.runtimeInfo', res["data"]["fieldCounter"]["runtimeInfo"]
342
+ assert_equal '["fieldCounter", "fieldCounter", "runtimeInfo"] -> FieldCounter.runtimeInfo', res["data"]["fieldCounter"]["fieldCounter"]["runtimeInfo"]
343
+ assert_equal '["fieldCounter", "fieldCounter", "lazyRuntimeInfo"] -> FieldCounter.lazyRuntimeInfo', res["data"]["fieldCounter"]["fieldCounter"]["lazyRuntimeInfo"]
344
+ end
345
+ end
346
+
347
+ describe "CI setup" do
348
+ it "sets interpreter based on a constant" do
349
+ # Force the plugins to be applied
350
+ Jazz::Schema.graphql_definition
351
+ Dummy::Schema.graphql_definition
352
+ if TESTING_INTERPRETER
353
+ assert_equal GraphQL::Execution::Interpreter, Jazz::Schema.query_execution_strategy
354
+ assert_equal GraphQL::Execution::Interpreter, Dummy::Schema.query_execution_strategy
355
+ else
356
+ refute_equal GraphQL::Execution::Interpreter, Jazz::Schema.query_execution_strategy
357
+ refute_equal GraphQL::Execution::Interpreter, Dummy::Schema.query_execution_strategy
358
+ end
359
+ end
360
+ end
361
+
362
+ describe "null propagation" do
363
+ it "propagates nulls" do
364
+ query_str = <<-GRAPHQL
365
+ {
366
+ expansion(sym: "XYZ") {
367
+ name
368
+ sym
369
+ lazySym
370
+ }
371
+ }
372
+ GRAPHQL
373
+
374
+ res = InterpreterTest::Schema.execute(query_str)
375
+ # Although the expansion was found, its name of `nil`
376
+ # propagated to here
377
+ assert_nil res["data"].fetch("expansion")
378
+ assert_equal ["Cannot return null for non-nullable field Expansion.name"], res["errors"].map { |e| e["message"] }
379
+ end
380
+
381
+ it "propagates nulls in lists" do
382
+ query_str = <<-GRAPHQL
383
+ {
384
+ expansions {
385
+ name
386
+ sym
387
+ lazySym
388
+ }
389
+ }
390
+ GRAPHQL
391
+
392
+ res = InterpreterTest::Schema.execute(query_str)
393
+ # A null in one of the list items removed the whole list
394
+ assert_nil(res["data"])
395
+ end
396
+
397
+ it "works with unions that fail .authorized?" do
398
+ res = InterpreterTest::Schema.execute <<-GRAPHQL
399
+ {
400
+ find(id: "NOPE") {
401
+ ... on Expansion {
402
+ sym
403
+ }
404
+ }
405
+ }
406
+ GRAPHQL
407
+ assert_equal ["Cannot return null for non-nullable field Query.find"], res["errors"].map { |e| e["message"] }
408
+ end
409
+
410
+ it "works with lists of unions" do
411
+ res = InterpreterTest::Schema.execute <<-GRAPHQL
412
+ {
413
+ findMany(ids: ["RAV", "NOPE", "BOGUS"]) {
414
+ ... on Expansion {
415
+ sym
416
+ }
417
+ }
418
+ }
419
+ GRAPHQL
420
+
421
+ assert_equal 3, res["data"]["findMany"].size
422
+ assert_equal "RAV", res["data"]["findMany"][0]["sym"]
423
+ assert_equal nil, res["data"]["findMany"][1]
424
+ assert_equal nil, res["data"]["findMany"][2]
425
+ assert_equal false, res.key?("errors")
426
+ end
427
+
428
+ it "works with union lists that have members of different kinds, with different nullabilities" do
429
+ res = InterpreterTest::Schema.execute <<-GRAPHQL
430
+ {
431
+ findMany(ids: ["RAV", "Dark Confidant"]) {
432
+ ... on Expansion {
433
+ nullUnionFieldTest
434
+ }
435
+ ... on Card {
436
+ nullUnionFieldTest
437
+ }
438
+ }
439
+ }
440
+ GRAPHQL
441
+
442
+ assert_equal [1, nil], res["data"]["findMany"].map { |f| f["nullUnionFieldTest"] }
443
+ end
444
+ end
445
+
446
+ describe "duplicated fields" do
447
+ it "doesn't run them multiple times" do
448
+ query_str = <<-GRAPHQL
449
+ {
450
+ fieldCounter {
451
+ calls(expected: 1)
452
+ # This should not be called since it matches the above
453
+ calls(expected: 1)
454
+ fieldCounter {
455
+ calls(expected: 2)
456
+ }
457
+ ...ExtraFields
458
+ }
459
+ }
460
+ fragment ExtraFields on FieldCounter {
461
+ fieldCounter {
462
+ # This should not be called since it matches the inline field:
463
+ calls(expected: 2)
464
+ # This _should_ be called
465
+ c3: calls(expected: 3)
466
+ }
467
+ }
468
+ GRAPHQL
469
+
470
+ # It will raise an error if it doesn't match the expectation
471
+ res = InterpreterTest::Schema.execute(query_str, context: { calls: 0 })
472
+ assert_equal 3, res["data"]["fieldCounter"]["fieldCounter"]["c3"]
473
+ end
474
+ end
475
+
476
+ describe "backwards compatibility" do
477
+ it "handles a legacy nodes field" do
478
+ res = InterpreterTest::Schema.execute('{ node(id: "abc") { id } }')
479
+ assert_equal "abc", res["data"]["node"]["id"]
480
+
481
+ res = InterpreterTest::Schema.execute('{ nodes(ids: ["abc", "xyz"]) { id } }')
482
+ assert_equal ["abc", "xyz"], res["data"]["nodes"].map { |n| n["id"] }
483
+ end
484
+ end
485
+ end
@@ -70,6 +70,55 @@ describe GraphQL::Execution::Lazy do
70
70
  assert_equal expected_data, res["data"]
71
71
  end
72
72
 
73
+ # This only works with the interpreter
74
+ if TESTING_INTERPRETER
75
+ [
76
+ [1, 2, LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK],
77
+ [2, LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK, 1],
78
+ [LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK, 1, 2],
79
+ ].each do |ordered_values|
80
+ it "resolves each field at one depth before proceeding to the next depth (using #{ordered_values})" do
81
+ res = run_query <<-GRAPHQL, variables: { values: ordered_values }
82
+ query($values: [Int!]!) {
83
+ listSum(values: $values) {
84
+ nestedSum(value: 3) {
85
+ value
86
+ }
87
+ }
88
+ }
89
+ GRAPHQL
90
+
91
+ # Even though magic number `44`'s `.authorized?` hook returns a lazy value,
92
+ # these fields should be resolved together and return the same value.
93
+ assert_equal 56, res["data"]["listSum"][0]["nestedSum"]["value"]
94
+ assert_equal 56, res["data"]["listSum"][1]["nestedSum"]["value"]
95
+ assert_equal 56, res["data"]["listSum"][2]["nestedSum"]["value"]
96
+ end
97
+ end
98
+
99
+ it "Handles fields that return nil" do
100
+ values = [
101
+ LazyHelpers::MAGIC_NUMBER_THAT_RETURNS_NIL,
102
+ LazyHelpers::MAGIC_NUMBER_WITH_LAZY_AUTHORIZED_HOOK,
103
+ 1,
104
+ 2,
105
+ ]
106
+
107
+ res = run_query <<-GRAPHQL, variables: { values: values }
108
+ query($values: [Int!]!) {
109
+ listSum(values: $values) {
110
+ nullableNestedSum(value: 3) {
111
+ value
112
+ }
113
+ }
114
+ }
115
+ GRAPHQL
116
+
117
+ values = res["data"]["listSum"].map { |s| s && s["nullableNestedSum"]["value"] }
118
+ assert_equal [nil, 56, 56, 56], values
119
+ end
120
+ end
121
+
73
122
  it "propagates nulls to the root" do
74
123
  res = run_query %|
75
124
  {
@@ -155,6 +204,23 @@ describe GraphQL::Execution::Lazy do
155
204
  end
156
205
  end
157
206
 
207
+ describe "Schema#sync_lazy(object)" do
208
+ it "Passes objects to that hook at runtime" do
209
+ res = run_query <<-GRAPHQL
210
+ {
211
+ a: nullableNestedSum(value: 1001) { value }
212
+ b: nullableNestedSum(value: 1013) { value }
213
+ c: nullableNestedSum(value: 1002) { value }
214
+ }
215
+ GRAPHQL
216
+
217
+ # This odd, non-adding behavior is hacked into `#sync_lazy`
218
+ assert_equal 101, res["data"]["a"]["value"]
219
+ assert_equal 113, res["data"]["b"]["value"]
220
+ assert_equal 102, res["data"]["c"]["value"]
221
+ end
222
+ end
223
+
158
224
  describe "LazyMethodMap" do
159
225
  class SubWrapper < LazyHelpers::Wrapper; end
160
226
 
@@ -165,7 +231,7 @@ describe GraphQL::Execution::Lazy do
165
231
  map.set(LazyHelpers::SumAll, :value)
166
232
  b = LazyHelpers::Wrapper.new(1)
167
233
  sub_b = LazyHelpers::Wrapper.new(2)
168
- s = LazyHelpers::SumAll.new({}, 3)
234
+ s = LazyHelpers::SumAll.new(3)
169
235
  assert_equal(:item, map.get(b))
170
236
  assert_equal(:item, map.get(sub_b))
171
237
  assert_equal(:value, map.get(s))