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
@@ -39,7 +39,7 @@ module GraphQL
39
39
  # })
40
40
  #
41
41
  # payload = {
42
- # result: result.subscription? ? nil : result.to_h,
42
+ # result: result.subscription? ? {data: nil} : result.to_h,
43
43
  # more: result.subscription?,
44
44
  # }
45
45
  #
@@ -62,19 +62,21 @@ module GraphQL
62
62
  class ActionCableSubscriptions < GraphQL::Subscriptions
63
63
  SUBSCRIPTION_PREFIX = "graphql-subscription:"
64
64
  EVENT_PREFIX = "graphql-event:"
65
- def initialize(**rest)
65
+
66
+ # @param serializer [<#dump(obj), #load(string)] Used for serializing messages before handing them to `.broadcast(msg)`
67
+ def initialize(serializer: Serialize, **rest)
66
68
  # A per-process map of subscriptions to deliver.
67
69
  # This is provided by Rails, so let's use it
68
70
  @subscriptions = Concurrent::Map.new
71
+ @serializer = serializer
69
72
  super
70
73
  end
71
74
 
72
75
  # An event was triggered; Push the data over ActionCable.
73
76
  # Subscribers will re-evaluate locally.
74
- # TODO: this method name is a smell
75
77
  def execute_all(event, object)
76
78
  stream = EVENT_PREFIX + event.topic
77
- message = Serialize.dump(object)
79
+ message = @serializer.dump(object)
78
80
  ActionCable.server.broadcast(stream, message)
79
81
  end
80
82
 
@@ -97,7 +99,7 @@ module GraphQL
97
99
  @subscriptions[subscription_id] = query
98
100
  events.each do |event|
99
101
  channel.stream_from(EVENT_PREFIX + event.topic, coder: ActiveSupport::JSON) do |message|
100
- execute(subscription_id, event, Serialize.load(message))
102
+ execute(subscription_id, event, @serializer.load(message))
101
103
  nil
102
104
  end
103
105
  end
@@ -56,7 +56,11 @@ module GraphQL
56
56
  ctx.skip
57
57
  elsif ctx.irep_node.subscription_topic == ctx.query.subscription_topic
58
58
  # The root object is _already_ the subscription update:
59
- obj
59
+ if obj.is_a?(GraphQL::Schema::Object)
60
+ obj.object
61
+ else
62
+ obj
63
+ end
60
64
  else
61
65
  # This is a subscription update, but this event wasn't triggered.
62
66
  ctx.skip
@@ -35,6 +35,8 @@ module GraphQL
35
35
  obj.map { |i| dump_recursive(i) }.join(':')
36
36
  when obj.is_a?(Hash)
37
37
  obj.map { |k, v| "#{dump_recursive(k)}:#{dump_recursive(v)}" }.join(":")
38
+ when obj.is_a?(GraphQL::Schema::InputObject)
39
+ dump_recursive(obj.to_h)
38
40
  when obj.respond_to?(:to_gid_param)
39
41
  obj.to_gid_param
40
42
  when obj.respond_to?(:to_param)
@@ -9,6 +9,13 @@ end
9
9
 
10
10
  module GraphQL
11
11
  class Subscriptions
12
+ # Raised when either:
13
+ # - the triggered `event_name` doesn't match a field in the schema; or
14
+ # - one or more arguments don't match the field arguments
15
+ class InvalidTriggerError < GraphQL::Error
16
+ end
17
+
18
+ # @see {Subscriptions#initialize} for options, concrete implementations may add options.
12
19
  def self.use(defn, options = {})
13
20
  schema = defn.target
14
21
  options[:schema] = schema
@@ -19,8 +26,9 @@ module GraphQL
19
26
  nil
20
27
  end
21
28
 
22
- def initialize(kwargs)
23
- @schema = kwargs[:schema]
29
+ # @param schema [Class] the GraphQL schema this manager belongs to
30
+ def initialize(schema:, **rest)
31
+ @schema = schema
24
32
  end
25
33
 
26
34
  # Fetch subscriptions matching this field + arguments pair
@@ -31,31 +39,35 @@ module GraphQL
31
39
  # @param scope [Symbol, String]
32
40
  # @return [void]
33
41
  def trigger(event_name, args, object, scope: nil)
42
+ event_name = event_name.to_s
43
+
44
+ # Try with the verbatim input first:
34
45
  field = @schema.get_field("Subscription", event_name)
35
- if !field
36
- raise "No subscription matching trigger: #{event_name}"
37
- end
38
46
 
39
- # Normalize symbol-keyed args to strings
40
- if args.any?
41
- stringified_args = {}
42
- args.each { |k, v| stringified_args[k.to_s] = v }
43
- args = stringified_args
47
+ if field.nil?
48
+ # And if it wasn't found, normalize it:
49
+ normalized_event_name = normalize_name(event_name)
50
+ field = @schema.get_field("Subscription", normalized_event_name)
51
+ if field.nil?
52
+ raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})"
53
+ end
54
+ else
55
+ # Since we found a field, the original input was already normalized
56
+ normalized_event_name = event_name
44
57
  end
45
58
 
59
+ # Normalize symbol-keyed args to strings, try camelizing them
60
+ normalized_args = normalize_arguments(normalized_event_name, field, args)
61
+
46
62
  event = Subscriptions::Event.new(
47
- name: event_name,
48
- arguments: args,
63
+ name: normalized_event_name,
64
+ arguments: normalized_args,
49
65
  field: field,
50
66
  scope: scope,
51
67
  )
52
68
  execute_all(event, object)
53
69
  end
54
70
 
55
- def initialize(schema:, **rest)
56
- @schema = schema
57
- end
58
-
59
71
  # `event` was triggered on `object`, and `subscription_id` was subscribed,
60
72
  # so it should be updated.
61
73
  #
@@ -139,5 +151,67 @@ module GraphQL
139
151
  def build_id
140
152
  SecureRandom.uuid
141
153
  end
154
+
155
+ # Convert a user-provided event name or argument
156
+ # to the equivalent in GraphQL.
157
+ #
158
+ # By default, it converts the identifier to camelcase.
159
+ # Override this in a subclass to change the transformation.
160
+ #
161
+ # @param event_or_arg_name [String, Symbol]
162
+ # @return [String]
163
+ def normalize_name(event_or_arg_name)
164
+ Schema::Member::BuildType.camelize(event_or_arg_name.to_s)
165
+ end
166
+
167
+ private
168
+
169
+ # Recursively normalize `args` as belonging to `arg_owner`:
170
+ # - convert symbols to strings,
171
+ # - if needed, camelize the string (using {#normalize_name})
172
+ # @param arg_owner [GraphQL::Field, GraphQL::BaseType]
173
+ # @param args [Hash, Array, Any] some GraphQL input value to coerce as `arg_owner`
174
+ # @return [Any] normalized arguments value
175
+ def normalize_arguments(event_name, arg_owner, args)
176
+ case arg_owner
177
+ when GraphQL::Field, GraphQL::InputObjectType
178
+ normalized_args = {}
179
+ missing_arg_names = []
180
+ args.each do |k, v|
181
+ arg_name = k.to_s
182
+ arg_defn = arg_owner.arguments[arg_name]
183
+ if arg_defn
184
+ normalized_arg_name = arg_name
185
+ else
186
+ normalized_arg_name = normalize_name(arg_name)
187
+ arg_defn = arg_owner.arguments[normalized_arg_name]
188
+ end
189
+
190
+ if arg_defn
191
+ normalized_args[normalized_arg_name] = normalize_arguments(event_name, arg_defn.type, v)
192
+ else
193
+ # Couldn't find a matching argument definition
194
+ missing_arg_names << arg_name
195
+ end
196
+ end
197
+
198
+ if missing_arg_names.any?
199
+ arg_owner_name = if arg_owner.is_a?(GraphQL::Field)
200
+ "Subscription.#{arg_owner.name}"
201
+ else
202
+ arg_owner.to_s
203
+ end
204
+ raise InvalidTriggerError, "Can't trigger Subscription.#{event_name}, received undefined arguments: #{missing_arg_names.join(", ")}. (Should match arguments of #{arg_owner_name}.)"
205
+ end
206
+
207
+ normalized_args
208
+ when GraphQL::ListType
209
+ args.map { |a| normalize_arguments(event_name, arg_owner.of_type, a) }
210
+ when GraphQL::NonNullType
211
+ normalize_arguments(event_name, arg_owner.of_type, args)
212
+ else
213
+ args
214
+ end
215
+ end
142
216
  end
143
217
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ class DataDogTracing < PlatformTracing
6
+ self.platform_keys = {
7
+ 'lex' => 'lex.graphql',
8
+ 'parse' => 'parse.graphql',
9
+ 'validate' => 'validate.graphql',
10
+ 'analyze_query' => 'analyze.graphql',
11
+ 'analyze_multiplex' => 'analyze.graphql',
12
+ 'execute_multiplex' => 'execute.graphql',
13
+ 'execute_query' => 'execute.graphql',
14
+ 'execute_query_lazy' => 'execute.graphql',
15
+ }
16
+
17
+ def platform_trace(platform_key, key, data)
18
+ tracer.trace(platform_key, service: service_name) do |span|
19
+ span.span_type = 'custom'
20
+
21
+ if key == 'execute_multiplex'
22
+ operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
23
+ span.resource = operations unless operations.empty?
24
+ end
25
+
26
+ if key == 'execute_query'
27
+ span.set_tag(:selected_operation_name, data[:query].selected_operation_name)
28
+ span.set_tag(:selected_operation_type, data[:query].selected_operation.operation_type)
29
+ span.set_tag(:query_string, data[:query].query_string)
30
+ end
31
+
32
+ yield
33
+ end
34
+ end
35
+
36
+ def service_name
37
+ options.fetch(:service, 'ruby-graphql')
38
+ end
39
+
40
+ def tracer
41
+ options.fetch(:tracer, Datadog.tracer)
42
+ end
43
+
44
+ def platform_field_key(type, field)
45
+ "#{type.name}.#{field.name}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -14,7 +14,33 @@ module GraphQL
14
14
  "execute_query_lazy" => "GraphQL/execute",
15
15
  }
16
16
 
17
+ # @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
18
+ # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
19
+ # It can also be specified per-query with `context[:set_new_relic_transaction_name]`.
20
+ def initialize(set_transaction_name: false)
21
+ @set_transaction_name = set_transaction_name
22
+ super
23
+ end
24
+
17
25
  def platform_trace(platform_key, key, data)
26
+ if key == "execute_query"
27
+ set_this_txn_name = data[:query].context[:set_new_relic_transaction_name]
28
+ if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
29
+ query = data[:query]
30
+ # Set the transaction name based on the operation type and name
31
+ selected_op = query.selected_operation
32
+ if selected_op
33
+ op_type = selected_op.operation_type
34
+ op_name = selected_op.name || "anonymous"
35
+ else
36
+ op_type = "query"
37
+ op_name = "anonymous"
38
+ end
39
+
40
+ NewRelic::Agent.set_transaction_name("GraphQL/#{op_type}.#{op_name}")
41
+ end
42
+ end
43
+
18
44
  NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(platform_key) do
19
45
  yield
20
46
  end
@@ -12,8 +12,10 @@ module GraphQL
12
12
  attr_accessor :platform_keys
13
13
  end
14
14
 
15
- def initialize
15
+ def initialize(options = {})
16
+ @options = options
16
17
  @platform_keys = self.class.platform_keys
18
+ @trace_scalars = options.fetch(:trace_scalars, false)
17
19
  end
18
20
 
19
21
  def trace(key, data)
@@ -41,19 +43,30 @@ module GraphQL
41
43
  return_type = field.type.unwrap
42
44
  case return_type
43
45
  when GraphQL::ScalarType, GraphQL::EnumType
44
- field
46
+ if field.trace || (field.trace.nil? && @trace_scalars)
47
+ trace_field(type, field)
48
+ else
49
+ field
50
+ end
45
51
  else
46
- new_f = field.redefine
47
- new_f.metadata[:platform_key] = platform_field_key(type, field)
48
- new_f
52
+ trace_field(type, field)
49
53
  end
50
54
  end
51
55
 
52
- def self.use(schema_defn)
53
- tracer = self.new
56
+ def trace_field(type, field)
57
+ new_f = field.redefine
58
+ new_f.metadata[:platform_key] = platform_field_key(type, field)
59
+ new_f
60
+ end
61
+
62
+ def self.use(schema_defn, options = {})
63
+ tracer = self.new(options)
54
64
  schema_defn.instrument(:field, tracer)
55
65
  schema_defn.tracer(tracer)
56
66
  end
67
+
68
+ private
69
+ attr_reader :options
57
70
  end
58
71
  end
59
72
  end
@@ -16,9 +16,9 @@ module GraphQL
16
16
  "execute_query_lazy" => "execute.graphql",
17
17
  }
18
18
 
19
- def initialize
19
+ def initialize(options = {})
20
20
  self.class.include ScoutApm::Tracer
21
- super
21
+ super(options)
22
22
  end
23
23
 
24
24
  def platform_trace(platform_key, key, data)
@@ -2,6 +2,7 @@
2
2
  require "graphql/tracing/active_support_notifications_tracing"
3
3
  require "graphql/tracing/platform_tracing"
4
4
  require "graphql/tracing/appsignal_tracing"
5
+ require "graphql/tracing/data_dog_tracing"
5
6
  require "graphql/tracing/new_relic_tracing"
6
7
  require "graphql/tracing/scout_tracing"
7
8
  require "graphql/tracing/skylight_tracing"
@@ -26,8 +26,9 @@ module GraphQL
26
26
  @possible_types = possible_types
27
27
  message = "The value from \"#{field.name}\" on \"#{parent_type}\" could not be resolved to \"#{field.type}\". " \
28
28
  "(Received: `#{resolved_type.inspect}`, Expected: [#{possible_types.map(&:inspect).join(", ")}]) " \
29
- "Make sure you have defined a `type_from_object` proc on your schema and that value `#{value.inspect}` " \
30
- "gets resolved to a valid type."
29
+ "Make sure you have defined a `resolve_type` proc on your schema and that value `#{value.inspect}` " \
30
+ "gets resolved to a valid type. You may need to add your type to `orphan_types` if it implements an " \
31
+ "interface but isn't a return type of any other field."
31
32
  super(message)
32
33
  end
33
34
  end