graphql 1.7.6 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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