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
@@ -36,7 +36,7 @@ module GraphQL
36
36
  # printer = GraphQL::Schema::Printer.new(MySchema)
37
37
  # puts printer.print_type(post_type)
38
38
  #
39
- class Printer
39
+ class Printer < GraphQL::Language::Printer
40
40
  attr_reader :schema, :warden
41
41
 
42
42
  # @param schema [GraphQL::Schema]
@@ -45,21 +45,32 @@ module GraphQL
45
45
  # @param except [<#call(member, ctx)>]
46
46
  # @param introspection [Boolean] Should include the introspection types in the string?
47
47
  def initialize(schema, context: nil, only: nil, except: nil, introspection: false)
48
- @schema = schema
49
- @context = context
48
+ @document_from_schema = GraphQL::Language::DocumentFromSchemaDefinition.new(
49
+ schema,
50
+ context: context,
51
+ only: only,
52
+ except: except,
53
+ include_introspection_types: introspection,
54
+ )
55
+
56
+ @document = @document_from_schema.document
50
57
 
51
- blacklist = build_blacklist(only, except, introspection: introspection)
52
- filter = GraphQL::Filter.new(except: blacklist)
53
- @warden = GraphQL::Schema::Warden.new(filter, schema: @schema, context: @context)
58
+ @schema = schema
54
59
  end
55
60
 
56
61
  # Return the GraphQL schema string for the introspection type system
57
62
  def self.print_introspection_schema
58
63
  query_root = ObjectType.define(name: "Root")
59
64
  schema = GraphQL::Schema.define(query: query_root)
60
- blacklist = ->(m, ctx) { m == query_root }
61
- printer = new(schema, except: blacklist, introspection: true)
62
- printer.print_schema
65
+
66
+ introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
67
+ schema,
68
+ except: ->(member, _) { member.name == "Root" },
69
+ include_introspection_types: true,
70
+ include_built_in_directives: true,
71
+ ).document
72
+
73
+ introspection_schema_ast.to_query_string(printer: IntrospectionPrinter.new)
63
74
  end
64
75
 
65
76
  # Return a GraphQL schema string for the defined types in the schema
@@ -74,277 +85,33 @@ module GraphQL
74
85
 
75
86
  # Return a GraphQL schema string for the defined types in the schema
76
87
  def print_schema
77
- directive_definitions = warden.directives.map { |directive| print_directive(directive) }
78
-
79
- printable_types = warden.types.reject(&:default_scalar?)
80
-
81
- type_definitions = printable_types
82
- .sort_by(&:name)
83
- .map { |type| print_type(type) }
84
-
85
- [print_schema_definition].compact
86
- .concat(directive_definitions)
87
- .concat(type_definitions).join("\n\n")
88
+ print(@document)
88
89
  end
89
90
 
90
91
  def print_type(type)
91
- TypeKindPrinters::STRATEGIES.fetch(type.kind).print(warden, type)
92
+ node = @document_from_schema.build_object_type_node(type)
93
+ print(node)
92
94
  end
93
95
 
94
- private
95
-
96
- # By default, these are included in a schema printout
97
- IS_USER_DEFINED_MEMBER = ->(member) {
98
- case member
99
- when GraphQL::BaseType
100
- !member.introspection?
101
- when GraphQL::Directive
102
- !member.default_directive?
103
- else
104
- true
105
- end
106
- }
107
-
108
- private_constant :IS_USER_DEFINED_MEMBER
96
+ def print_directive(directive)
97
+ if directive.name == "deprecated"
98
+ reason = directive.arguments.find { |arg| arg.name == "reason" }
109
99
 
110
- def build_blacklist(only, except, introspection:)
111
- if introspection
112
- if only
113
- ->(m, ctx) { !only.call(m, ctx) }
114
- elsif except
115
- except
100
+ if reason.value == GraphQL::Directive::DEFAULT_DEPRECATION_REASON
101
+ "@deprecated"
116
102
  else
117
- ->(m, ctx) { false }
103
+ "@deprecated(reason: #{reason.value.to_s.inspect})"
118
104
  end
119
105
  else
120
- if only
121
- ->(m, ctx) { !(IS_USER_DEFINED_MEMBER.call(m) && only.call(m, ctx)) }
122
- elsif except
123
- ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) || except.call(m, ctx) }
124
- else
125
- ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) }
126
- end
106
+ super
127
107
  end
128
108
  end
129
109
 
130
- def print_schema_definition
131
- if (schema.query.nil? || schema.query.name == 'Query') &&
132
- (schema.mutation.nil? || schema.mutation.name == 'Mutation') &&
133
- (schema.subscription.nil? || schema.subscription.name == 'Subscription')
134
- return
110
+ class IntrospectionPrinter < GraphQL::Language::Printer
111
+ def print_schema_definition(schema)
112
+ "schema {\n query: Root\n}"
135
113
  end
136
-
137
- operations = [:query, :mutation, :subscription].map do |operation_type|
138
- object_type = schema.public_send(operation_type)
139
- # Special treatment for the introspection schema, which prints `{ query: "Root" }`
140
- if object_type && (warden.get_type(object_type.name) || (object_type.name == "Root" && schema.query == object_type))
141
- " #{operation_type}: #{object_type.name}\n"
142
- else
143
- nil
144
- end
145
- end.compact.join
146
- "schema {\n#{operations}}"
147
- end
148
-
149
- def print_directive(directive)
150
- TypeKindPrinters::DirectivePrinter.print(warden, directive)
151
- end
152
-
153
- module TypeKindPrinters
154
- module DeprecatedPrinter
155
- def print_deprecated(field_or_enum_value)
156
- return unless field_or_enum_value.deprecation_reason
157
-
158
- case field_or_enum_value.deprecation_reason
159
- when nil
160
- ''
161
- when '', GraphQL::Directive::DEFAULT_DEPRECATION_REASON
162
- ' @deprecated'
163
- else
164
- " @deprecated(reason: #{field_or_enum_value.deprecation_reason.to_s.inspect})"
165
- end
166
- end
167
- end
168
-
169
- module DescriptionPrinter
170
- def print_description(definition, indentation='', first_in_block=true)
171
- return '' unless definition.description
172
-
173
- description = indentation != '' && !first_in_block ? "\n".dup : "".dup
174
- description << GraphQL::Language::Comments.commentize(definition.description, indent: indentation)
175
- end
176
- end
177
-
178
- module ArgsPrinter
179
- include DescriptionPrinter
180
- def print_args(warden, field, indentation = '')
181
- arguments = warden.arguments(field)
182
- return if arguments.empty?
183
-
184
- if arguments.all?{ |arg| !arg.description }
185
- return "(#{arguments.map{ |arg| print_input_value(arg) }.join(", ")})"
186
- end
187
-
188
- out = "(\n".dup
189
- out << arguments.sort_by(&:name).map.with_index{ |arg, i|
190
- "#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\
191
- "#{print_input_value(arg)}"
192
- }.join("\n")
193
- out << "\n#{indentation})"
194
- end
195
-
196
- def print_input_value(arg)
197
- if arg.default_value?
198
- default_string = " = #{print_value(arg.default_value, arg.type)}"
199
- else
200
- default_string = nil
201
- end
202
-
203
- "#{arg.name}: #{arg.type.to_s}#{default_string}"
204
- end
205
-
206
- def print_value(value, type)
207
- case type
208
- when FLOAT_TYPE
209
- return 'null' if value.nil?
210
- value.to_f.inspect
211
- when INT_TYPE
212
- return 'null' if value.nil?
213
- value.to_i.inspect
214
- when BOOLEAN_TYPE
215
- return 'null' if value.nil?
216
- (!!value).inspect
217
- when ScalarType, ID_TYPE, STRING_TYPE
218
- return 'null' if value.nil?
219
- value.to_s.inspect
220
- when EnumType
221
- return 'null' if value.nil?
222
- type.coerce_isolated_result(value)
223
- when InputObjectType
224
- return 'null' if value.nil?
225
- fields = value.to_h.map{ |field_name, field_value|
226
- field_type = type.input_fields.fetch(field_name.to_s).type
227
- "#{field_name}: #{print_value(field_value, field_type)}"
228
- }.join(", ")
229
- "{#{fields}}"
230
- when NonNullType
231
- print_value(value, type.of_type)
232
- when ListType
233
- return 'null' if value.nil?
234
- "[#{value.to_a.map{ |v| print_value(v, type.of_type) }.join(", ")}]"
235
- else
236
- raise NotImplementedError, "Unexpected value type #{type.inspect}"
237
- end
238
- end
239
- end
240
-
241
- module FieldPrinter
242
- include DeprecatedPrinter
243
- include ArgsPrinter
244
- include DescriptionPrinter
245
- def print_fields(warden, type)
246
- fields = warden.fields(type)
247
- fields.sort_by(&:name).map.with_index { |field, i|
248
- "#{print_description(field, ' ', i == 0)}"\
249
- " #{field.name}#{print_args(warden, field, ' ')}: #{field.type}#{print_deprecated(field)}"
250
- }.join("\n")
251
- end
252
- end
253
-
254
- class DirectivePrinter
255
- extend ArgsPrinter
256
- extend DescriptionPrinter
257
- def self.print(warden, directive)
258
- "#{print_description(directive)}"\
259
- "directive @#{directive.name}#{print_args(warden, directive)} "\
260
- "on #{directive.locations.join(' | ')}"
261
- end
262
- end
263
-
264
- class ScalarPrinter
265
- extend DescriptionPrinter
266
- def self.print(warden, type)
267
- "#{print_description(type)}"\
268
- "scalar #{type.name}"
269
- end
270
- end
271
-
272
- class ObjectPrinter
273
- extend FieldPrinter
274
- extend DescriptionPrinter
275
- def self.print(warden, type)
276
- interfaces = warden.interfaces(type)
277
- if interfaces.any?
278
- implementations = " implements #{interfaces.sort_by(&:name).map(&:to_s).join(", ")}"
279
- else
280
- implementations = nil
281
- end
282
-
283
- "#{print_description(type)}"\
284
- "type #{type.name}#{implementations} {\n"\
285
- "#{print_fields(warden, type)}\n"\
286
- "}"
287
- end
288
- end
289
-
290
- class InterfacePrinter
291
- extend FieldPrinter
292
- extend DescriptionPrinter
293
- def self.print(warden, type)
294
- "#{print_description(type)}"\
295
- "interface #{type.name} {\n#{print_fields(warden, type)}\n}"
296
- end
297
- end
298
-
299
- class UnionPrinter
300
- extend DescriptionPrinter
301
- def self.print(warden, type)
302
- possible_types = warden.possible_types(type)
303
- "#{print_description(type)}"\
304
- "union #{type.name} = #{possible_types.sort_by(&:name).map(&:to_s).join(" | ")}"
305
- end
306
- end
307
-
308
- class EnumPrinter
309
- extend DeprecatedPrinter
310
- extend DescriptionPrinter
311
- def self.print(warden, type)
312
- enum_values = warden.enum_values(type)
313
-
314
- values = enum_values.sort_by(&:name).map.with_index { |v, i|
315
- "#{print_description(v, ' ', i == 0)}"\
316
- " #{v.name}#{print_deprecated(v)}"
317
- }.join("\n")
318
-
319
- "#{print_description(type)}"\
320
- "enum #{type.name} {\n#{values}\n}"
321
- end
322
- end
323
-
324
- class InputObjectPrinter
325
- extend FieldPrinter
326
- extend DescriptionPrinter
327
- def self.print(warden, type)
328
- arguments = warden.arguments(type)
329
- fields = arguments.sort_by(&:name).map.with_index{ |field, i|
330
- "#{print_description(field, " ", i == 0)}"\
331
- " #{print_input_value(field)}"
332
- }.join("\n")
333
- "#{print_description(type)}"\
334
- "input #{type.name} {\n#{fields}\n}"
335
- end
336
- end
337
-
338
- STRATEGIES = {
339
- GraphQL::TypeKinds::SCALAR => ScalarPrinter,
340
- GraphQL::TypeKinds::OBJECT => ObjectPrinter,
341
- GraphQL::TypeKinds::INTERFACE => InterfacePrinter,
342
- GraphQL::TypeKinds::UNION => UnionPrinter,
343
- GraphQL::TypeKinds::ENUM => EnumPrinter,
344
- GraphQL::TypeKinds::INPUT_OBJECT => InputObjectPrinter,
345
- }
346
114
  end
347
- private_constant :TypeKindPrinters
348
115
  end
349
116
  end
350
117
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ # Mutations that extend this base class get some conventions added for free:
6
+ #
7
+ # - An argument called `clientMutationId` is _always_ added, but it's not passed
8
+ # to the resolve method. The value is re-inserted to the response. (It's for
9
+ # client libraries to manage optimistic updates.)
10
+ # - The returned object type always has a field called `clientMutationId` to support that.
11
+ # - The mutation accepts one argument called `input`, `argument`s defined in the mutation
12
+ # class are added to that input object, which is generated by the mutation.
13
+ #
14
+ # These conventions were first specified by Relay Classic, but they come in handy:
15
+ #
16
+ # - `clientMutationId` supports optimistic updates and cache rollbacks on the client
17
+ # - using a single `input:` argument makes it easy to post whole JSON objects to the mutation
18
+ # using one GraphQL variable (`$input`) instead of making a separate variable for each argument.
19
+ #
20
+ # @see {GraphQL::Schema::Mutation} for an example, it's basically the same.
21
+ #
22
+ class RelayClassicMutation < GraphQL::Schema::Mutation
23
+ # The payload should always include this field
24
+ field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.", null: true)
25
+ # Relay classic default:
26
+ null(true)
27
+
28
+ # Override {GraphQL::Schema::Mutation#resolve_mutation} to
29
+ # delete `client_mutation_id` from the kwargs.
30
+ def resolve_mutation(kwargs)
31
+ # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
32
+ kwargs.delete(:client_mutation_id)
33
+ resolve(**kwargs)
34
+ end
35
+
36
+ resolve_method(:resolve_mutation)
37
+
38
+ class << self
39
+ # The base class for generated input object types
40
+ # @param new_class [Class] The base class to use for generating input object definitions
41
+ # @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
42
+ def input_object_class(new_class = nil)
43
+ if new_class
44
+ @input_object_class = new_class
45
+ end
46
+ @input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
47
+ end
48
+
49
+ # @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
50
+ # @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
51
+ def input_type(new_input_type = nil)
52
+ if new_input_type
53
+ @input_type = new_input_type
54
+ end
55
+ @input_type ||= generate_input_type
56
+ end
57
+
58
+ # Extend {Schema::Mutation.field_options} to add the `input` argument
59
+ def field_options
60
+ sig = super
61
+ # Arguments were added at the root, but they should be nested
62
+ sig[:arguments].clear
63
+ sig[:arguments][:input] = { type: input_type, required: true }
64
+ sig
65
+ end
66
+
67
+ private
68
+
69
+ # Generate the input type for the `input:` argument
70
+ # To customize how input objects are generated, override this method
71
+ # @return [Class] a subclass of {.input_object_class}
72
+ def generate_input_type
73
+ mutation_args = arguments
74
+ mutation_name = graphql_name
75
+ mutation_class = self
76
+ Class.new(input_object_class) do
77
+ graphql_name("#{mutation_name}Input")
78
+ description("Autogenerated input type of #{mutation_name}")
79
+ mutation(mutation_class)
80
+ own_arguments.merge!(mutation_args)
81
+ argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -41,13 +41,14 @@ module GraphQL
41
41
  private
42
42
 
43
43
  def attempt_rescue(err)
44
- handler = rescue_table[err.class]
45
- if handler
46
- message = handler.call(err)
47
- GraphQL::ExecutionError.new(message)
48
- else
49
- raise(err)
50
- end
44
+ rescue_table.each { |klass, handler|
45
+ if klass.is_a?(Class) && err.is_a?(klass) && handler
46
+ message = handler.call(err)
47
+ return GraphQL::ExecutionError.new(message)
48
+ end
49
+ }
50
+
51
+ raise(err)
51
52
  end
52
53
  end
53
54
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ # A class-based container for field configuration and resolution logic. It supports:
6
+ #
7
+ # - Arguments, via `.argument(...)` helper, which will be applied to the field.
8
+ # - Return type, via `.type(..., null: ...)`, which will be applied to the field.
9
+ # - Description, via `.description(...)`, which will be applied to the field
10
+ # - Resolution, via `#resolve(**args)` method, which will be called to resolve the field.
11
+ # - `#object` and `#context` accessors for use during `#resolve`.
12
+ #
13
+ # Resolvers can be attached with the `resolver:` option in a `field(...)` call.
14
+ #
15
+ # A resolver's configuration may be overridden with other keywords in the `field(...)` call.
16
+ #
17
+ # See the {.field_options} to see how a Resolver becomes a set of field configuration options.
18
+ #
19
+ # @see {GraphQL::Schema::Mutation} for a concrete subclass of `Resolver`.
20
+ # @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
21
+ class Resolver
22
+ include Schema::Member::GraphQLTypeNames
23
+ # Really we only need description from here, but:
24
+ extend Schema::Member::BaseDSLMethods
25
+ extend GraphQL::Schema::Member::HasArguments
26
+
27
+ # @param object [Object] the initialize object, pass to {Query.initialize} as `root_value`
28
+ # @param context [GraphQL::Query::Context]
29
+ def initialize(object:, context:)
30
+ @object = object
31
+ @context = context
32
+ end
33
+
34
+ # @return [Object] The application object this field is being resolved on
35
+ attr_reader :object
36
+
37
+ # @return [GraphQL::Query::Context]
38
+ attr_reader :context
39
+
40
+ # Do the work. Everything happens here.
41
+ # @return [Object] An object corresponding to the return type
42
+ def resolve(**args)
43
+ raise NotImplementedError, "#{self.class.name}#resolve should execute the field's logic"
44
+ end
45
+
46
+ class << self
47
+ # Default `:resolve` set below.
48
+ # @return [Symbol] The method to call on instances of this object to resolve the field
49
+ def resolve_method(new_method = nil)
50
+ if new_method
51
+ @resolve_method = new_method
52
+ end
53
+ @resolve_method || (superclass.respond_to?(:resolve_method) ? superclass.resolve_method : :resolve)
54
+ end
55
+
56
+ # Additional info injected into {#resolve}
57
+ # @see {GraphQL::Schema::Field#extras}
58
+ def extras(new_extras = nil)
59
+ if new_extras
60
+ @own_extras = new_extras
61
+ end
62
+ own_extras = @own_extras || []
63
+ own_extras + (superclass.respond_to?(:extras) ? superclass.extras : [])
64
+ end
65
+
66
+ # Specifies whether or not the field is nullable. Defaults to `true`
67
+ # TODO unify with {#type}
68
+ # @param allow_null [Boolean] Whether or not the response can be null
69
+ def null(allow_null = nil)
70
+ if !allow_null.nil?
71
+ @null = allow_null
72
+ end
73
+
74
+ @null.nil? ? (superclass.respond_to?(:null) ? superclass.null : true) : @null
75
+ end
76
+
77
+ # Call this method to get the return type of the field,
78
+ # or use it as a configuration method to assign a return type
79
+ # instead of generating one.
80
+ # TODO unify with {#null}
81
+ # @param new_type [Class, nil] If a type definition class is provided, it will be used as the return type of the field
82
+ # @param null [true, false] Whether or not the field may return `nil`
83
+ # @return [Class] The type which this field returns.
84
+ def type(new_type = nil, null: nil)
85
+ if new_type
86
+ if null.nil?
87
+ raise ArgumentError, "required argument `null:` is missing"
88
+ end
89
+ @type_expr = new_type
90
+ @null = null
91
+ else
92
+ if @type_expr
93
+ GraphQL::Schema::Member::BuildType.parse_type(@type_expr, null: @null)
94
+ elsif superclass.respond_to?(:type)
95
+ superclass.type
96
+ else
97
+ nil
98
+ end
99
+ end
100
+ end
101
+
102
+ def field_options
103
+ {
104
+ type: type_expr,
105
+ description: description,
106
+ extras: extras,
107
+ method: resolve_method,
108
+ resolver_class: self,
109
+ arguments: arguments,
110
+ null: null,
111
+ }
112
+ end
113
+
114
+ # A non-normalized type configuration, without `null` applied
115
+ # @api private
116
+ def type_expr
117
+ @type_expr || (superclass.respond_to?(:type_expr) ? superclass.type_expr : nil)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Scalar < GraphQL::Schema::Member
5
+ extend GraphQL::Schema::Member::AcceptsDefinition
6
+
7
+ class << self
8
+ extend Forwardable
9
+ def_delegators :graphql_definition, :coerce_isolated_input, :coerce_isolated_result
10
+
11
+ def coerce_input(val, ctx)
12
+ val
13
+ end
14
+
15
+ def coerce_result(val, ctx)
16
+ val
17
+ end
18
+
19
+ def to_graphql
20
+ type_defn = GraphQL::ScalarType.new
21
+ type_defn.name = graphql_name
22
+ type_defn.description = description
23
+ type_defn.coerce_result = method(:coerce_result)
24
+ type_defn.coerce_input = method(:coerce_input)
25
+ type_defn.metadata[:type_class] = self
26
+ type_defn
27
+ end
28
+
29
+ def kind
30
+ GraphQL::TypeKinds::SCALAR
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end