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
@@ -75,7 +75,7 @@ class InMemoryBackend
75
75
  end
76
76
  end
77
77
  # Just a random stateful object for tracking what happens:
78
- class Payload
78
+ class SubscriptionPayload
79
79
  attr_reader :str
80
80
 
81
81
  def initialize
@@ -87,7 +87,65 @@ class InMemoryBackend
87
87
  @counter += 1
88
88
  end
89
89
  end
90
+ end
91
+
92
+ class ClassBasedInMemoryBackend < InMemoryBackend
93
+ class Payload < GraphQL::Schema::Object
94
+ field :str, String, null: false
95
+ field :int, Integer, null: false
96
+ end
97
+
98
+ class PayloadType < GraphQL::Schema::Enum
99
+ graphql_name "PayloadType"
100
+ # Arbitrary "kinds" of payloads which may be
101
+ # subscribed to separately
102
+ value "ONE"
103
+ value "TWO"
104
+ end
105
+
106
+ class StreamInput < GraphQL::Schema::InputObject
107
+ argument :user_id, ID, required: true
108
+ argument :type, PayloadType, required: false, default_value: "ONE"
109
+ end
110
+
111
+ class Subscription < GraphQL::Schema::Object
112
+ field :payload, Payload, null: false do
113
+ argument :id, ID, required: true
114
+ end
115
+
116
+ def payload(id:)
117
+ object
118
+ end
119
+
120
+ field :event, Payload, null: true do
121
+ argument :stream, StreamInput, required: false
122
+ end
123
+
124
+ def event(stream: nil)
125
+ object
126
+ end
127
+
128
+ field :my_event, Payload, null: true, subscription_scope: :me do
129
+ argument :type, PayloadType, required: false
130
+ end
131
+
132
+ def my_event(type: nil)
133
+ object
134
+ end
135
+ end
136
+
137
+ class Query < GraphQL::Schema::Object
138
+ field :dummy, Integer, null: true
139
+ end
140
+
141
+ class Schema < GraphQL::Schema
142
+ query(Query)
143
+ subscription(Subscription)
144
+ use InMemoryBackend::Subscriptions, extra: 123
145
+ end
146
+ end
90
147
 
148
+ class FromDefinitionInMemoryBackend < InMemoryBackend
91
149
  SchemaDefinition = <<-GRAPHQL
92
150
  type Subscription {
93
151
  payload(id: ID!): Payload!
@@ -126,7 +184,7 @@ class InMemoryBackend
126
184
  }
127
185
  Schema = GraphQL::Schema.from_definition(SchemaDefinition, default_resolve: Resolvers).redefine do
128
186
  use InMemoryBackend::Subscriptions,
129
- extra: 123
187
+ extra: 123
130
188
  end
131
189
 
132
190
  # TODO don't hack this (no way to add metadata from IDL parser right now)
@@ -162,233 +220,264 @@ describe GraphQL::Subscriptions do
162
220
  schema.subscriptions.reset
163
221
  end
164
222
 
165
- let(:root_object) {
166
- OpenStruct.new(
167
- payload: InMemoryBackend::Payload.new,
168
- )
169
- }
223
+ [ClassBasedInMemoryBackend, FromDefinitionInMemoryBackend].each do |in_memory_backend_class|
224
+ describe "using #{in_memory_backend_class}" do
225
+ let(:root_object) {
226
+ OpenStruct.new(
227
+ payload: in_memory_backend_class::SubscriptionPayload.new,
228
+ )
229
+ }
170
230
 
171
- let(:schema) { InMemoryBackend::Schema }
172
- let(:implementation) { schema.subscriptions }
173
- let(:deliveries) { implementation.deliveries }
174
- describe "pushing updates" do
175
- it "sends updated data" do
176
- query_str = <<-GRAPHQL
231
+ let(:schema) { in_memory_backend_class::Schema }
232
+ let(:implementation) { schema.subscriptions }
233
+ let(:deliveries) { implementation.deliveries }
234
+ describe "pushing updates" do
235
+ it "sends updated data" do
236
+ query_str = <<-GRAPHQL
177
237
  subscription ($id: ID!){
178
238
  firstPayload: payload(id: $id) { str, int }
179
239
  otherPayload: payload(id: "900") { int }
180
240
  }
181
- GRAPHQL
182
-
183
- # Initial subscriptions
184
- res_1 = schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "100" }, root_value: root_object)
185
- res_2 = schema.execute(query_str, context: { socket: "2" }, variables: { "id" => "200" }, root_value: root_object)
186
-
187
- # Initial response is nil, no broadcasts yet
188
- assert_equal(nil, res_1["data"])
189
- assert_equal(nil, res_2["data"])
190
- assert_equal [], deliveries["1"]
191
- assert_equal [], deliveries["2"]
192
-
193
- # Application stuff happens.
194
- # The application signals graphql via `subscriptions.trigger`:
195
- schema.subscriptions.trigger("payload", {"id" => "100"}, root_object.payload)
196
- schema.subscriptions.trigger("payload", {"id" => "200"}, root_object.payload)
197
- # Symobls are OK too
198
- schema.subscriptions.trigger("payload", {:id => "100"}, root_object.payload)
199
- schema.subscriptions.trigger("payload", {"id" => "300"}, nil)
200
-
201
- # Let's see what GraphQL sent over the wire:
202
- assert_equal({"str" => "Update", "int" => 1}, deliveries["1"][0]["data"]["firstPayload"])
203
- assert_equal({"str" => "Update", "int" => 2}, deliveries["2"][0]["data"]["firstPayload"])
204
- assert_equal({"str" => "Update", "int" => 3}, deliveries["1"][1]["data"]["firstPayload"])
205
- end
206
- end
241
+ GRAPHQL
242
+
243
+ # Initial subscriptions
244
+ res_1 = schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "100" }, root_value: root_object)
245
+ res_2 = schema.execute(query_str, context: { socket: "2" }, variables: { "id" => "200" }, root_value: root_object)
246
+
247
+ # Initial response is nil, no broadcasts yet
248
+ assert_equal(nil, res_1["data"])
249
+ assert_equal(nil, res_2["data"])
250
+ assert_equal [], deliveries["1"]
251
+ assert_equal [], deliveries["2"]
252
+
253
+ # Application stuff happens.
254
+ # The application signals graphql via `subscriptions.trigger`:
255
+ schema.subscriptions.trigger(:payload, {"id" => "100"}, root_object.payload)
256
+ schema.subscriptions.trigger("payload", {"id" => "200"}, root_object.payload)
257
+ # Symobls are OK too
258
+ schema.subscriptions.trigger(:payload, {:id => "100"}, root_object.payload)
259
+ schema.subscriptions.trigger("payload", {"id" => "300"}, nil)
260
+
261
+ # Let's see what GraphQL sent over the wire:
262
+ assert_equal({"str" => "Update", "int" => 1}, deliveries["1"][0]["data"]["firstPayload"])
263
+ assert_equal({"str" => "Update", "int" => 2}, deliveries["2"][0]["data"]["firstPayload"])
264
+ assert_equal({"str" => "Update", "int" => 3}, deliveries["1"][1]["data"]["firstPayload"])
265
+ end
266
+ end
207
267
 
208
- describe "subscribing" do
209
- it "doesn't call the subscriptions for invalid queries" do
210
- query_str = <<-GRAPHQL
268
+ describe "subscribing" do
269
+ it "doesn't call the subscriptions for invalid queries" do
270
+ query_str = <<-GRAPHQL
211
271
  subscription ($id: ID){
212
272
  payload(id: $id) { str, int }
213
273
  }
214
- GRAPHQL
274
+ GRAPHQL
215
275
 
216
- res = schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "100" }, root_value: root_object)
217
- assert_equal true, res.key?("errors")
218
- assert_equal 0, implementation.size
219
- end
220
- end
276
+ res = schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "100" }, root_value: root_object)
277
+ assert_equal true, res.key?("errors")
278
+ assert_equal 0, implementation.size
279
+ end
280
+ end
221
281
 
222
- describe "trigger" do
223
- it "uses the provided queue" do
224
- query_str = <<-GRAPHQL
282
+ describe "trigger" do
283
+ it "uses the provided queue" do
284
+ query_str = <<-GRAPHQL
225
285
  subscription ($id: ID!){
226
286
  payload(id: $id) { str, int }
227
287
  }
228
- GRAPHQL
288
+ GRAPHQL
229
289
 
230
- schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "8" }, root_value: root_object)
231
- schema.subscriptions.trigger("payload", { "id" => "8"}, root_object.payload)
232
- assert_equal ["1"], implementation.pushes
233
- end
290
+ schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "8" }, root_value: root_object)
291
+ schema.subscriptions.trigger("payload", { "id" => "8"}, root_object.payload)
292
+ assert_equal ["1"], implementation.pushes
293
+ end
234
294
 
235
- it "pushes errors" do
236
- query_str = <<-GRAPHQL
295
+ it "pushes errors" do
296
+ query_str = <<-GRAPHQL
237
297
  subscription ($id: ID!){
238
298
  payload(id: $id) { str, int }
239
299
  }
240
- GRAPHQL
300
+ GRAPHQL
241
301
 
242
- schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "8" }, root_value: root_object)
243
- schema.subscriptions.trigger("payload", { "id" => "8"}, OpenStruct.new(str: nil, int: nil))
244
- delivery = deliveries["1"].first
245
- assert_equal nil, delivery.fetch("data")
246
- assert_equal 1, delivery["errors"].length
247
- end
302
+ schema.execute(query_str, context: { socket: "1" }, variables: { "id" => "8" }, root_value: root_object)
303
+ schema.subscriptions.trigger("payload", { "id" => "8"}, OpenStruct.new(str: nil, int: nil))
304
+ delivery = deliveries["1"].first
305
+ assert_nil delivery.fetch("data")
306
+ assert_equal 1, delivery["errors"].length
307
+ end
248
308
 
249
- it "coerces args" do
250
- query_str = <<-GRAPHQL
309
+ it "coerces args" do
310
+ query_str = <<-GRAPHQL
251
311
  subscription($type: PayloadType) {
252
312
  e1: event(stream: { userId: "3", type: $type }) { int }
253
313
  }
254
- GRAPHQL
255
-
256
- # Subscribe with explicit `TYPE`
257
- schema.execute(query_str, context: { socket: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
258
- # Subscribe with default `TYPE`
259
- schema.execute(query_str, context: { socket: "2" }, root_value: root_object)
260
- # Subscribe with non-matching `TYPE`
261
- schema.execute(query_str, context: { socket: "3" }, variables: { "type" => "TWO" }, root_value: root_object)
262
- # Subscribe with explicit null
263
- schema.execute(query_str, context: { socket: "4" }, variables: { "type" => nil }, root_value: root_object)
264
-
265
- # Trigger the subscription with coerceable args, different orders:
266
- schema.subscriptions.trigger("event", { "stream" => {"userId" => 3, "type" => "ONE"} }, OpenStruct.new(str: "", int: 1))
267
- schema.subscriptions.trigger("event", { "stream" => {"type" => "ONE", "userId" => "3"} }, OpenStruct.new(str: "", int: 2))
268
- # This is a non-trigger
269
- schema.subscriptions.trigger("event", { "stream" => {"userId" => "3", "type" => "TWO"} }, OpenStruct.new(str: "", int: 3))
270
- # These get default value of ONE
271
- schema.subscriptions.trigger("event", { "stream" => {"userId" => "3"} }, OpenStruct.new(str: "", int: 4))
272
- # Trigger with null updates subscriptionss to null
273
- schema.subscriptions.trigger("event", { "stream" => {"userId" => 3, "type" => nil} }, OpenStruct.new(str: "", int: 5))
274
-
275
- assert_equal [1,2,4], deliveries["1"].map { |d| d["data"]["e1"]["int"] }
276
-
277
- # Same as socket_1
278
- assert_equal [1,2,4], deliveries["2"].map { |d| d["data"]["e1"]["int"] }
279
-
280
- # Received the "non-trigger"
281
- assert_equal [3], deliveries["3"].map { |d| d["data"]["e1"]["int"] }
282
-
283
- # Received the trigger with null
284
- assert_equal [5], deliveries["4"].map { |d| d["data"]["e1"]["int"] }
285
- end
314
+ GRAPHQL
315
+
316
+ # Subscribe with explicit `TYPE`
317
+ schema.execute(query_str, context: { socket: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
318
+ # Subscribe with default `TYPE`
319
+ schema.execute(query_str, context: { socket: "2" }, root_value: root_object)
320
+ # Subscribe with non-matching `TYPE`
321
+ schema.execute(query_str, context: { socket: "3" }, variables: { "type" => "TWO" }, root_value: root_object)
322
+ # Subscribe with explicit null
323
+ schema.execute(query_str, context: { socket: "4" }, variables: { "type" => nil }, root_value: root_object)
324
+
325
+ # Trigger the subscription with coerceable args, different orders:
326
+ schema.subscriptions.trigger("event", { "stream" => {"userId" => 3, "type" => "ONE"} }, OpenStruct.new(str: "", int: 1))
327
+ schema.subscriptions.trigger("event", { "stream" => {"type" => "ONE", "userId" => "3"} }, OpenStruct.new(str: "", int: 2))
328
+ # This is a non-trigger
329
+ schema.subscriptions.trigger("event", { "stream" => {"userId" => "3", "type" => "TWO"} }, OpenStruct.new(str: "", int: 3))
330
+ # These get default value of ONE (underscored / symbols are ok)
331
+ schema.subscriptions.trigger("event", { stream: { user_id: "3"} }, OpenStruct.new(str: "", int: 4))
332
+ # Trigger with null updates subscriptionss to null
333
+ schema.subscriptions.trigger("event", { "stream" => {"userId" => 3, "type" => nil} }, OpenStruct.new(str: "", int: 5))
334
+
335
+ assert_equal [1,2,4], deliveries["1"].map { |d| d["data"]["e1"]["int"] }
336
+
337
+ # Same as socket_1
338
+ assert_equal [1,2,4], deliveries["2"].map { |d| d["data"]["e1"]["int"] }
339
+
340
+ # Received the "non-trigger"
341
+ assert_equal [3], deliveries["3"].map { |d| d["data"]["e1"]["int"] }
342
+
343
+ # Received the trigger with null
344
+ assert_equal [5], deliveries["4"].map { |d| d["data"]["e1"]["int"] }
345
+ end
286
346
 
287
- it "allows context-scoped subscriptions" do
288
- query_str = <<-GRAPHQL
347
+ it "allows context-scoped subscriptions" do
348
+ query_str = <<-GRAPHQL
289
349
  subscription($type: PayloadType) {
290
350
  myEvent(type: $type) { int }
291
351
  }
292
- GRAPHQL
293
-
294
- # Subscriptions for user 1
295
- schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
296
- schema.execute(query_str, context: { socket: "2", me: "1" }, variables: { "type" => "TWO" }, root_value: root_object)
297
- # Subscription for user 2
298
- schema.execute(query_str, context: { socket: "3", me: "2" }, variables: { "type" => "ONE" }, root_value: root_object)
299
-
300
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 1), scope: "1")
301
- schema.subscriptions.trigger("myEvent", { "type" => "TWO" }, OpenStruct.new(str: "", int: 2), scope: "1")
302
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 3), scope: "2")
303
-
304
- # Delivered to user 1
305
- assert_equal [1], deliveries["1"].map { |d| d["data"]["myEvent"]["int"] }
306
- assert_equal [2], deliveries["2"].map { |d| d["data"]["myEvent"]["int"] }
307
- # Delivered to user 2
308
- assert_equal [3], deliveries["3"].map { |d| d["data"]["myEvent"]["int"] }
309
- end
352
+ GRAPHQL
353
+
354
+ # Subscriptions for user 1
355
+ schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
356
+ schema.execute(query_str, context: { socket: "2", me: "1" }, variables: { "type" => "TWO" }, root_value: root_object)
357
+ # Subscription for user 2
358
+ schema.execute(query_str, context: { socket: "3", me: "2" }, variables: { "type" => "ONE" }, root_value: root_object)
359
+
360
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 1), scope: "1")
361
+ schema.subscriptions.trigger("myEvent", { "type" => "TWO" }, OpenStruct.new(str: "", int: 2), scope: "1")
362
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 3), scope: "2")
363
+
364
+ # Delivered to user 1
365
+ assert_equal [1], deliveries["1"].map { |d| d["data"]["myEvent"]["int"] }
366
+ assert_equal [2], deliveries["2"].map { |d| d["data"]["myEvent"]["int"] }
367
+ # Delivered to user 2
368
+ assert_equal [3], deliveries["3"].map { |d| d["data"]["myEvent"]["int"] }
369
+ end
310
370
 
311
- if defined?(GlobalID)
312
- it "allows complex object subscription scopes" do
313
- query_str = <<-GRAPHQL
371
+ if defined?(GlobalID)
372
+ it "allows complex object subscription scopes" do
373
+ query_str = <<-GRAPHQL
314
374
  subscription($type: PayloadType) {
315
375
  myEvent(type: $type) { int }
316
376
  }
317
- GRAPHQL
318
-
319
- # Global ID Backed User
320
- schema.execute(query_str, context: { socket: "1", me: GlobalIDUser.new(1) }, variables: { "type" => "ONE" }, root_value: root_object)
321
- schema.execute(query_str, context: { socket: "2", me: GlobalIDUser.new(1) }, variables: { "type" => "TWO" }, root_value: root_object)
322
- # ToParam Backed User
323
- schema.execute(query_str, context: { socket: "3", me: ToParamUser.new(2) }, variables: { "type" => "ONE" }, root_value: root_object)
324
- # Array of Objects
325
- schema.execute(query_str, context: { socket: "4", me: [GlobalIDUser.new(4), ToParamUser.new(5)] }, variables: { "type" => "ONE" }, root_value: root_object)
326
-
327
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 1), scope: GlobalIDUser.new(1))
328
- schema.subscriptions.trigger("myEvent", { "type" => "TWO" }, OpenStruct.new(str: "", int: 2), scope: GlobalIDUser.new(1))
329
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 3), scope: ToParamUser.new(2))
330
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 4), scope: [GlobalIDUser.new(4), ToParamUser.new(5)])
331
-
332
- # Delivered to GlobalIDUser
333
- assert_equal [1], deliveries["1"].map { |d| d["data"]["myEvent"]["int"] }
334
- assert_equal [2], deliveries["2"].map { |d| d["data"]["myEvent"]["int"] }
335
- # Delivered to ToParamUser
336
- assert_equal [3], deliveries["3"].map { |d| d["data"]["myEvent"]["int"] }
337
- # Delivered to Array of GlobalIDUser and ToParamUser
338
- assert_equal [4], deliveries["4"].map { |d| d["data"]["myEvent"]["int"] }
339
- end
340
- end
341
-
342
- describe "errors" do
343
- class ErrorPayload
344
- def int
345
- raise "Boom!"
377
+ GRAPHQL
378
+
379
+ # Global ID Backed User
380
+ schema.execute(query_str, context: { socket: "1", me: GlobalIDUser.new(1) }, variables: { "type" => "ONE" }, root_value: root_object)
381
+ schema.execute(query_str, context: { socket: "2", me: GlobalIDUser.new(1) }, variables: { "type" => "TWO" }, root_value: root_object)
382
+ # ToParam Backed User
383
+ schema.execute(query_str, context: { socket: "3", me: ToParamUser.new(2) }, variables: { "type" => "ONE" }, root_value: root_object)
384
+ # Array of Objects
385
+ schema.execute(query_str, context: { socket: "4", me: [GlobalIDUser.new(4), ToParamUser.new(5)] }, variables: { "type" => "ONE" }, root_value: root_object)
386
+
387
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 1), scope: GlobalIDUser.new(1))
388
+ schema.subscriptions.trigger("myEvent", { "type" => "TWO" }, OpenStruct.new(str: "", int: 2), scope: GlobalIDUser.new(1))
389
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 3), scope: ToParamUser.new(2))
390
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, OpenStruct.new(str: "", int: 4), scope: [GlobalIDUser.new(4), ToParamUser.new(5)])
391
+
392
+ # Delivered to GlobalIDUser
393
+ assert_equal [1], deliveries["1"].map { |d| d["data"]["myEvent"]["int"] }
394
+ assert_equal [2], deliveries["2"].map { |d| d["data"]["myEvent"]["int"] }
395
+ # Delivered to ToParamUser
396
+ assert_equal [3], deliveries["3"].map { |d| d["data"]["myEvent"]["int"] }
397
+ # Delivered to Array of GlobalIDUser and ToParamUser
398
+ assert_equal [4], deliveries["4"].map { |d| d["data"]["myEvent"]["int"] }
399
+ end
346
400
  end
347
401
 
348
- def str
349
- raise GraphQL::ExecutionError.new("This is handled")
350
- end
351
- end
402
+ describe "errors" do
403
+ class ErrorPayload
404
+ def int
405
+ raise "Boom!"
406
+ end
352
407
 
353
- it "lets unhandled errors crash "do
354
- query_str = <<-GRAPHQL
408
+ def str
409
+ raise GraphQL::ExecutionError.new("This is handled")
410
+ end
411
+ end
412
+
413
+ it "lets unhandled errors crash "do
414
+ query_str = <<-GRAPHQL
355
415
  subscription($type: PayloadType) {
356
416
  myEvent(type: $type) { int }
357
417
  }
358
- GRAPHQL
359
-
360
- schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
361
- err = assert_raises(RuntimeError) {
362
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, ErrorPayload.new, scope: "1")
363
- }
364
- assert_equal "Boom!", err.message
365
- end
366
- end
418
+ GRAPHQL
419
+
420
+ schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
421
+ err = assert_raises(RuntimeError) {
422
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, ErrorPayload.new, scope: "1")
423
+ }
424
+ assert_equal "Boom!", err.message
425
+ end
426
+ end
367
427
 
368
- it "sends query errors to the subscriptions" do
369
- query_str = <<-GRAPHQL
428
+ it "sends query errors to the subscriptions" do
429
+ query_str = <<-GRAPHQL
370
430
  subscription($type: PayloadType) {
371
431
  myEvent(type: $type) { str }
372
432
  }
373
- GRAPHQL
433
+ GRAPHQL
374
434
 
375
- schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
376
- schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, ErrorPayload.new, scope: "1")
377
- res = deliveries["1"].first
378
- assert_equal "This is handled", res["errors"][0]["message"]
379
- end
380
- end
435
+ schema.execute(query_str, context: { socket: "1", me: "1" }, variables: { "type" => "ONE" }, root_value: root_object)
436
+ schema.subscriptions.trigger("myEvent", { "type" => "ONE" }, ErrorPayload.new, scope: "1")
437
+ res = deliveries["1"].first
438
+ assert_equal "This is handled", res["errors"][0]["message"]
439
+ end
440
+ end
381
441
 
382
- describe "implementation" do
383
- it "is initialized with keywords" do
384
- assert_equal 123, schema.subscriptions.extra
385
- end
386
- end
442
+ describe "implementation" do
443
+ it "is initialized with keywords" do
444
+ assert_equal 123, schema.subscriptions.extra
445
+ end
446
+ end
447
+
448
+ describe "#build_id" do
449
+ it "returns a unique ID string" do
450
+ assert_instance_of String, schema.subscriptions.build_id
451
+ refute_equal schema.subscriptions.build_id, schema.subscriptions.build_id
452
+ end
453
+ end
454
+
455
+ describe ".trigger" do
456
+ it "raises when event name is not found" do
457
+ err = assert_raises(GraphQL::Subscriptions::InvalidTriggerError) do
458
+ schema.subscriptions.trigger(:nonsense_field, {}, nil)
459
+ end
460
+
461
+ assert_includes err.message, "trigger: nonsense_field"
462
+ assert_includes err.message, "Subscription.nonsenseField"
463
+ end
464
+
465
+ it "raises when argument is not found" do
466
+ err = assert_raises(GraphQL::Subscriptions::InvalidTriggerError) do
467
+ schema.subscriptions.trigger(:event, { scream: {"userId" => "😱"} }, nil)
468
+ end
387
469
 
388
- describe "#build_id" do
389
- it "returns a unique ID string" do
390
- assert_instance_of String, schema.subscriptions.build_id
391
- refute_equal schema.subscriptions.build_id, schema.subscriptions.build_id
470
+ assert_includes err.message, "arguments: scream"
471
+ assert_includes err.message, "arguments of Subscription.event"
472
+
473
+ err = assert_raises(GraphQL::Subscriptions::InvalidTriggerError) do
474
+ schema.subscriptions.trigger(:event, { stream: { user_id_number: "😱"} }, nil)
475
+ end
476
+
477
+ assert_includes err.message, "arguments: user_id_number"
478
+ assert_includes err.message, "arguments of StreamInput"
479
+ end
480
+ end
392
481
  end
393
482
  end
394
483
  end
@@ -41,10 +41,10 @@ describe GraphQL::Tracing::ActiveSupportNotificationsTracing do
41
41
  "graphql.execute_field",
42
42
  "graphql.execute_query",
43
43
  "graphql.lazy_loader",
44
- "graphql.execute_field",
45
44
  "graphql.execute_field_lazy",
46
45
  "graphql.execute_field",
47
46
  "graphql.execute_field_lazy",
47
+ "graphql.execute_field",
48
48
  "graphql.execute_field_lazy",
49
49
  "graphql.execute_field_lazy",
50
50
  "graphql.execute_query_lazy",
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Tracing::NewRelicTracing do
5
+ module NewRelicTest
6
+ class Query < GraphQL::Schema::Object
7
+ field :int, Integer, null: false
8
+
9
+ def int
10
+ 1
11
+ end
12
+ end
13
+
14
+ class SchemaWithoutTransactionName < GraphQL::Schema
15
+ query(Query)
16
+ use(GraphQL::Tracing::NewRelicTracing)
17
+ end
18
+
19
+ class SchemaWithTransactionName < GraphQL::Schema
20
+ query(Query)
21
+ use(GraphQL::Tracing::NewRelicTracing, set_transaction_name: true)
22
+ end
23
+ end
24
+
25
+ before do
26
+ NewRelic.clear_all
27
+ end
28
+
29
+ it "can leave the transaction name in place" do
30
+ NewRelicTest::SchemaWithoutTransactionName.execute "query X { int }"
31
+ assert_equal [], NewRelic::TRANSACTION_NAMES
32
+ end
33
+
34
+ it "can override the transaction name" do
35
+ NewRelicTest::SchemaWithTransactionName.execute "query X { int }"
36
+ assert_equal ["GraphQL/query.X"], NewRelic::TRANSACTION_NAMES
37
+ end
38
+
39
+ it "can override the transaction name per query" do
40
+ # Override with `false`
41
+ NewRelicTest::SchemaWithTransactionName.execute "{ int }", context: { set_new_relic_transaction_name: false }
42
+ assert_equal [], NewRelic::TRANSACTION_NAMES
43
+ # Override with `true`
44
+ NewRelicTest::SchemaWithoutTransactionName.execute "{ int }", context: { set_new_relic_transaction_name: true }
45
+ assert_equal ["GraphQL/query.anonymous"], NewRelic::TRANSACTION_NAMES
46
+ end
47
+ end