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,82 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/analysis/ast/visitor"
3
+ require "graphql/analysis/ast/analyzer"
4
+ require "graphql/analysis/ast/field_usage"
5
+ require "graphql/analysis/ast/query_complexity"
6
+ require "graphql/analysis/ast/max_query_complexity"
7
+ require "graphql/analysis/ast/query_depth"
8
+ require "graphql/analysis/ast/max_query_depth"
9
+
10
+ # frozen_string_literal: true
11
+ module GraphQL
12
+ module Analysis
13
+ module AST
14
+ module_function
15
+
16
+ def use(schema_defn)
17
+ schema = schema_defn.target
18
+ schema.analysis_engine = GraphQL::Analysis::AST
19
+ end
20
+
21
+ # Analyze a multiplex, and all queries within.
22
+ # Multiplex analyzers are ran for all queries, keeping state.
23
+ # Query analyzers are ran per query, without carrying state between queries.
24
+ #
25
+ # @param multiplex [GraphQL::Execution::Multiplex]
26
+ # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
27
+ # @return [void]
28
+ def analyze_multiplex(multiplex, analyzers)
29
+ multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
30
+
31
+ multiplex.trace("analyze_multiplex", { multiplex: multiplex }) do
32
+ query_results = multiplex.queries.map do |query|
33
+ if query.valid?
34
+ analyze_query(
35
+ query,
36
+ query.analyzers,
37
+ multiplex_analyzers: multiplex_analyzers
38
+ )
39
+ else
40
+ []
41
+ end
42
+ end
43
+
44
+ multiplex_results = multiplex_analyzers.map(&:result)
45
+ multiplex_errors = analysis_errors(multiplex_results)
46
+
47
+ multiplex.queries.each_with_index do |query, idx|
48
+ query.analysis_errors = multiplex_errors + analysis_errors(query_results[idx])
49
+ end
50
+ end
51
+ nil
52
+ end
53
+
54
+ # @param query [GraphQL::Query]
55
+ # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
56
+ # @return [Array<Any>] Results from those analyzers
57
+ def analyze_query(query, analyzers, multiplex_analyzers: [])
58
+ query.trace("analyze_query", { query: query }) do
59
+ query_analyzers = analyzers
60
+ .map { |analyzer| analyzer.new(query) }
61
+ .select { |analyzer| analyzer.analyze? }
62
+
63
+ analyzers_to_run = query_analyzers + multiplex_analyzers
64
+ return [] unless analyzers_to_run.any?
65
+
66
+ visitor = GraphQL::Analysis::AST::Visitor.new(
67
+ query: query,
68
+ analyzers: analyzers_to_run
69
+ )
70
+
71
+ visitor.visit
72
+
73
+ query_analyzers.map(&:result)
74
+ end
75
+ end
76
+
77
+ def analysis_errors(results)
78
+ results.flatten.select { |r| r.is_a?(GraphQL::AnalysisError) }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/analysis/ast"
2
3
  require "graphql/analysis/max_query_complexity"
3
4
  require "graphql/analysis/max_query_depth"
4
5
  require "graphql/analysis/query_complexity"
@@ -89,6 +89,11 @@ module GraphQL
89
89
  @expose_as ||= (@as || @name).to_s
90
90
  end
91
91
 
92
+ # Backport this to support legacy-style directives
93
+ def keyword
94
+ @keyword ||= GraphQL::Schema::Member::BuildType.underscore(expose_as).to_sym
95
+ end
96
+
92
97
  # @param value [Object] The incoming value from variables or query string literal
93
98
  # @param ctx [GraphQL::Query::Context]
94
99
  # @return [Object] The prepared `value` for this argument or `value` itself if no `prepare` function exists.
@@ -20,6 +20,7 @@ module GraphQL
20
20
  end
21
21
  end
22
22
 
23
+ # @deprecated authorization at query runtime is generally a better idea.
23
24
  module Analyzer
24
25
  module_function
25
26
  def initial_value(query)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # Helpers for migrating in a backwards-compatibile way
3
+ # Helpers for migrating in a backwards-compatible way
4
4
  # @api private
5
5
  module BackwardsCompatibility
6
6
  module_function
@@ -187,7 +187,7 @@ module GraphQL
187
187
  resolve_related_type(type_arg.call)
188
188
  when String
189
189
  # Get a constant by this name
190
- Object.const_get(type_arg)
190
+ resolve_related_type(Object.const_get(type_arg))
191
191
  else
192
192
  if type_arg.respond_to?(:graphql_definition)
193
193
  type_arg.graphql_definition
@@ -49,8 +49,7 @@ module GraphQL
49
49
  end
50
50
 
51
51
  module TestMiddleware
52
- # TODO: Once deprecated `next_middleware` argument becomes unsupported, add `&` to the argument
53
- def self.call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
52
+ def self.call(parent_type, parent_object, field_definition, field_args, query_context, &next_middleware)
54
53
  query_context[:middleware_log] && query_context[:middleware_log] << field_definition.name
55
54
  next_middleware.call
56
55
  end
@@ -595,31 +595,27 @@ module GraphQL
595
595
 
596
596
  assert_equal 6, document.definitions.size
597
597
 
598
- schema_definition = document.definitions.shift
598
+ schema_definition, directive_definition, enum_type_definition, object_type_definition, input_object_type_definition, interface_type_definition = document.definitions
599
+
599
600
  assert_equal GraphQL::Language::Nodes::SchemaDefinition, schema_definition.class
600
601
 
601
- directive_definition = document.definitions.shift
602
602
  assert_equal GraphQL::Language::Nodes::DirectiveDefinition, directive_definition.class
603
603
  assert_equal 'This is a directive', directive_definition.description
604
604
 
605
- enum_type_definition = document.definitions.shift
606
605
  assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, enum_type_definition.class
607
606
  assert_equal "Multiline comment\n\nWith an enum", enum_type_definition.description
608
607
 
609
608
  assert_nil enum_type_definition.values[0].description
610
609
  assert_equal 'Not a creative color', enum_type_definition.values[1].description
611
610
 
612
- object_type_definition = document.definitions.shift
613
611
  assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, object_type_definition.class
614
612
  assert_equal 'Comment without preceding space', object_type_definition.description
615
613
  assert_equal 'And a field to boot', object_type_definition.fields[0].description
616
614
 
617
- input_object_type_definition = document.definitions.shift
618
615
  assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, input_object_type_definition.class
619
616
  assert_equal 'Comment for input object types', input_object_type_definition.description
620
617
  assert_equal 'Color of the car', input_object_type_definition.fields[0].description
621
618
 
622
- interface_type_definition = document.definitions.shift
623
619
  assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, interface_type_definition.class
624
620
  assert_equal 'Comment for interface definitions', interface_type_definition.description
625
621
  assert_equal 'Amount of wheels', interface_type_definition.fields[0].description
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Dig
4
+ # implemented using the old activesupport #dig instead of the ruby built-in
5
+ # so we can use some of the magic in Schema::InputObject and Query::Arguments
6
+ # to handle stringified/symbolized keys.
7
+ #
8
+ # @param args [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
9
+ # @return [Object]
10
+ def dig(own_key, *rest_keys)
11
+ val = self[own_key]
12
+ if val.nil? || rest_keys.empty?
13
+ val
14
+ else
15
+ val.dig(*rest_keys)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,8 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::IncludeDirective = GraphQL::Directive.define do
3
- name "include"
4
- description "Directs the executor to include this field or fragment only when the `if` argument is true."
5
- locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
6
- argument :if, !GraphQL::BOOLEAN_TYPE, 'Included when true.'
7
- default_directive true
8
- end
2
+ GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition
@@ -1,9 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::SkipDirective = GraphQL::Directive.define do
3
- name "skip"
4
- description "Directs the executor to skip this field or fragment when the `if` argument is true."
5
- locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
6
-
7
- argument :if, !GraphQL::BOOLEAN_TYPE, 'Skipped when true.'
8
- default_directive true
9
- end
2
+ GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition
@@ -14,7 +14,15 @@ module GraphQL
14
14
  attr_accessor :ast_node
15
15
  # @api private
16
16
  attr_writer :default_directive
17
- ensure_defined(:locations, :arguments, :name, :description, :default_directive?)
17
+ ensure_defined(:locations, :arguments, :graphql_name, :name, :description, :default_directive?)
18
+
19
+ # Future-compatible alias
20
+ # @see {GraphQL::SchemaMember}
21
+ alias :graphql_name :name
22
+
23
+ # Future-compatible alias
24
+ # @see {GraphQL::SchemaMember}
25
+ alias :graphql_definition :itself
18
26
 
19
27
  LOCATIONS = [
20
28
  QUERY = :QUERY,
@@ -84,6 +92,10 @@ module GraphQL
84
92
  def default_directive?
85
93
  @default_directive
86
94
  end
95
+
96
+ def inspect
97
+ "#<GraphQL::Directive #{name}>"
98
+ end
87
99
  end
88
100
  end
89
101
 
@@ -147,6 +147,10 @@ module GraphQL
147
147
  GraphQL::NameValidator.validate!(new_name)
148
148
  @name = new_name
149
149
  end
150
+
151
+ def graphql_name
152
+ name
153
+ end
150
154
  end
151
155
 
152
156
  class UnresolvedValueError < GraphQL::Error
@@ -165,6 +169,10 @@ module GraphQL
165
169
  def coerce_non_null_input(value_name, ctx)
166
170
  if @values_by_name.key?(value_name)
167
171
  @values_by_name.fetch(value_name).value
172
+ elsif match_by_value = @values_by_name.find { |k, v| v.value == value_name }
173
+ # this is for matching default values, which are "inputs", but they're
174
+ # the Ruby value, not the GraphQL string.
175
+ match_by_value[1].value
168
176
  else
169
177
  nil
170
178
  end
@@ -24,6 +24,23 @@ module GraphQL
24
24
  GraphQL::Execution::Flatten.call(query.context)
25
25
  end
26
26
 
27
+ def self.begin_multiplex(_multiplex)
28
+ end
29
+
30
+ def self.begin_query(query, _multiplex)
31
+ ExecutionFunctions.resolve_root_selection(query)
32
+ end
33
+
34
+ def self.finish_multiplex(results, multiplex)
35
+ ExecutionFunctions.lazy_resolve_root_selection(results, multiplex: multiplex)
36
+ end
37
+
38
+ def self.finish_query(query, _multiplex)
39
+ {
40
+ "data" => Execution::Flatten.call(query.context)
41
+ }
42
+ end
43
+
27
44
  # @api private
28
45
  module ExecutionFunctions
29
46
  module_function
@@ -142,11 +159,11 @@ module GraphQL
142
159
  # If the returned object is finished, continue to coerce
143
160
  # and resolve child fields
144
161
  def continue_or_wait(raw_value, field_type, field_ctx)
145
- if (lazy_method = field_ctx.schema.lazy_method_name(raw_value))
162
+ if field_ctx.schema.lazy?(raw_value)
146
163
  field_ctx.value = Execution::Lazy.new {
147
164
  inner_value = begin
148
165
  begin
149
- raw_value.public_send(lazy_method)
166
+ field_ctx.schema.sync_lazy(raw_value)
150
167
  rescue GraphQL::UnauthorizedError => err
151
168
  field_ctx.schema.unauthorized_object(err)
152
169
  end
@@ -179,7 +196,7 @@ module GraphQL
179
196
  if list_errors.any?
180
197
  list_errors.each do |error, index|
181
198
  error.ast_node = field_ctx.ast_node
182
- error.path = field_ctx.path + [index]
199
+ error.path = field_ctx.path + (field_ctx.type.list? ? [index] : [])
183
200
  query.context.errors.push(error)
184
201
  end
185
202
  end
@@ -264,20 +281,22 @@ module GraphQL
264
281
  )
265
282
  when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
266
283
  query = field_ctx.query
267
- resolved_type = field_type.resolve_type(value, field_ctx)
268
- possible_types = query.possible_types(field_type)
269
-
270
- if !possible_types.include?(resolved_type)
271
- parent_type = field_ctx.irep_node.owner_type
272
- type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
273
- field_ctx.schema.type_error(type_error, field_ctx)
274
- PROPAGATE_NULL
275
- else
276
- resolve_value(
277
- value,
278
- resolved_type,
279
- field_ctx,
280
- )
284
+ resolved_type_or_lazy = field_type.resolve_type(value, field_ctx)
285
+ query.schema.after_lazy(resolved_type_or_lazy) do |resolved_type|
286
+ possible_types = query.possible_types(field_type)
287
+
288
+ if !possible_types.include?(resolved_type)
289
+ parent_type = field_ctx.irep_node.owner_type
290
+ type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
291
+ field_ctx.schema.type_error(type_error, field_ctx)
292
+ PROPAGATE_NULL
293
+ else
294
+ resolve_value(
295
+ value,
296
+ resolved_type,
297
+ field_ctx,
298
+ )
299
+ end
281
300
  end
282
301
  else
283
302
  raise("Unknown type kind: #{field_type.kind}")
@@ -62,6 +62,8 @@ module GraphQL
62
62
  # if any before hooks raise an exception, quit calling before hooks,
63
63
  # but call the after hooks on anything that succeeded but also
64
64
  # raise the exception that came from the before hook.
65
+ rescue GraphQL::ExecutionError => err
66
+ object.context.errors << err
65
67
  rescue => e
66
68
  raise call_after_hooks(successful, object, after_hook_name, e)
67
69
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Execution
5
+ class Interpreter
6
+ class ExecutionErrors
7
+ def initialize(ctx, ast_node, path)
8
+ @context = ctx
9
+ @ast_node = ast_node
10
+ @path = path
11
+ end
12
+
13
+ def add(err_or_msg)
14
+ err = case err_or_msg
15
+ when String
16
+ GraphQL::ExecutionError.new(err_or_msg)
17
+ when GraphQL::ExecutionError
18
+ err_or_msg
19
+ else
20
+ raise ArgumentError, "expected String or GraphQL::ExecutionError, not #{err_or_msg.class} (#{err_or_msg.inspect})"
21
+ end
22
+ err.ast_node ||= @ast_node
23
+ err.path ||= @path
24
+ @context.add_error(err)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Execution
5
+ class Interpreter
6
+ # This response class handles `#write` by accumulating
7
+ # values into a Hash.
8
+ class HashResponse
9
+ def initialize
10
+ @result = {}
11
+ end
12
+
13
+ def final_value
14
+ @result
15
+ end
16
+
17
+ def inspect
18
+ "#<#{self.class.name} result=#{@result.inspect}>"
19
+ end
20
+
21
+ # Add `value` at `path`.
22
+ # @return [void]
23
+ def write(path, value)
24
+ if path.empty?
25
+ @result = value
26
+ elsif (write_target = @result)
27
+ i = 0
28
+ prefinal_steps = path.size - 1
29
+ # Use `while` to avoid a closure
30
+ while i < prefinal_steps
31
+ path_part = path[i]
32
+ i += 1
33
+ write_target = write_target[path_part]
34
+ end
35
+ path_part = path[i]
36
+ write_target[path_part] = value
37
+ else
38
+ # The response is completely nulled out
39
+ end
40
+
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Execution
5
+ class Interpreter
6
+ module Resolve
7
+ # Continue field results in `results` until there's nothing else to continue.
8
+ # @return [void]
9
+ def self.resolve_all(results)
10
+ while results.any?
11
+ results = resolve(results)
12
+ end
13
+ end
14
+
15
+ # After getting `results` back from an interpreter evaluation,
16
+ # continue it until you get a response-ready Ruby value.
17
+ #
18
+ # `results` is one level of _depth_ of a query or multiplex.
19
+ #
20
+ # Resolve all lazy values in that depth before moving on
21
+ # to the next level.
22
+ #
23
+ # It's assumed that the lazies will
24
+ # return {Lazy} instances if there's more work to be done,
25
+ # or return {Hash}/{Array} if the query should be continued.
26
+ #
27
+ # @param results [Array]
28
+ # @return [Array] Same size, filled with finished values
29
+ def self.resolve(results)
30
+ next_results = []
31
+
32
+ # Work through the queue until it's empty
33
+ while results.size > 0
34
+ result_value = results.shift
35
+
36
+ if result_value.is_a?(Lazy)
37
+ result_value = result_value.value
38
+ end
39
+
40
+ if result_value.is_a?(Lazy)
41
+ # Since this field returned another lazy,
42
+ # add it to the same queue
43
+ results << result_value
44
+ elsif result_value.is_a?(Hash)
45
+ # This is part of the next level, add it
46
+ next_results.concat(result_value.values)
47
+ elsif result_value.is_a?(Array)
48
+ # This is part of the next level, add it
49
+ next_results.concat(result_value)
50
+ end
51
+ end
52
+
53
+ next_results
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end