graphql 1.7.6 → 1.8.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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/install_generator.rb +14 -8
  4. data/lib/generators/graphql/loader_generator.rb +1 -1
  5. data/lib/generators/graphql/mutation_generator.rb +6 -1
  6. data/lib/generators/graphql/templates/function.erb +2 -2
  7. data/lib/generators/graphql/templates/loader.erb +2 -2
  8. data/lib/generators/graphql/templates/schema.erb +1 -1
  9. data/lib/graphql/argument.rb +25 -19
  10. data/lib/graphql/backtrace/tracer.rb +16 -22
  11. data/lib/graphql/backtrace.rb +1 -1
  12. data/lib/graphql/backwards_compatibility.rb +2 -3
  13. data/lib/graphql/base_type.rb +31 -31
  14. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +14 -0
  15. data/lib/graphql/compatibility/query_parser_specification.rb +117 -0
  16. data/lib/graphql/define/assign_object_field.rb +5 -12
  17. data/lib/graphql/deprecated_dsl.rb +42 -0
  18. data/lib/graphql/directive.rb +1 -0
  19. data/lib/graphql/enum_type.rb +3 -1
  20. data/lib/graphql/execution/execute.rb +21 -13
  21. data/lib/graphql/execution/instrumentation.rb +82 -0
  22. data/lib/graphql/execution/lazy/lazy_method_map.rb +1 -1
  23. data/lib/graphql/execution/lazy/resolve.rb +1 -3
  24. data/lib/graphql/execution/multiplex.rb +12 -29
  25. data/lib/graphql/execution.rb +1 -0
  26. data/lib/graphql/field.rb +21 -4
  27. data/lib/graphql/function.rb +14 -0
  28. data/lib/graphql/input_object_type.rb +3 -1
  29. data/lib/graphql/interface_type.rb +5 -3
  30. data/lib/graphql/internal_representation/node.rb +26 -14
  31. data/lib/graphql/internal_representation/visit.rb +3 -6
  32. data/lib/graphql/introspection/base_object.rb +16 -0
  33. data/lib/graphql/introspection/directive_location_enum.rb +11 -7
  34. data/lib/graphql/introspection/directive_type.rb +23 -16
  35. data/lib/graphql/introspection/dynamic_fields.rb +11 -0
  36. data/lib/graphql/introspection/entry_points.rb +29 -0
  37. data/lib/graphql/introspection/enum_value_type.rb +16 -11
  38. data/lib/graphql/introspection/field_type.rb +21 -12
  39. data/lib/graphql/introspection/input_value_type.rb +26 -23
  40. data/lib/graphql/introspection/schema_field.rb +7 -2
  41. data/lib/graphql/introspection/schema_type.rb +36 -22
  42. data/lib/graphql/introspection/type_by_name_field.rb +10 -2
  43. data/lib/graphql/introspection/type_kind_enum.rb +10 -6
  44. data/lib/graphql/introspection/type_type.rb +85 -23
  45. data/lib/graphql/introspection/typename_field.rb +1 -0
  46. data/lib/graphql/introspection.rb +3 -10
  47. data/lib/graphql/language/block_string.rb +47 -0
  48. data/lib/graphql/language/document_from_schema_definition.rb +280 -0
  49. data/lib/graphql/language/generation.rb +3 -182
  50. data/lib/graphql/language/lexer.rb +144 -69
  51. data/lib/graphql/language/lexer.rl +15 -4
  52. data/lib/graphql/language/nodes.rb +141 -78
  53. data/lib/graphql/language/parser.rb +677 -630
  54. data/lib/graphql/language/parser.y +18 -12
  55. data/lib/graphql/language/printer.rb +361 -0
  56. data/lib/graphql/language/token.rb +10 -3
  57. data/lib/graphql/language.rb +3 -0
  58. data/lib/graphql/non_null_type.rb +1 -1
  59. data/lib/graphql/object_type.rb +1 -6
  60. data/lib/graphql/query/arguments.rb +63 -32
  61. data/lib/graphql/query/context.rb +32 -2
  62. data/lib/graphql/query/literal_input.rb +4 -1
  63. data/lib/graphql/query/null_context.rb +1 -1
  64. data/lib/graphql/query/result.rb +1 -1
  65. data/lib/graphql/query/variables.rb +21 -3
  66. data/lib/graphql/query.rb +19 -6
  67. data/lib/graphql/railtie.rb +109 -0
  68. data/lib/graphql/relay/connection_resolve.rb +3 -0
  69. data/lib/graphql/relay/connection_type.rb +5 -3
  70. data/lib/graphql/relay/edge_type.rb +2 -1
  71. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  72. data/lib/graphql/relay/mongo_relation_connection.rb +40 -0
  73. data/lib/graphql/relay/mutation/instrumentation.rb +1 -1
  74. data/lib/graphql/relay/mutation/resolve.rb +5 -1
  75. data/lib/graphql/relay/relation_connection.rb +14 -19
  76. data/lib/graphql/relay/type_extensions.rb +30 -0
  77. data/lib/graphql/relay.rb +2 -0
  78. data/lib/graphql/scalar_type.rb +14 -2
  79. data/lib/graphql/schema/argument.rb +92 -0
  80. data/lib/graphql/schema/build_from_definition.rb +64 -18
  81. data/lib/graphql/schema/enum.rb +85 -0
  82. data/lib/graphql/schema/enum_value.rb +74 -0
  83. data/lib/graphql/schema/field.rb +372 -0
  84. data/lib/graphql/schema/finder.rb +153 -0
  85. data/lib/graphql/schema/input_object.rb +87 -0
  86. data/lib/graphql/schema/interface.rb +105 -0
  87. data/lib/graphql/schema/introspection_system.rb +93 -0
  88. data/lib/graphql/schema/late_bound_type.rb +32 -0
  89. data/lib/graphql/schema/list.rb +32 -0
  90. data/lib/graphql/schema/loader.rb +2 -2
  91. data/lib/graphql/schema/member/accepts_definition.rb +152 -0
  92. data/lib/graphql/schema/member/base_dsl_methods.rb +100 -0
  93. data/lib/graphql/schema/member/build_type.rb +137 -0
  94. data/lib/graphql/schema/member/cached_graphql_definition.rb +26 -0
  95. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  96. data/lib/graphql/schema/member/has_arguments.rb +50 -0
  97. data/lib/graphql/schema/member/has_fields.rb +130 -0
  98. data/lib/graphql/schema/member/instrumentation.rb +115 -0
  99. data/lib/graphql/schema/member/type_system_helpers.rb +34 -0
  100. data/lib/graphql/schema/member.rb +28 -0
  101. data/lib/graphql/schema/middleware_chain.rb +5 -1
  102. data/lib/graphql/schema/mutation.rb +138 -0
  103. data/lib/graphql/schema/non_null.rb +38 -0
  104. data/lib/graphql/schema/object.rb +81 -0
  105. data/lib/graphql/schema/printer.rb +33 -266
  106. data/lib/graphql/schema/relay_classic_mutation.rb +87 -0
  107. data/lib/graphql/schema/rescue_middleware.rb +8 -7
  108. data/lib/graphql/schema/resolver.rb +122 -0
  109. data/lib/graphql/schema/scalar.rb +35 -0
  110. data/lib/graphql/schema/traversal.rb +102 -22
  111. data/lib/graphql/schema/union.rb +36 -0
  112. data/lib/graphql/schema/validation.rb +3 -2
  113. data/lib/graphql/schema.rb +381 -12
  114. data/lib/graphql/static_validation/definition_dependencies.rb +1 -1
  115. data/lib/graphql/static_validation/literal_validator.rb +16 -4
  116. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
  117. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -1
  118. data/lib/graphql/static_validation/rules/fields_will_merge.rb +15 -8
  119. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +11 -1
  120. data/lib/graphql/static_validation/validation_context.rb +1 -1
  121. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -5
  122. data/lib/graphql/subscriptions/instrumentation.rb +5 -1
  123. data/lib/graphql/subscriptions/serialize.rb +2 -0
  124. data/lib/graphql/subscriptions.rb +90 -16
  125. data/lib/graphql/tracing/data_dog_tracing.rb +49 -0
  126. data/lib/graphql/tracing/new_relic_tracing.rb +26 -0
  127. data/lib/graphql/tracing/platform_tracing.rb +20 -7
  128. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  129. data/lib/graphql/tracing.rb +1 -0
  130. data/lib/graphql/unresolved_type_error.rb +3 -2
  131. data/lib/graphql/upgrader/member.rb +894 -0
  132. data/lib/graphql/upgrader/schema.rb +37 -0
  133. data/lib/graphql/version.rb +1 -1
  134. data/lib/graphql.rb +5 -25
  135. data/readme.md +2 -2
  136. data/spec/dummy/app/channels/graphql_channel.rb +23 -2
  137. data/spec/dummy/log/development.log +239 -0
  138. data/spec/dummy/log/test.log +410 -0
  139. data/spec/dummy/test/system/action_cable_subscription_test.rb +4 -0
  140. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-x/-xYZjAnuuzgR79fcznLTQtSdh6AARxu8FcQ_J6p7L3U.cache +0 -0
  141. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/13/13HiV12xyoQvT-1L39ZzLwMZxjyaGMiENmfw7f-QTIc.cache +0 -0
  142. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3W/3Wtf5pCWdqq0AB-iB0Y9uUNrTkruRxIEf1XFn_BETU0.cache +1 -0
  143. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5i/5iguGafb4hOn8262Kn8Q37ogNN9MxxQKGKNzHAzUcvI.cache +1 -0
  144. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8m/8mj2T6yy847Mc2Z7k3Xzh8O91hhVJt3NrPe8ASNDlIA.cache +1 -0
  145. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DT/DTQyMpr4ABZYQetsdRJ5A7S4jf1r3ie4FGOR7GZBNSs.cache +3 -0
  146. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Dq/DqJ5_yJPrP5iLlOQyTQsjAVI5FE5LCVDkED0f7GgsSo.cache +3 -0
  147. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +0 -0
  148. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +0 -0
  149. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rw/RwDuCV-XpnCtjNkvhpJfBuxXMk0b5AD3L9eR6M-wcy0.cache +3 -0
  150. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/UL/ULdjhhb0bRuqmaG7XSZlFYzGYCXTDnqZuJBTWRlzqgw.cache +0 -0
  151. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Up/UpPNgh0yYoUsyMDh5zWqe_U6qJIyTC6-dxMMAs1vvlM.cache +1 -0
  152. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wg/Wguh-szFGTI1gaL6npYwPekMXflugRei7F_mOyRucXg.cache +0 -0
  153. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/X-/X-khLYMA9mqFRPg3zAi86mREDxpKl4bdKYp3uF6WHos.cache +0 -0
  154. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bi/BIkdhfxsezxM4q-HZ4oCNTq97WEJTigcq0tpX2cDvbY.cache +0 -0
  155. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ff/FfxmA4CMHQZT7exx0G7NS1Wpcnny0vzp-Jhc2H36bp8.cache +1 -0
  156. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gE/gEiiG4GZNy_djEjK2pHm_NgA-gyhLZhdQvo0Yt96GqE.cache +0 -0
  157. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gn/gnA9ZSqpjccNL2m8pe_jBvY6SinXlCzXDWyop83Od8s.cache +1 -0
  158. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lO/lOAan3cMwCE_Hli6gsDML88xFNfn0nxPmvrSkW7eEOw.cache +1 -0
  159. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m1/M1pv8MJEPLXGLvS8QxVh3DSO9cI4mRt5FHFWdrvUj6o.cache +2 -0
  160. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m7/m77qH7ZqH0_0SmwJbiKGDd-aLau1Dav847DC6ge46zY.cache +1 -0
  161. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sj/sjRjnjRB37lH2vrgtkdJ8Cz84__IJ978IuKTM7HcztI.cache +0 -0
  162. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/um/um1JrirR4hJhK-1rE-HywlyCi5ibgxHVrReiujZBWJM.cache +1 -0
  163. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v4/v4fwVytD7ITcE0_GDbslZEYud8a5Okm85fV1o7SDl6g.cache +0 -0
  164. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v_/v_0PAQt0iipQjFP5zjgkkk9Stnpf4VzvnMv67d1Keuw.cache +1 -0
  165. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wd/wdT9U4MKxe1PyqNjVuCKMpCl3dxGCIRJIlwUTfh2DQU.cache +1 -0
  166. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xI/xIaxut_fEIhKBDqljTNwYaADK9kj3gG0ESrfHs-5_og.cache +3 -0
  167. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/y0/y0SJOqIx2fn1SKqOkAihsQow0trRJrSIyAswufVuoA8.cache +0 -0
  168. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zg/zgpzeaX-KZErHyGJ1aBH3ZusweNXMneVZule88XsIJI.cache +1 -0
  169. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zy/zYFltDy-8VC-uKq2BVEiJJyYXNFvVzAKuMlR3ZIYZsk.cache +0 -0
  170. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  171. data/spec/fixtures/upgrader/account.original.rb +19 -0
  172. data/spec/fixtures/upgrader/account.transformed.rb +20 -0
  173. data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
  174. data/spec/fixtures/upgrader/blame_range.transformed.rb +30 -0
  175. data/spec/fixtures/upgrader/date_time.original.rb +24 -0
  176. data/spec/fixtures/upgrader/date_time.transformed.rb +23 -0
  177. data/spec/fixtures/upgrader/delete_project.original.rb +28 -0
  178. data/spec/fixtures/upgrader/delete_project.transformed.rb +27 -0
  179. data/spec/fixtures/upgrader/gist_order_field.original.rb +14 -0
  180. data/spec/fixtures/upgrader/gist_order_field.transformed.rb +13 -0
  181. data/spec/fixtures/upgrader/increment_count.original.rb +59 -0
  182. data/spec/fixtures/upgrader/increment_count.transformed.rb +50 -0
  183. data/spec/fixtures/upgrader/photo.original.rb +10 -0
  184. data/spec/fixtures/upgrader/photo.transformed.rb +12 -0
  185. data/spec/fixtures/upgrader/release_order.original.rb +15 -0
  186. data/spec/fixtures/upgrader/release_order.transformed.rb +14 -0
  187. data/spec/fixtures/upgrader/starrable.original.rb +49 -0
  188. data/spec/fixtures/upgrader/starrable.transformed.rb +46 -0
  189. data/spec/fixtures/upgrader/subscribable.original.rb +55 -0
  190. data/spec/fixtures/upgrader/subscribable.transformed.rb +51 -0
  191. data/spec/fixtures/upgrader/type_x.original.rb +65 -0
  192. data/spec/fixtures/upgrader/type_x.transformed.rb +56 -0
  193. data/spec/generators/graphql/function_generator_spec.rb +26 -0
  194. data/spec/generators/graphql/install_generator_spec.rb +1 -1
  195. data/spec/generators/graphql/loader_generator_spec.rb +24 -0
  196. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  197. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  198. data/spec/graphql/argument_spec.rb +21 -0
  199. data/spec/graphql/backtrace_spec.rb +10 -0
  200. data/spec/graphql/base_type_spec.rb +42 -0
  201. data/spec/graphql/boolean_type_spec.rb +3 -3
  202. data/spec/graphql/directive_spec.rb +3 -1
  203. data/spec/graphql/enum_type_spec.rb +18 -5
  204. data/spec/graphql/execution/execute_spec.rb +4 -4
  205. data/spec/graphql/execution/instrumentation_spec.rb +165 -0
  206. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  207. data/spec/graphql/execution_error_spec.rb +18 -0
  208. data/spec/graphql/float_type_spec.rb +2 -2
  209. data/spec/graphql/id_type_spec.rb +1 -1
  210. data/spec/graphql/input_object_type_spec.rb +15 -2
  211. data/spec/graphql/int_type_spec.rb +2 -2
  212. data/spec/graphql/interface_type_spec.rb +12 -0
  213. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  214. data/spec/graphql/introspection/schema_type_spec.rb +2 -0
  215. data/spec/graphql/language/block_string_spec.rb +70 -0
  216. data/spec/graphql/language/document_from_schema_definition_spec.rb +770 -0
  217. data/spec/graphql/language/generation_spec.rb +21 -186
  218. data/spec/graphql/language/lexer_spec.rb +21 -1
  219. data/spec/graphql/language/nodes_spec.rb +21 -12
  220. data/spec/graphql/language/parser_spec.rb +1 -1
  221. data/spec/graphql/language/printer_spec.rb +203 -0
  222. data/spec/graphql/object_type_spec.rb +22 -0
  223. data/spec/graphql/query/arguments_spec.rb +25 -15
  224. data/spec/graphql/query/context_spec.rb +18 -0
  225. data/spec/graphql/query/executor_spec.rb +2 -1
  226. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -8
  227. data/spec/graphql/query/variables_spec.rb +42 -1
  228. data/spec/graphql/query_spec.rb +31 -5
  229. data/spec/graphql/rake_task_spec.rb +3 -1
  230. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  231. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  232. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  233. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  234. data/spec/graphql/relay/mongo_relation_connection_spec.rb +474 -0
  235. data/spec/graphql/relay/mutation_spec.rb +9 -7
  236. data/spec/graphql/relay/range_add_spec.rb +5 -1
  237. data/spec/graphql/relay/relation_connection_spec.rb +65 -1
  238. data/spec/graphql/schema/argument_spec.rb +87 -0
  239. data/spec/graphql/schema/build_from_definition_spec.rb +89 -5
  240. data/spec/graphql/schema/enum_spec.rb +74 -0
  241. data/spec/graphql/schema/field_spec.rb +225 -0
  242. data/spec/graphql/schema/finder_spec.rb +135 -0
  243. data/spec/graphql/schema/input_object_spec.rb +111 -0
  244. data/spec/graphql/schema/instrumentation_spec.rb +40 -0
  245. data/spec/graphql/schema/interface_spec.rb +185 -0
  246. data/spec/graphql/schema/introspection_system_spec.rb +39 -0
  247. data/spec/graphql/schema/member/accepts_definition_spec.rb +111 -0
  248. data/spec/graphql/schema/member/build_type_spec.rb +17 -0
  249. data/spec/graphql/schema/member/has_fields_spec.rb +129 -0
  250. data/spec/graphql/schema/member/type_system_helpers_spec.rb +63 -0
  251. data/spec/graphql/schema/mutation_spec.rb +148 -0
  252. data/spec/graphql/schema/object_spec.rb +175 -0
  253. data/spec/graphql/schema/printer_spec.rb +111 -15
  254. data/spec/graphql/schema/relay_classic_mutation_spec.rb +38 -0
  255. data/spec/graphql/schema/rescue_middleware_spec.rb +11 -0
  256. data/spec/graphql/schema/resolver_spec.rb +131 -0
  257. data/spec/graphql/schema/scalar_spec.rb +95 -0
  258. data/spec/graphql/schema/traversal_spec.rb +31 -0
  259. data/spec/graphql/schema/union_spec.rb +65 -0
  260. data/spec/graphql/schema/validation_spec.rb +1 -1
  261. data/spec/graphql/schema/warden_spec.rb +11 -11
  262. data/spec/graphql/schema_spec.rb +55 -12
  263. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -2
  264. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  265. data/spec/graphql/string_type_spec.rb +3 -3
  266. data/spec/graphql/subscriptions_spec.rb +273 -184
  267. data/spec/graphql/tracing/active_support_notifications_tracing_spec.rb +1 -1
  268. data/spec/graphql/tracing/new_relic_tracing_spec.rb +47 -0
  269. data/spec/graphql/tracing/platform_tracing_spec.rb +60 -1
  270. data/spec/graphql/union_type_spec.rb +1 -1
  271. data/spec/graphql/upgrader/member_spec.rb +516 -0
  272. data/spec/graphql/upgrader/schema_spec.rb +82 -0
  273. data/spec/spec_helper.rb +8 -0
  274. data/spec/support/dummy/schema.rb +53 -24
  275. data/spec/support/jazz.rb +544 -0
  276. data/spec/support/lazy_helpers.rb +21 -23
  277. data/spec/support/new_relic.rb +24 -0
  278. data/spec/support/star_trek/data.rb +109 -0
  279. data/spec/support/star_trek/schema.rb +388 -0
  280. data/spec/support/star_wars/data.rb +6 -7
  281. data/spec/support/star_wars/schema.rb +127 -171
  282. metadata +233 -11
  283. data/lib/graphql/introspection/arguments_field.rb +0 -7
  284. data/lib/graphql/introspection/enum_values_field.rb +0 -18
  285. data/lib/graphql/introspection/fields_field.rb +0 -13
  286. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  287. data/lib/graphql/introspection/interfaces_field.rb +0 -11
  288. data/lib/graphql/introspection/of_type_field.rb +0 -6
  289. data/lib/graphql/introspection/possible_types_field.rb +0 -11
@@ -25,36 +25,100 @@ module GraphQL
25
25
  Schema::BUILT_IN_INSTRUMENTERS +
26
26
  schema.instrumenters[:field_after_built_ins]
27
27
 
28
+ # These fields have types specified by _name_,
29
+ # So we need to inspect the schema and find those types,
30
+ # then update their references.
31
+ @late_bound_fields = []
28
32
  @type_map = {}
29
33
  @instrumented_field_map = Hash.new { |h, k| h[k] = {} }
30
34
  @type_reference_map = Hash.new { |h, k| h[k] = [] }
31
35
  @union_memberships = Hash.new { |h, k| h[k] = [] }
32
- visit(schema, nil)
36
+ visit(schema, schema, nil)
37
+ resolve_late_bound_fields
33
38
  end
34
39
 
35
40
  private
36
41
 
37
- def visit(member, context_description)
42
+ # A brute-force appraoch to late binding.
43
+ # Just keep trying the whole list, hoping that they
44
+ # eventually all resolve.
45
+ # This could be replaced with proper dependency tracking.
46
+ def resolve_late_bound_fields
47
+ # This is a bit tricky, with the writes going to internal state.
48
+ prev_late_bound_fields = @late_bound_fields
49
+ # Things might get added here during `visit...`
50
+ # or they might be added manually if we can't find them by hand
51
+ @late_bound_fields = []
52
+ prev_late_bound_fields.each do |(owner_type, field_defn, dynamic_field)|
53
+ if @type_map.key?(field_defn.type.unwrap.name)
54
+ late_bound_return_type = field_defn.type
55
+ resolved_type = @type_map.fetch(late_bound_return_type.unwrap.name)
56
+ wrapped_resolved_type = rewrap_resolved_type(late_bound_return_type, resolved_type)
57
+ # Update the field definition in place? :thinking_face:
58
+ field_defn.type = wrapped_resolved_type
59
+ visit_field_on_type(@schema, owner_type, field_defn, dynamic_field: dynamic_field)
60
+ else
61
+ @late_bound_fields << [owner_type, field_defn, dynamic_field]
62
+ end
63
+ end
64
+
65
+ if @late_bound_fields.any?
66
+ # If we visited each field and failed to resolve _any_,
67
+ # then we're stuck.
68
+ if @late_bound_fields == prev_late_bound_fields
69
+ type_names = prev_late_bound_fields.map { |f| f[1] }.map(&:type).map(&:unwrap).map(&:name).uniq
70
+ raise <<-ERR
71
+ Some late-bound types couldn't be resolved:
72
+
73
+ - #{type_names}
74
+ - Found __* types: #{@type_map.keys.select { |k| k.start_with?("__") }}
75
+ ERR
76
+ else
77
+ resolve_late_bound_fields
78
+ end
79
+ end
80
+ end
81
+
82
+ # The late-bound type may be wrapped with list or non-null types.
83
+ # Apply the same wrapping to the resolve type and
84
+ # return the maybe-wrapped type
85
+ def rewrap_resolved_type(late_bound_type, resolved_inner_type)
86
+ case late_bound_type
87
+ when GraphQL::NonNullType
88
+ rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_non_null_type
89
+ when GraphQL::ListType
90
+ rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_list_type
91
+ when GraphQL::Schema::LateBoundType
92
+ resolved_inner_type
93
+ else
94
+ raise "Unexpected late_bound_type: #{late_bound_type.inspect} (#{late_bound_type.class})"
95
+ end
96
+ end
97
+
98
+ def visit(schema, member, context_description)
38
99
  case member
39
100
  when GraphQL::Schema
40
- member.directives.each { |name, directive| visit(directive, "Directive #{name}") }
101
+ member.directives.each { |name, directive| visit(schema, directive, "Directive #{name}") }
41
102
  # Find the starting points, then visit them
42
103
  visit_roots = [member.query, member.mutation, member.subscription]
43
104
  if @introspection
44
- visit_roots << GraphQL::Introspection::SchemaType
105
+ introspection_types = schema.introspection_system.object_types
106
+ visit_roots.concat(introspection_types)
45
107
  if member.query
46
- # Visit this so that arguments class is preconstructed
47
- # Skip validation since it begins with __
48
- visit_field_on_type(member.query, GraphQL::Introspection::TypeByNameField, dynamic_field: true)
108
+ member.introspection_system.entry_points.each do |introspection_field|
109
+ # Visit this so that arguments class is preconstructed
110
+ # Skip validation since it begins with "__"
111
+ visit_field_on_type(schema, member.query, introspection_field, dynamic_field: true)
112
+ end
49
113
  end
50
114
  end
51
115
  visit_roots.concat(member.orphan_types)
52
116
  visit_roots.compact!
53
- visit_roots.each { |t| visit(t, t.name) }
117
+ visit_roots.each { |t| visit(schema, t, t.name) }
54
118
  when GraphQL::Directive
55
119
  member.arguments.each do |name, argument|
56
120
  @type_reference_map[argument.type.unwrap.to_s] << argument
57
- visit(argument.type, "Directive argument #{member.name}.#{name}")
121
+ visit(schema, argument.type, "Directive argument #{member.name}.#{name}")
58
122
  end
59
123
  # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
60
124
  # to be passed to a resolver proc
@@ -68,28 +132,40 @@ module GraphQL
68
132
  @type_map[type_defn.name] = type_defn
69
133
  case type_defn
70
134
  when GraphQL::ObjectType
71
- type_defn.interfaces.each { |i| visit(i, "Interface on #{type_defn.name}") }
72
- visit_fields(type_defn)
135
+ type_defn.interfaces.each { |i| visit(schema, i, "Interface on #{type_defn.name}") }
136
+ visit_fields(schema, type_defn)
73
137
  when GraphQL::InterfaceType
74
- visit_fields(type_defn)
138
+ visit_fields(schema, type_defn)
139
+ type_defn.orphan_types.each do |t|
140
+ visit(schema, t, "Orphan type for #{type_defn.name}")
141
+ end
75
142
  when GraphQL::UnionType
76
143
  type_defn.possible_types.each do |t|
77
144
  @union_memberships[t.name] << type_defn
78
- visit(t, "Possible type for #{type_defn.name}")
145
+ visit(schema, t, "Possible type for #{type_defn.name}")
79
146
  end
80
147
  when GraphQL::InputObjectType
81
148
  type_defn.arguments.each do |name, arg|
82
149
  @type_reference_map[arg.type.unwrap.to_s] << arg
83
- visit(arg.type, "Input field #{type_defn.name}.#{name}")
150
+ visit(schema, arg.type, "Input field #{type_defn.name}.#{name}")
84
151
  end
85
152
 
86
153
  # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
87
154
  # to be passed to a resolver proc
88
- GraphQL::Query::Arguments.construct_arguments_class(type_defn)
155
+ if type_defn.arguments_class.nil?
156
+ GraphQL::Query::Arguments.construct_arguments_class(type_defn)
157
+ end
89
158
  end
90
159
  elsif !prev_type.equal?(type_defn)
91
160
  # If the previous entry in the map isn't the same object we just found, raise.
92
- raise("Duplicate type definition found for name '#{type_defn.name}'")
161
+ raise("Duplicate type definition found for name '#{type_defn.name}' (#{prev_type.metadata[:type_class]}, #{type_defn.metadata[:type_class]}})")
162
+ end
163
+ when Class
164
+ if member.respond_to?(:graphql_definition)
165
+ graphql_member = member.graphql_definition
166
+ visit(schema, graphql_member, context_description)
167
+ else
168
+ raise GraphQL::Schema::InvalidTypeError.new("Unexpected traversal member: #{member} (#{member.class.name})")
93
169
  end
94
170
  else
95
171
  message = "Unexpected schema traversal member: #{member} (#{member.class.name})"
@@ -97,13 +173,18 @@ module GraphQL
97
173
  end
98
174
  end
99
175
 
100
- def visit_fields(type_defn)
176
+ def visit_fields(schema, type_defn)
101
177
  type_defn.all_fields.each do |field_defn|
102
- visit_field_on_type(type_defn, field_defn)
178
+ visit_field_on_type(schema, type_defn, field_defn)
103
179
  end
104
180
  end
105
181
 
106
- def visit_field_on_type(type_defn, field_defn, dynamic_field: false)
182
+ def visit_field_on_type(schema, type_defn, field_defn, dynamic_field: false)
183
+ base_return_type = field_defn.type.unwrap
184
+ if base_return_type.is_a?(GraphQL::Schema::LateBoundType)
185
+ @late_bound_fields << [type_defn, field_defn, dynamic_field]
186
+ return
187
+ end
107
188
  if dynamic_field
108
189
  # Don't apply instrumentation to dynamic fields since they're shared constants
109
190
  instrumented_field_defn = field_defn
@@ -114,11 +195,10 @@ module GraphQL
114
195
  @instrumented_field_map[type_defn.name][instrumented_field_defn.name] = instrumented_field_defn
115
196
  end
116
197
  @type_reference_map[instrumented_field_defn.type.unwrap.name] << instrumented_field_defn
117
- visit(instrumented_field_defn.type, "Field #{type_defn.name}.#{instrumented_field_defn.name}'s return type")
118
-
198
+ visit(schema, instrumented_field_defn.type, "Field #{type_defn.name}.#{instrumented_field_defn.name}'s return type")
119
199
  instrumented_field_defn.arguments.each do |name, arg|
120
200
  @type_reference_map[arg.type.unwrap.to_s] << arg
121
- visit(arg.type, "Argument #{name} on #{type_defn.name}.#{instrumented_field_defn.name}")
201
+ visit(schema, arg.type, "Argument #{name} on #{type_defn.name}.#{instrumented_field_defn.name}")
122
202
  end
123
203
 
124
204
  # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Union < GraphQL::Schema::Member
5
+ extend GraphQL::Schema::Member::AcceptsDefinition
6
+
7
+ class << self
8
+ def possible_types(*types)
9
+ if types.any?
10
+ @possible_types = types
11
+ else
12
+ all_possible_types = @possible_types || []
13
+ all_possible_types += super if defined?(super)
14
+ all_possible_types.uniq
15
+ end
16
+ end
17
+
18
+ def to_graphql
19
+ type_defn = GraphQL::UnionType.new
20
+ type_defn.name = graphql_name
21
+ type_defn.description = description
22
+ type_defn.possible_types = possible_types
23
+ if respond_to?(:resolve_type)
24
+ type_defn.resolve_type = method(:resolve_type)
25
+ end
26
+ type_defn.metadata[:type_class] = self
27
+ type_defn
28
+ end
29
+
30
+ def kind
31
+ GraphQL::TypeKinds::UNION
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -24,7 +24,8 @@ module GraphQL
24
24
  # @param allowed_classes [Class] Classes which the return value may be an instance of
25
25
  # @return [Proc] A proc which will validate the input by calling `property_name` and asserting it is an instance of one of `allowed_classes`
26
26
  def self.assert_property(property_name, *allowed_classes)
27
- allowed_classes_message = allowed_classes.map(&:name).join(" or ")
27
+ # Hide LateBoundType from user-facing errors
28
+ allowed_classes_message = allowed_classes.map(&:name).reject {|n| n.include?("LateBoundType") }.join(" or ")
28
29
  ->(obj) {
29
30
  property_value = obj.public_send(property_name)
30
31
  is_valid_value = allowed_classes.any? { |allowed_class| property_value.is_a?(allowed_class) }
@@ -240,7 +241,7 @@ module GraphQL
240
241
  Rules::RESERVED_NAME,
241
242
  Rules::DESCRIPTION_IS_STRING_OR_NIL,
242
243
  Rules.assert_property(:deprecation_reason, String, NilClass),
243
- Rules.assert_property(:type, GraphQL::BaseType),
244
+ Rules.assert_property(:type, GraphQL::BaseType, GraphQL::Schema::LateBoundType),
244
245
  Rules.assert_property(:property, Symbol, NilClass),
245
246
  Rules::ARGUMENTS_ARE_STRING_TO_ARGUMENT,
246
247
  Rules::ARGUMENTS_ARE_VALID,