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
@@ -0,0 +1,372 @@
1
+ # frozen_string_literal: true
2
+ # test_via: ../object.rb
3
+ module GraphQL
4
+ class Schema
5
+ class Field
6
+ include GraphQL::Schema::Member::CachedGraphQLDefinition
7
+ include GraphQL::Schema::Member::AcceptsDefinition
8
+ include GraphQL::Schema::Member::HasArguments
9
+
10
+ # @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
11
+ attr_accessor :name
12
+
13
+ # @return [String]
14
+ attr_accessor :description
15
+
16
+ # @return [Symbol] Method or hash key to look up
17
+ attr_reader :method_sym
18
+
19
+ # @return [String] Method or hash key to look up
20
+ attr_reader :method_str
21
+
22
+ # @return [Class] The type that this field belongs to
23
+ attr_reader :owner
24
+
25
+
26
+ # @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
27
+ def resolver
28
+ @resolver_class
29
+ end
30
+
31
+ alias :mutation :resolver
32
+
33
+ # Create a field instance from a list of arguments, keyword arguments, and a block.
34
+ #
35
+ # This method implements prioritization between the `resolver` or `mutation` defaults
36
+ # and the local overrides via other keywords.
37
+ #
38
+ # It also normalizes positional arguments into keywords for {Schema::Field#initialize}.
39
+ # @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
40
+ # @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
41
+ # @return [GraphQL::Schema:Field] an instance of `self
42
+ # @see {.initialize} for other options
43
+ def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, **kwargs, &block)
44
+ if (parent_config = resolver || mutation)
45
+ # Get the parent config, merge in local overrides
46
+ kwargs = parent_config.field_options.merge(kwargs)
47
+ # Add a reference to that parent class
48
+ kwargs[:resolver_class] = parent_config
49
+ end
50
+
51
+ if name
52
+ kwargs[:name] = name
53
+ end
54
+
55
+ if !type.nil?
56
+ if type.is_a?(GraphQL::Field)
57
+ raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
58
+ end
59
+ if desc
60
+ if kwargs[:description]
61
+ raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
62
+ end
63
+
64
+ kwargs[:description] = desc
65
+ kwargs[:type] = type
66
+ elsif (kwargs[:field] || kwargs[:function] || resolver || mutation) && type.is_a?(String)
67
+ # The return type should be copied from `field` or `function`, and the second positional argument is the description
68
+ kwargs[:description] = type
69
+ else
70
+ kwargs[:type] = type
71
+ end
72
+ end
73
+ new(**kwargs, &block)
74
+ end
75
+
76
+ # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
77
+ # @param return_type_expr [Class, GraphQL::BaseType, Array] The return type of this field
78
+ # @param desc [String] Field description
79
+ # @param owner [Class] The type that this field belongs to
80
+ # @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
81
+ # @param description [String] Field description
82
+ # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
83
+ # @param method [Symbol] The method to call to resolve this field (defaults to `name`)
84
+ # @param hash_key [Object] The hash key to lookup to resolve this field (defaults to `name` or `name.to_s`)
85
+ # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
86
+ # @param max_page_size [Integer] For connections, the maximum number of items to return from this field
87
+ # @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
88
+ # @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
89
+ # @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
90
+ # @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
91
+ # @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
92
+ # @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
93
+ # @param camelize [Boolean] If true, the field name will be camelized when building the schema
94
+ # @param complexity [Numeric] When provided, set the complexity for this field
95
+ # @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
96
+ def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, connection: nil, max_page_size: nil, resolve: nil, introspection: false, hash_key: nil, camelize: true, complexity: 1, extras: [], resolver_class: nil, subscription_scope: nil, arguments: {}, &definition_block)
97
+
98
+ if name.nil?
99
+ raise ArgumentError, "missing first `name` argument or keyword `name:`"
100
+ end
101
+ if !(field || function || mutation || resolver)
102
+ if type.nil?
103
+ raise ArgumentError, "missing second `type` argument or keyword `type:`"
104
+ end
105
+ if null.nil?
106
+ raise ArgumentError, "missing keyword argument null:"
107
+ end
108
+ end
109
+ if (field || function || resolve || mutation) && extras.any?
110
+ raise ArgumentError, "keyword `extras:` may only be used with method-based resolve, please remove `field:`, `function:`, `resolve:`, or `mutation:`"
111
+ end
112
+ @name = camelize ? Member::BuildType.camelize(name.to_s) : name.to_s
113
+ @description = description
114
+ if field.is_a?(GraphQL::Schema::Field)
115
+ @field_instance = field
116
+ else
117
+ @field = field
118
+ end
119
+ @function = function
120
+ @resolve = resolve
121
+ @deprecation_reason = deprecation_reason
122
+ if method && hash_key
123
+ raise ArgumentError, "Provide `method:` _or_ `hash_key:`, not both. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}`)"
124
+ end
125
+
126
+ # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
127
+ method_name = method || hash_key || Member::BuildType.underscore(name.to_s)
128
+
129
+ @method_str = method_name.to_s
130
+ @method_sym = method_name.to_sym
131
+ @complexity = complexity
132
+ @return_type_expr = type
133
+ @return_type_null = null
134
+ @connection = connection
135
+ @max_page_size = max_page_size
136
+ @introspection = introspection
137
+ @extras = extras
138
+ @resolver_class = resolver_class
139
+
140
+ # Override the default from HasArguments
141
+ @own_arguments = {}
142
+ arguments.each do |name, arg|
143
+ if arg.is_a?(Hash)
144
+ argument(name: name, **arg)
145
+ else
146
+ @own_arguments[name] = arg
147
+ end
148
+ end
149
+
150
+ @owner = owner
151
+ @subscription_scope = subscription_scope
152
+
153
+ if definition_block
154
+ instance_eval(&definition_block)
155
+ end
156
+ end
157
+
158
+ def description(text = nil)
159
+ if text
160
+ @description = text
161
+ else
162
+ @description
163
+ end
164
+ end
165
+
166
+ def complexity(new_complexity)
167
+ case new_complexity
168
+ when Proc
169
+ if new_complexity.parameters.size != 3
170
+ fail(
171
+ "A complexity proc should always accept 3 parameters: ctx, args, child_complexity. "\
172
+ "E.g.: complexity ->(ctx, args, child_complexity) { child_complexity * args[:limit] }"
173
+ )
174
+ else
175
+ @complexity = new_complexity
176
+ end
177
+ when Numeric
178
+ @complexity = new_complexity
179
+ else
180
+ raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
181
+ end
182
+
183
+ end
184
+
185
+ # @return [GraphQL::Field]
186
+ def to_graphql
187
+ # this field was previously defined and passed here, so delegate to it
188
+ if @field_instance
189
+ return @field_instance.to_graphql
190
+ end
191
+
192
+
193
+ field_defn = if @field
194
+ @field.dup
195
+ elsif @function
196
+ GraphQL::Function.build_field(@function)
197
+ else
198
+ GraphQL::Field.new
199
+ end
200
+
201
+ field_defn.name = @name
202
+ if @return_type_expr
203
+ field_defn.type = -> { type }
204
+ end
205
+
206
+ if @connection.nil?
207
+ # Provide default based on type name
208
+ return_type_name = if @field || @function
209
+ Member::BuildType.to_type_name(field_defn.type)
210
+ elsif @return_type_expr
211
+ Member::BuildType.to_type_name(@return_type_expr)
212
+ else
213
+ raise "No connection info possible"
214
+ end
215
+ @connection = return_type_name.end_with?("Connection")
216
+ end
217
+
218
+ if @description
219
+ field_defn.description = @description
220
+ end
221
+
222
+ if @deprecation_reason
223
+ field_defn.deprecation_reason = @deprecation_reason
224
+ end
225
+
226
+ if @resolver_class
227
+ if @resolver_class < GraphQL::Schema::Mutation
228
+ field_defn.mutation = @resolver_class
229
+ end
230
+ field_defn.metadata[:resolver] = @resolver_class
231
+ end
232
+
233
+ field_defn.resolve = self.method(:resolve_field)
234
+ field_defn.connection = @connection
235
+ field_defn.connection_max_page_size = @max_page_size
236
+ field_defn.introspection = @introspection
237
+ field_defn.complexity = @complexity
238
+ field_defn.subscription_scope = @subscription_scope
239
+
240
+ # apply this first, so it can be overriden below
241
+ if @connection
242
+ # TODO: this could be a bit weird, because these fields won't be present
243
+ # after initialization, only in the `to_graphql` response.
244
+ # This calculation _could_ be moved up if need be.
245
+ argument :after, "String", "Returns the elements in the list that come after the specified global ID.", required: false
246
+ argument :before, "String", "Returns the elements in the list that come before the specified global ID.", required: false
247
+ argument :first, "Int", "Returns the first _n_ elements from the list.", required: false
248
+ argument :last, "Int", "Returns the last _n_ elements from the list.", required: false
249
+ end
250
+
251
+ arguments.each do |name, defn|
252
+ arg_graphql = defn.to_graphql
253
+ field_defn.arguments[arg_graphql.name] = arg_graphql
254
+ end
255
+
256
+ # Support a passed-in proc, one way or another
257
+ @resolve_proc = if @resolve
258
+ @resolve
259
+ elsif @function
260
+ @function
261
+ elsif @field
262
+ @field.resolve_proc
263
+ end
264
+
265
+ # Ok, `self` isn't a class, but this is for consistency with the classes
266
+ field_defn.metadata[:type_class] = self
267
+
268
+ field_defn
269
+ end
270
+
271
+ def type
272
+ @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
273
+ rescue
274
+ raise ArgumentError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: #{$!.message}", $!.backtrace
275
+ end
276
+
277
+ # Implement {GraphQL::Field}'s resolve API.
278
+ #
279
+ # Eventually, we might hook up field instances to execution in another way. TBD.
280
+ def resolve_field(obj, args, ctx)
281
+ if @resolve_proc
282
+ # Might be nil, still want to call the func in that case
283
+ inner_obj = obj && obj.object
284
+ @resolve_proc.call(inner_obj, args, ctx)
285
+ elsif @resolver_class
286
+ inner_obj = obj && obj.object
287
+ singleton_inst = @resolver_class.new(object: inner_obj, context: ctx.query.context)
288
+ public_send_field(singleton_inst, args, ctx)
289
+ else
290
+ public_send_field(obj, args, ctx)
291
+ end
292
+ end
293
+
294
+ # Find a way to resolve this field, checking:
295
+ #
296
+ # - Hash keys, if the wrapped object is a hash;
297
+ # - A method on the wrapped object;
298
+ # - Or, raise not implemented.
299
+ #
300
+ # This can be overridden by defining a method on the object type.
301
+ # @param obj [GraphQL::Schema::Object]
302
+ # @param ruby_kwargs [Hash<Symbol => Object>]
303
+ # @param ctx [GraphQL::Query::Context]
304
+ def resolve_field_method(obj, ruby_kwargs, ctx)
305
+ if obj.object.is_a?(Hash)
306
+ inner_object = obj.object
307
+ if inner_object.key?(@method_sym)
308
+ inner_object[@method_sym]
309
+ else
310
+ inner_object[@method_str]
311
+ end
312
+ elsif obj.object.respond_to?(@method_sym)
313
+ if ruby_kwargs.any?
314
+ obj.object.public_send(@method_sym, **ruby_kwargs)
315
+ else
316
+ obj.object.public_send(@method_sym)
317
+ end
318
+ else
319
+ raise <<-ERR
320
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
321
+
322
+ - `#{obj.class}##{@method_sym}`, which did not exist
323
+ - `#{obj.object.class}##{@method_sym}`, which did not exist
324
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
325
+
326
+ To implement this field, define one of the methods above (and check for typos)
327
+ ERR
328
+ end
329
+ end
330
+
331
+ private
332
+
333
+ NO_ARGS = {}.freeze
334
+
335
+ def public_send_field(obj, graphql_args, field_ctx)
336
+ if graphql_args.any? || @extras.any?
337
+ # Splat the GraphQL::Arguments to Ruby keyword arguments
338
+ ruby_kwargs = graphql_args.to_kwargs
339
+ # Apply any `prepare` methods. Not great code organization, can this go somewhere better?
340
+ arguments.each do |name, arg_defn|
341
+ ruby_kwargs_key = arg_defn.keyword
342
+ if ruby_kwargs.key?(ruby_kwargs_key) && arg_defn.prepare
343
+ ruby_kwargs[ruby_kwargs_key] = arg_defn.prepare_value(obj, ruby_kwargs[ruby_kwargs_key])
344
+ end
345
+ end
346
+
347
+ if @connection
348
+ # Remove pagination args before passing it to a user method
349
+ ruby_kwargs.delete(:first)
350
+ ruby_kwargs.delete(:last)
351
+ ruby_kwargs.delete(:before)
352
+ ruby_kwargs.delete(:after)
353
+ end
354
+
355
+ @extras.each do |extra_arg|
356
+ # TODO: provide proper tests for `:ast_node`, `:irep_node`, `:parent`, others?
357
+ ruby_kwargs[extra_arg] = field_ctx.public_send(extra_arg)
358
+ end
359
+ else
360
+ ruby_kwargs = NO_ARGS
361
+ end
362
+
363
+
364
+ if ruby_kwargs.any?
365
+ obj.public_send(@method_sym, **ruby_kwargs)
366
+ else
367
+ obj.public_send(@method_sym)
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ # Find schema members using string paths
6
+ #
7
+ # @example Finding object types
8
+ # MySchema.find("SomeObjectType")
9
+ #
10
+ # @example Finding fields
11
+ # MySchema.find("SomeObjectType.myField")
12
+ #
13
+ # @example Finding arguments
14
+ # MySchema.find("SomeObjectType.myField.anArgument")
15
+ #
16
+ # @example Finding directives
17
+ # MySchema.find("@include")
18
+ #
19
+ class Finder
20
+ class MemberNotFoundError < ArgumentError; end
21
+
22
+ def initialize(schema)
23
+ @schema = schema
24
+ end
25
+
26
+ def find(path)
27
+ path = path.split(".")
28
+ type_or_directive = path.shift
29
+
30
+ if type_or_directive.start_with?("@")
31
+ directive = schema.directives[type_or_directive[1..-1]]
32
+
33
+ if directive.nil?
34
+ raise MemberNotFoundError, "Could not find directive `#{type_or_directive}` in schema."
35
+ end
36
+
37
+ return directive if path.empty?
38
+
39
+ find_in_directive(directive, path: path)
40
+ else
41
+ type = schema.types[type_or_directive]
42
+
43
+ if type.nil?
44
+ raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
45
+ end
46
+
47
+ return type if path.empty?
48
+
49
+ find_in_type(type, path: path)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ attr_reader :schema
56
+
57
+ def find_in_directive(directive, path:)
58
+ argument_name = path.shift
59
+ argument = directive.arguments[argument_name]
60
+
61
+ if argument.nil?
62
+ raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
63
+ end
64
+
65
+ argument
66
+ end
67
+
68
+ def find_in_type(type, path:)
69
+ case type
70
+ when GraphQL::ObjectType
71
+ find_in_fields_type(type, kind: "object", path: path)
72
+ when GraphQL::InterfaceType
73
+ find_in_fields_type(type, kind: "interface", path: path)
74
+ when GraphQL::InputObjectType
75
+ find_in_input_object(type, path: path)
76
+ when GraphQL::UnionType
77
+ # Error out if path that was provided is too long
78
+ # i.e UnionType.PossibleType.aField
79
+ # Use PossibleType.aField instead.
80
+ if invalid = path.first
81
+ raise MemberNotFoundError, "Cannot select union possible type `#{invalid}`. Select the type directly instead."
82
+ end
83
+ when GraphQL::EnumType
84
+ find_in_enum_type(type, path: path)
85
+ end
86
+ end
87
+
88
+ def find_in_fields_type(type, kind:, path:)
89
+ field_name = path.shift
90
+ field = schema.get_field(type, field_name)
91
+
92
+ if field.nil?
93
+ raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type}`."
94
+ end
95
+
96
+ return field if path.empty?
97
+
98
+ find_in_field(field, path: path)
99
+ end
100
+
101
+ def find_in_field(field, path:)
102
+ argument_name = path.shift
103
+ argument = field.arguments[argument_name]
104
+
105
+ if argument.nil?
106
+ raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
107
+ end
108
+
109
+ # Error out if path that was provided is too long
110
+ # i.e Type.field.argument.somethingBad
111
+ if invalid = path.first
112
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on a field."
113
+ end
114
+
115
+ argument
116
+ end
117
+
118
+ def find_in_input_object(input_object, path:)
119
+ field_name = path.shift
120
+ input_field = input_object.input_fields[field_name]
121
+
122
+ if input_field.nil?
123
+ raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object}`."
124
+ end
125
+
126
+ # Error out if path that was provided is too long
127
+ # i.e InputType.inputField.bad
128
+ if invalid = path.first
129
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on an input field."
130
+ end
131
+
132
+ input_field
133
+ end
134
+
135
+ def find_in_enum_type(enum_type, path:)
136
+ value_name = path.shift
137
+ enum_value = enum_type.values[value_name]
138
+
139
+ if enum_value.nil?
140
+ raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type}`."
141
+ end
142
+
143
+ # Error out if path that was provided is too long
144
+ # i.e Enum.VALUE.wat
145
+ if invalid = path.first
146
+ raise MemberNotFoundError, "Cannot select member `#{invalid}` on an enum value."
147
+ end
148
+
149
+ enum_value
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class InputObject < GraphQL::Schema::Member
5
+ extend GraphQL::Schema::Member::AcceptsDefinition
6
+ extend Forwardable
7
+ extend GraphQL::Schema::Member::HasArguments
8
+
9
+ def initialize(values, context:, defaults_used:)
10
+ @context = context
11
+ @arguments = self.class.arguments_class.new(values, context: context, defaults_used: defaults_used)
12
+ # Symbolized, underscored hash:
13
+ @ruby_style_hash = @arguments.to_kwargs
14
+ # Apply prepares, not great to have it duplicated here.
15
+ self.class.arguments.each do |name, arg_defn|
16
+ ruby_kwargs_key = arg_defn.keyword
17
+ if @ruby_style_hash.key?(ruby_kwargs_key) && arg_defn.prepare
18
+ @ruby_style_hash[ruby_kwargs_key] = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
19
+ end
20
+ end
21
+ end
22
+
23
+ # @return [GraphQL::Query::Context] The context for this query
24
+ attr_reader :context
25
+
26
+ # @return [GraphQL::Query::Arguments] The underlying arguments instance
27
+ attr_reader :arguments
28
+
29
+ # Ruby-like hash behaviors, read-only
30
+ def_delegators :@ruby_style_hash, :to_h, :keys, :values, :each, :any?
31
+
32
+ # Lookup a key on this object, it accepts new-style underscored symbols
33
+ # Or old-style camelized identifiers.
34
+ # @param key [Symbol, String]
35
+ def [](key)
36
+ if @ruby_style_hash.key?(key)
37
+ @ruby_style_hash[key]
38
+ else
39
+ @arguments[key]
40
+ end
41
+ end
42
+
43
+ def key?(key)
44
+ @ruby_style_hash.key?(key) || @arguments.key?(key)
45
+ end
46
+
47
+ # A copy of the Ruby-style hash
48
+ def to_kwargs
49
+ @ruby_style_hash.dup
50
+ end
51
+
52
+ class << self
53
+ # @return [Class<GraphQL::Arguments>]
54
+ attr_accessor :arguments_class
55
+
56
+ def argument(*args)
57
+ argument_defn = super
58
+ # Add a method access
59
+ arg_name = argument_defn.graphql_definition.name
60
+ define_method(Member::BuildType.underscore(arg_name)) do
61
+ @arguments.public_send(arg_name)
62
+ end
63
+ end
64
+
65
+ def to_graphql
66
+ type_defn = GraphQL::InputObjectType.new
67
+ type_defn.name = graphql_name
68
+ type_defn.description = description
69
+ type_defn.metadata[:type_class] = self
70
+ type_defn.mutation = mutation
71
+ arguments.each do |name, arg|
72
+ type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
73
+ end
74
+ # Make a reference to a classic-style Arguments class
75
+ self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
76
+ # But use this InputObject class at runtime
77
+ type_defn.arguments_class = self
78
+ type_defn
79
+ end
80
+
81
+ def kind
82
+ GraphQL::TypeKinds::INPUT_OBJECT
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end