graphql 1.8.7 → 1.9.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 (368) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +2 -1
  3. data/lib/generators/graphql/scalar_generator.rb +20 -0
  4. data/lib/generators/graphql/templates/base_scalar.erb +4 -0
  5. data/lib/generators/graphql/templates/scalar.erb +13 -0
  6. data/lib/graphql/analysis/ast/analyzer.rb +62 -0
  7. data/lib/graphql/analysis/ast/field_usage.rb +28 -0
  8. data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
  9. data/lib/graphql/analysis/ast/max_query_depth.rb +18 -0
  10. data/lib/graphql/analysis/ast/query_complexity.rb +114 -0
  11. data/lib/graphql/analysis/ast/query_depth.rb +66 -0
  12. data/lib/graphql/analysis/ast/visitor.rb +255 -0
  13. data/lib/graphql/analysis/ast.rb +82 -0
  14. data/lib/graphql/analysis.rb +1 -0
  15. data/lib/graphql/argument.rb +5 -0
  16. data/lib/graphql/authorization.rb +1 -0
  17. data/lib/graphql/backwards_compatibility.rb +1 -1
  18. data/lib/graphql/base_type.rb +1 -1
  19. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
  20. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -6
  21. data/lib/graphql/dig.rb +19 -0
  22. data/lib/graphql/directive/include_directive.rb +1 -7
  23. data/lib/graphql/directive/skip_directive.rb +1 -8
  24. data/lib/graphql/directive.rb +13 -1
  25. data/lib/graphql/enum_type.rb +8 -0
  26. data/lib/graphql/execution/execute.rb +36 -17
  27. data/lib/graphql/execution/instrumentation.rb +2 -0
  28. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  29. data/lib/graphql/execution/interpreter/hash_response.rb +46 -0
  30. data/lib/graphql/execution/interpreter/resolve.rb +58 -0
  31. data/lib/graphql/execution/interpreter/runtime.rb +597 -0
  32. data/lib/graphql/execution/interpreter.rb +99 -0
  33. data/lib/graphql/execution/lazy.rb +8 -1
  34. data/lib/graphql/execution/lookahead.rb +351 -0
  35. data/lib/graphql/execution/multiplex.rb +37 -29
  36. data/lib/graphql/execution.rb +2 -0
  37. data/lib/graphql/execution_error.rb +1 -1
  38. data/lib/graphql/field.rb +1 -7
  39. data/lib/graphql/integer_encoding_error.rb +12 -0
  40. data/lib/graphql/internal_representation/rewrite.rb +127 -142
  41. data/lib/graphql/introspection/dynamic_fields.rb +8 -2
  42. data/lib/graphql/introspection/entry_points.rb +11 -6
  43. data/lib/graphql/introspection/enum_value_type.rb +4 -0
  44. data/lib/graphql/introspection/schema_type.rb +7 -2
  45. data/lib/graphql/introspection/type_type.rb +9 -5
  46. data/lib/graphql/invalid_null_error.rb +1 -1
  47. data/lib/graphql/language/block_string.rb +37 -0
  48. data/lib/graphql/language/document_from_schema_definition.rb +10 -7
  49. data/lib/graphql/language/lexer.rb +55 -36
  50. data/lib/graphql/language/lexer.rl +8 -3
  51. data/lib/graphql/language/nodes.rb +440 -362
  52. data/lib/graphql/language/parser.rb +56 -56
  53. data/lib/graphql/language/parser.y +12 -12
  54. data/lib/graphql/language/printer.rb +2 -2
  55. data/lib/graphql/language/visitor.rb +158 -15
  56. data/lib/graphql/language.rb +0 -1
  57. data/lib/graphql/literal_validation_error.rb +6 -0
  58. data/lib/graphql/query/arguments.rb +3 -2
  59. data/lib/graphql/query/arguments_cache.rb +1 -1
  60. data/lib/graphql/query/context.rb +14 -5
  61. data/lib/graphql/query/executor.rb +1 -1
  62. data/lib/graphql/query/result.rb +1 -1
  63. data/lib/graphql/query/validation_pipeline.rb +35 -11
  64. data/lib/graphql/query/variable_validation_error.rb +10 -1
  65. data/lib/graphql/query.rb +16 -2
  66. data/lib/graphql/relay/base_connection.rb +2 -0
  67. data/lib/graphql/relay/connection_instrumentation.rb +3 -1
  68. data/lib/graphql/relay/connection_resolve.rb +1 -1
  69. data/lib/graphql/relay/node.rb +2 -28
  70. data/lib/graphql/relay/relation_connection.rb +1 -1
  71. data/lib/graphql/schema/argument.rb +13 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +4 -4
  73. data/lib/graphql/schema/build_from_definition.rb +2 -4
  74. data/lib/graphql/schema/default_type_error.rb +1 -1
  75. data/lib/graphql/schema/directive/feature.rb +66 -0
  76. data/lib/graphql/schema/directive/include.rb +25 -0
  77. data/lib/graphql/schema/directive/skip.rb +25 -0
  78. data/lib/graphql/schema/directive/transform.rb +48 -0
  79. data/lib/graphql/schema/directive.rb +103 -0
  80. data/lib/graphql/schema/enum_value.rb +3 -2
  81. data/lib/graphql/schema/field/connection_extension.rb +50 -0
  82. data/lib/graphql/schema/field/scope_extension.rb +18 -0
  83. data/lib/graphql/schema/field.rb +273 -64
  84. data/lib/graphql/schema/field_extension.rb +69 -0
  85. data/lib/graphql/schema/input_object.rb +16 -8
  86. data/lib/graphql/schema/interface.rb +1 -0
  87. data/lib/graphql/schema/loader.rb +22 -16
  88. data/lib/graphql/schema/member/base_dsl_methods.rb +8 -2
  89. data/lib/graphql/schema/member/build_type.rb +33 -1
  90. data/lib/graphql/schema/member/has_arguments.rb +6 -2
  91. data/lib/graphql/schema/member/has_fields.rb +18 -70
  92. data/lib/graphql/schema/member/has_path.rb +25 -0
  93. data/lib/graphql/schema/member/instrumentation.rb +10 -7
  94. data/lib/graphql/schema/member.rb +2 -0
  95. data/lib/graphql/schema/mutation.rb +6 -48
  96. data/lib/graphql/schema/non_null.rb +5 -1
  97. data/lib/graphql/schema/object.rb +18 -4
  98. data/lib/graphql/schema/printer.rb +1 -1
  99. data/lib/graphql/schema/relay_classic_mutation.rb +42 -9
  100. data/lib/graphql/schema/resolver/has_payload_type.rb +65 -0
  101. data/lib/graphql/schema/resolver.rb +45 -20
  102. data/lib/graphql/schema/subscription.rb +97 -0
  103. data/lib/graphql/schema/traversal.rb +11 -7
  104. data/lib/graphql/schema.rb +186 -38
  105. data/lib/graphql/static_validation/all_rules.rb +3 -2
  106. data/lib/graphql/static_validation/base_visitor.rb +199 -0
  107. data/lib/graphql/static_validation/default_visitor.rb +15 -0
  108. data/lib/graphql/static_validation/definition_dependencies.rb +62 -68
  109. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  110. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  111. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  112. data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
  113. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +87 -16
  114. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  115. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +11 -11
  116. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  117. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +52 -8
  118. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  119. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -15
  120. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  121. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +19 -14
  122. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  123. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +17 -19
  124. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  125. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +30 -14
  126. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  127. data/lib/graphql/static_validation/rules/fields_will_merge.rb +356 -29
  128. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  129. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +20 -13
  130. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  131. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +37 -29
  132. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  133. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +25 -17
  134. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  135. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +12 -10
  136. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  137. data/lib/graphql/static_validation/rules/fragments_are_named.rb +7 -11
  138. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  139. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +16 -16
  140. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  141. data/lib/graphql/static_validation/rules/fragments_are_used.rb +21 -14
  142. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  143. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +10 -14
  144. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  145. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +30 -30
  146. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  147. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +25 -17
  148. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  149. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +17 -18
  150. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  151. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  152. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  153. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +10 -14
  154. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  155. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +28 -17
  156. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  157. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +35 -27
  158. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  159. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +15 -14
  160. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  161. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -30
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +18 -14
  164. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  165. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +73 -65
  166. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  167. data/lib/graphql/static_validation/validation_context.rb +8 -51
  168. data/lib/graphql/static_validation/validator.rb +23 -15
  169. data/lib/graphql/static_validation.rb +5 -3
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -2
  171. data/lib/graphql/subscriptions/event.rb +28 -5
  172. data/lib/graphql/subscriptions/subscription_root.rb +66 -0
  173. data/lib/graphql/subscriptions.rb +16 -2
  174. data/lib/graphql/tracing/active_support_notifications_tracing.rb +0 -1
  175. data/lib/graphql/tracing/appsignal_tracing.rb +1 -1
  176. data/lib/graphql/tracing/data_dog_tracing.rb +1 -1
  177. data/lib/graphql/tracing/new_relic_tracing.rb +3 -3
  178. data/lib/graphql/tracing/platform_tracing.rb +17 -1
  179. data/lib/graphql/tracing/prometheus_tracing.rb +1 -1
  180. data/lib/graphql/tracing/scout_tracing.rb +1 -1
  181. data/lib/graphql/tracing/skylight_tracing.rb +3 -3
  182. data/lib/graphql/tracing.rb +8 -8
  183. data/lib/graphql/types/float.rb +1 -1
  184. data/lib/graphql/types/int.rb +11 -2
  185. data/lib/graphql/types/iso_8601_date_time.rb +15 -1
  186. data/lib/graphql/types/relay/base_connection.rb +15 -1
  187. data/lib/graphql/types/relay/node.rb +0 -1
  188. data/lib/graphql/types/relay/node_field.rb +43 -0
  189. data/lib/graphql/types/relay/nodes_field.rb +45 -0
  190. data/lib/graphql/types/relay.rb +2 -0
  191. data/lib/graphql/unauthorized_error.rb +4 -0
  192. data/lib/graphql/unauthorized_field_error.rb +23 -0
  193. data/lib/graphql/upgrader/member.rb +5 -0
  194. data/lib/graphql/version.rb +1 -1
  195. data/lib/graphql.rb +6 -1
  196. data/readme.md +7 -7
  197. data/spec/dummy/Gemfile +1 -1
  198. data/spec/dummy/Gemfile.lock +157 -0
  199. data/spec/dummy/app/channels/graphql_channel.rb +22 -11
  200. data/spec/dummy/config/locales/en.yml +1 -1
  201. data/spec/dummy/log/test.log +199 -0
  202. data/spec/dummy/test/test_helper.rb +1 -0
  203. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
  204. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +1 -0
  205. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +1 -0
  206. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +1 -0
  207. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +3 -0
  208. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
  209. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +2 -0
  210. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +2 -0
  211. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
  212. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
  213. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +1 -0
  214. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
  215. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +1 -0
  216. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +3 -0
  217. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +1 -0
  218. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +1 -0
  219. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
  220. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +1 -0
  221. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
  222. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  223. data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
  224. data/spec/graphql/analysis/ast/field_usage_spec.rb +51 -0
  225. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +120 -0
  226. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +114 -0
  227. data/spec/graphql/analysis/ast/query_complexity_spec.rb +299 -0
  228. data/spec/graphql/analysis/ast/query_depth_spec.rb +108 -0
  229. data/spec/graphql/analysis/ast_spec.rb +269 -0
  230. data/spec/graphql/authorization_spec.rb +120 -23
  231. data/spec/graphql/base_type_spec.rb +6 -4
  232. data/spec/graphql/enum_type_spec.rb +6 -1
  233. data/spec/graphql/execution/execute_spec.rb +9 -9
  234. data/spec/graphql/execution/instrumentation_spec.rb +19 -0
  235. data/spec/graphql/execution/interpreter_spec.rb +485 -0
  236. data/spec/graphql/execution/lazy_spec.rb +67 -1
  237. data/spec/graphql/execution/lookahead_spec.rb +363 -0
  238. data/spec/graphql/execution/multiplex_spec.rb +31 -3
  239. data/spec/graphql/execution/typecast_spec.rb +20 -20
  240. data/spec/graphql/execution_error_spec.rb +110 -96
  241. data/spec/graphql/field_spec.rb +1 -1
  242. data/spec/graphql/input_object_type_spec.rb +13 -352
  243. data/spec/graphql/int_type_spec.rb +19 -0
  244. data/spec/graphql/interface_type_spec.rb +4 -4
  245. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -0
  246. data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
  247. data/spec/graphql/introspection/type_type_spec.rb +1 -2
  248. data/spec/graphql/language/document_from_schema_definition_spec.rb +2 -2
  249. data/spec/graphql/language/lexer_spec.rb +72 -3
  250. data/spec/graphql/language/nodes_spec.rb +20 -0
  251. data/spec/graphql/language/printer_spec.rb +18 -6
  252. data/spec/graphql/language/visitor_spec.rb +320 -14
  253. data/spec/graphql/non_null_type_spec.rb +1 -1
  254. data/spec/graphql/object_type_spec.rb +32 -27
  255. data/spec/graphql/query/arguments_spec.rb +21 -0
  256. data/spec/graphql/query/context_spec.rb +28 -0
  257. data/spec/graphql/query/executor_spec.rb +40 -36
  258. data/spec/graphql/query_spec.rb +12 -6
  259. data/spec/graphql/schema/argument_spec.rb +35 -1
  260. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  261. data/spec/graphql/schema/catchall_middleware_spec.rb +16 -15
  262. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  263. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  264. data/spec/graphql/schema/enum_spec.rb +12 -3
  265. data/spec/graphql/schema/enum_value_spec.rb +11 -0
  266. data/spec/graphql/schema/field_extension_spec.rb +115 -0
  267. data/spec/graphql/schema/field_spec.rb +47 -7
  268. data/spec/graphql/schema/input_object_spec.rb +95 -0
  269. data/spec/graphql/schema/instrumentation_spec.rb +3 -0
  270. data/spec/graphql/schema/interface_spec.rb +8 -2
  271. data/spec/graphql/schema/introspection_system_spec.rb +9 -1
  272. data/spec/graphql/schema/loader_spec.rb +5 -0
  273. data/spec/graphql/schema/member/accepts_definition_spec.rb +4 -0
  274. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  275. data/spec/graphql/schema/member/scoped_spec.rb +19 -3
  276. data/spec/graphql/schema/mutation_spec.rb +5 -3
  277. data/spec/graphql/schema/object_spec.rb +9 -1
  278. data/spec/graphql/schema/printer_spec.rb +255 -93
  279. data/spec/graphql/schema/relay_classic_mutation_spec.rb +133 -0
  280. data/spec/graphql/schema/resolver_spec.rb +173 -9
  281. data/spec/graphql/schema/scalar_spec.rb +6 -0
  282. data/spec/graphql/schema/subscription_spec.rb +416 -0
  283. data/spec/graphql/schema/traversal_spec.rb +10 -10
  284. data/spec/graphql/schema/type_expression_spec.rb +2 -2
  285. data/spec/graphql/schema/union_spec.rb +7 -0
  286. data/spec/graphql/schema/validation_spec.rb +1 -1
  287. data/spec/graphql/schema/warden_spec.rb +145 -88
  288. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +213 -73
  289. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  290. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  291. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  292. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  293. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  294. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  295. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +131 -5
  296. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  297. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  298. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  299. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  300. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  301. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  302. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  303. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  304. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  305. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  306. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  307. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  308. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  309. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  310. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  311. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  312. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +23 -3
  313. data/spec/graphql/static_validation/type_stack_spec.rb +10 -19
  314. data/spec/graphql/static_validation/validator_spec.rb +50 -2
  315. data/spec/graphql/subscriptions_spec.rb +27 -16
  316. data/spec/graphql/tracing/new_relic_tracing_spec.rb +16 -0
  317. data/spec/graphql/tracing/platform_tracing_spec.rb +59 -37
  318. data/spec/graphql/tracing/prometheus_tracing_spec.rb +3 -0
  319. data/spec/graphql/tracing/skylight_tracing_spec.rb +16 -0
  320. data/spec/graphql/types/iso_8601_date_time_spec.rb +29 -2
  321. data/spec/graphql/union_type_spec.rb +2 -2
  322. data/spec/graphql/upgrader/member_spec.rb +67 -0
  323. data/spec/{graphql → integration/mongoid/graphql}/relay/mongo_relation_connection_spec.rb +11 -22
  324. data/spec/integration/mongoid/spec_helper.rb +2 -0
  325. data/spec/{support → integration/mongoid}/star_trek/data.rb +0 -0
  326. data/spec/{support → integration/mongoid}/star_trek/schema.rb +56 -34
  327. data/spec/{support/star_wars → integration/rails}/data.rb +1 -0
  328. data/spec/{support → integration/rails/generators}/base_generator_test.rb +0 -0
  329. data/spec/{generators → integration/rails/generators}/graphql/enum_generator_spec.rb +0 -0
  330. data/spec/{generators → integration/rails/generators}/graphql/install_generator_spec.rb +1 -1
  331. data/spec/{generators → integration/rails/generators}/graphql/interface_generator_spec.rb +0 -0
  332. data/spec/{generators → integration/rails/generators}/graphql/loader_generator_spec.rb +0 -0
  333. data/spec/{generators → integration/rails/generators}/graphql/mutation_generator_spec.rb +0 -0
  334. data/spec/{generators → integration/rails/generators}/graphql/object_generator_spec.rb +0 -0
  335. data/spec/integration/rails/generators/graphql/scalar_generator_spec.rb +28 -0
  336. data/spec/{generators → integration/rails/generators}/graphql/union_generator_spec.rb +0 -0
  337. data/spec/integration/rails/graphql/input_object_type_spec.rb +364 -0
  338. data/spec/{graphql → integration/rails/graphql}/query/variables_spec.rb +7 -7
  339. data/spec/{graphql → integration/rails/graphql}/relay/array_connection_spec.rb +9 -9
  340. data/spec/{graphql → integration/rails/graphql}/relay/base_connection_spec.rb +11 -3
  341. data/spec/{graphql → integration/rails/graphql}/relay/connection_instrumentation_spec.rb +19 -22
  342. data/spec/{graphql → integration/rails/graphql}/relay/connection_resolve_spec.rb +16 -0
  343. data/spec/{graphql → integration/rails/graphql}/relay/connection_type_spec.rb +0 -0
  344. data/spec/{graphql → integration/rails/graphql}/relay/edge_spec.rb +0 -0
  345. data/spec/{graphql → integration/rails/graphql}/relay/mutation_spec.rb +48 -0
  346. data/spec/{graphql → integration/rails/graphql}/relay/node_spec.rb +0 -0
  347. data/spec/{graphql → integration/rails/graphql}/relay/page_info_spec.rb +22 -22
  348. data/spec/{graphql → integration/rails/graphql}/relay/range_add_spec.rb +4 -4
  349. data/spec/{graphql → integration/rails/graphql}/relay/relation_connection_spec.rb +56 -27
  350. data/spec/{graphql → integration/rails/graphql}/schema_spec.rb +15 -11
  351. data/spec/{graphql → integration/rails/graphql}/tracing/active_support_notifications_tracing_spec.rb +16 -9
  352. data/spec/integration/rails/spec_helper.rb +25 -0
  353. data/spec/integration/tmp/app/graphql/types/family_type.rb +9 -0
  354. data/spec/spec_helper.rb +23 -39
  355. data/spec/support/dummy/data.rb +20 -17
  356. data/spec/support/dummy/schema.rb +315 -305
  357. data/spec/support/error_bubbling_helpers.rb +23 -0
  358. data/spec/support/jazz.rb +213 -46
  359. data/spec/support/lazy_helpers.rb +69 -27
  360. data/spec/support/new_relic.rb +3 -0
  361. data/spec/support/skylight.rb +3 -0
  362. data/spec/support/star_wars/schema.rb +131 -81
  363. data/spec/support/static_validation_helpers.rb +9 -5
  364. metadata +418 -261
  365. data/lib/graphql/language/comments.rb +0 -45
  366. data/lib/graphql/static_validation/arguments_validator.rb +0 -50
  367. data/spec/graphql/schema/member/has_fields_spec.rb +0 -129
  368. data/spec/rails_dependency_sanity_spec.rb +0 -14
@@ -37,7 +37,7 @@ module GraphQL
37
37
  end
38
38
 
39
39
  def inspect
40
- "#<GraphQL::Query::Result @query=... @to_h=#{@to_h} >"
40
+ "#<GraphQL::Query::Result @query=... @to_h=#{@to_h}>"
41
41
  end
42
42
 
43
43
  # A result is equal to another object when:
@@ -14,6 +14,8 @@ module GraphQL
14
14
  #
15
15
  # @api private
16
16
  class ValidationPipeline
17
+ attr_reader :max_depth, :max_complexity
18
+
17
19
  def initialize(query:, validate:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
18
20
  @validation_errors = []
19
21
  @internal_representation = nil
@@ -34,7 +36,7 @@ module GraphQL
34
36
  @valid
35
37
  end
36
38
 
37
- # @return [Array<GraphQL::StaticValidation::Message>] Static validation errors for the query string
39
+ # @return [Array<GraphQL::StaticValidation::Error >] Static validation errors for the query string
38
40
  def validation_errors
39
41
  ensure_has_validated
40
42
  @validation_errors
@@ -74,11 +76,11 @@ module GraphQL
74
76
  @validation_errors.concat(validation_result[:errors])
75
77
  @internal_representation = validation_result[:irep]
76
78
 
77
- if @validation_errors.none?
79
+ if @validation_errors.empty?
78
80
  @validation_errors.concat(@query.variables.errors)
79
81
  end
80
82
 
81
- if @validation_errors.none?
83
+ if @validation_errors.empty?
82
84
  @query_analyzers = build_analyzers(
83
85
  @schema,
84
86
  @max_depth,
@@ -87,24 +89,46 @@ module GraphQL
87
89
  end
88
90
  end
89
91
 
90
- @valid = @validation_errors.none?
92
+ @valid = @validation_errors.empty?
91
93
  end
92
94
 
93
95
  # If there are max_* values, add them,
94
96
  # otherwise reuse the schema's list of analyzers.
95
97
  def build_analyzers(schema, max_depth, max_complexity)
96
- if max_depth || max_complexity
97
- qa = schema.query_analyzers.dup
98
+ qa = schema.query_analyzers.dup
98
99
 
99
- if max_depth
100
- qa << GraphQL::Analysis::MaxQueryDepth.new(max_depth)
100
+ # Filter out the built in authorization analyzer.
101
+ # It is deprecated and does not have an AST analyzer alternative.
102
+ qa = qa.select do |analyzer|
103
+ if analyzer == GraphQL::Authorization::Analyzer && schema.using_ast_analysis?
104
+ raise "The Authorization analyzer is not supported with AST Analyzers"
105
+ else
106
+ true
101
107
  end
102
- if max_complexity
103
- qa << GraphQL::Analysis::MaxQueryComplexity.new(max_complexity)
108
+ end
109
+
110
+ if max_depth || max_complexity
111
+ # Depending on the analysis engine, we must use different analyzers
112
+ # remove this once everything has switched over to AST analyzers
113
+ if schema.using_ast_analysis?
114
+ if max_depth
115
+ qa << GraphQL::Analysis::AST::MaxQueryDepth
116
+ end
117
+ if max_complexity
118
+ qa << GraphQL::Analysis::AST::MaxQueryComplexity
119
+ end
120
+ else
121
+ if max_depth
122
+ qa << GraphQL::Analysis::MaxQueryDepth.new(max_depth)
123
+ end
124
+ if max_complexity
125
+ qa << GraphQL::Analysis::MaxQueryComplexity.new(max_complexity)
126
+ end
104
127
  end
128
+
105
129
  qa
106
130
  else
107
- schema.query_analyzers
131
+ qa
108
132
  end
109
133
  end
110
134
  end
@@ -14,7 +14,16 @@ module GraphQL
14
14
  end
15
15
 
16
16
  def to_h
17
- super.merge({ "value" => value, "problems" => validation_result.problems })
17
+ # It is possible there are other extension items in this error, so handle
18
+ # a one level deep merge explicitly. However beyond that only show the
19
+ # latest value and problems.
20
+ super.merge({ "extensions" => { "value" => value, "problems" => validation_result.problems }}) do |key, oldValue, newValue|
21
+ if oldValue.respond_to? merge
22
+ oldValue.merge(newValue)
23
+ else
24
+ newValue
25
+ end
26
+ end
18
27
  end
19
28
  end
20
29
  end
data/lib/graphql/query.rb CHANGED
@@ -135,10 +135,23 @@ module GraphQL
135
135
  end
136
136
  end
137
137
 
138
+ def_delegators :@schema, :interpreter?
139
+
138
140
  def subscription_update?
139
141
  @subscription_topic && subscription?
140
142
  end
141
143
 
144
+ # A lookahead for the root selections of this query
145
+ # @return [GraphQL::Execution::Lookahead]
146
+ def lookahead
147
+ @lookahead ||= begin
148
+ ast_node = selected_operation
149
+ root_type = warden.root_type_for_operation(ast_node.operation_type || "query")
150
+ root_type = root_type.metadata[:type_class] || raise("Invariant: `lookahead` only works with class-based types")
151
+ GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
152
+ end
153
+ end
154
+
142
155
  # @api private
143
156
  def result_values=(result_hash)
144
157
  if @executed
@@ -221,11 +234,12 @@ module GraphQL
221
234
  with_prepared_ast { @validation_pipeline }
222
235
  end
223
236
 
224
- def_delegators :validation_pipeline, :validation_errors, :internal_representation, :analyzers
237
+ def_delegators :validation_pipeline, :validation_errors, :internal_representation,
238
+ :analyzers, :ast_analyzers, :max_depth, :max_complexity
225
239
 
226
240
  attr_accessor :analysis_errors
227
241
  def valid?
228
- validation_pipeline.valid? && analysis_errors.none?
242
+ validation_pipeline.valid? && analysis_errors.empty?
229
243
  end
230
244
 
231
245
  def warden
@@ -70,6 +70,8 @@ module GraphQL
70
70
 
71
71
  def decode(data)
72
72
  @encoder.decode(data, nonce: true)
73
+ rescue ArgumentError
74
+ raise GraphQL::ExecutionError, "Invalid cursor: #{data.inspect}"
73
75
  end
74
76
 
75
77
  # The value passed as `first:`, if there was one. Negative numbers become `0`.
@@ -32,7 +32,9 @@ module GraphQL
32
32
  # - Merging in the default arguments
33
33
  # - Transforming its resolve function to return a connection object
34
34
  def self.instrument(type, field)
35
- if field.connection?
35
+ # Don't apply the wrapper to class-based fields, since they
36
+ # use Schema::Field::ConnectionFilter
37
+ if field.connection? && !field.metadata[:type_class]
36
38
  connection_arguments = default_arguments.merge(field.arguments)
37
39
  original_resolve = field.resolve_proc
38
40
  original_lazy_resolve = field.lazy_resolve_proc
@@ -9,7 +9,7 @@ module GraphQL
9
9
  end
10
10
 
11
11
  def call(obj, args, ctx)
12
- # in a lazy ressolve hook, obj is the promise,
12
+ # in a lazy resolve hook, obj is the promise,
13
13
  # get the object that the promise was
14
14
  # originally derived from
15
15
  parent = ctx.object
@@ -8,13 +8,7 @@ module GraphQL
8
8
  # We have to define it fresh each time because
9
9
  # its name will be modified and its description
10
10
  # _may_ be modified.
11
- field = GraphQL::Field.define do
12
- type(GraphQL::Relay::Node.interface)
13
- description("Fetches an object given its ID.")
14
- argument(:id, types.ID.to_non_null_type, "ID of the object.")
15
- resolve(GraphQL::Relay::Node::FindNode)
16
- relay_node_field(true)
17
- end
11
+ field = GraphQL::Types::Relay::NodeField.graphql_definition
18
12
 
19
13
  if kwargs.any? || block
20
14
  field = field.redefine(kwargs, &block)
@@ -24,13 +18,7 @@ module GraphQL
24
18
  end
25
19
 
26
20
  def self.plural_field(**kwargs, &block)
27
- field = GraphQL::Field.define do
28
- type(!types[GraphQL::Relay::Node.interface])
29
- description("Fetches a list of objects given a list of IDs.")
30
- argument(:ids, types.ID.to_non_null_type.to_list_type.to_non_null_type, "IDs of the objects.")
31
- resolve(GraphQL::Relay::Node::FindNodes)
32
- relay_nodes_field(true)
33
- end
21
+ field = GraphQL::Types::Relay::NodesField.graphql_definition
34
22
 
35
23
  if kwargs.any? || block
36
24
  field = field.redefine(kwargs, &block)
@@ -43,20 +31,6 @@ module GraphQL
43
31
  def self.interface
44
32
  @interface ||= GraphQL::Types::Relay::Node.graphql_definition
45
33
  end
46
-
47
- # A field resolve for finding objects by IDs
48
- module FindNodes
49
- def self.call(obj, args, ctx)
50
- args[:ids].map { |id| ctx.query.schema.object_from_id(id, ctx) }
51
- end
52
- end
53
-
54
- # A field resolve for finding an object by ID
55
- module FindNode
56
- def self.call(obj, args, ctx)
57
- ctx.query.schema.object_from_id(args[:id], ctx )
58
- end
59
- end
60
34
  end
61
35
  end
62
36
  end
@@ -124,7 +124,7 @@ module GraphQL
124
124
  # If a relation contains a `.group` clause, a `.count` will return a Hash.
125
125
  def relation_count(relation)
126
126
  count_or_hash = if(defined?(ActiveRecord::Relation) && relation.is_a?(ActiveRecord::Relation))
127
- relation.count(:all)
127
+ relation.respond_to?(:unscope)? relation.unscope(:order).count(:all) : relation.count(:all)
128
128
  else # eg, Sequel::Dataset, don't mess up others
129
129
  relation.count
130
130
  end
@@ -4,6 +4,7 @@ module GraphQL
4
4
  class Argument
5
5
  include GraphQL::Schema::Member::CachedGraphQLDefinition
6
6
  include GraphQL::Schema::Member::AcceptsDefinition
7
+ include GraphQL::Schema::Member::HasPath
7
8
 
8
9
  NO_DEFAULT = :__no_default__
9
10
 
@@ -27,7 +28,7 @@ module GraphQL
27
28
  # @param description [String]
28
29
  # @param default_value [Object]
29
30
  # @param as [Symbol] Override the keyword name when passed to a method
30
- # @param prepare [Symbol] A method to call to tranform this argument's valuebefore sending it to field resolution
31
+ # @param prepare [Symbol] A method to call to transform this argument's valuebefore sending it to field resolution
31
32
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
32
33
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, description: nil, default_value: NO_DEFAULT, as: nil, camelize: true, prepare: nil, owner:, &definition_block)
33
34
  arg_name ||= name
@@ -50,6 +51,14 @@ module GraphQL
50
51
  end
51
52
  end
52
53
 
54
+ # @return [Object] the value used when the client doesn't provide a value for this argument
55
+ attr_reader :default_value
56
+
57
+ # @return [Boolean] True if this argument has a default value
58
+ def default_value?
59
+ @default_value != NO_DEFAULT
60
+ end
61
+
53
62
  attr_writer :description
54
63
 
55
64
  # @return [String] Documentation for this argument
@@ -96,12 +105,11 @@ module GraphQL
96
105
  # Used by the runtime.
97
106
  # @api private
98
107
  def prepare_value(obj, value)
99
- case @prepare
100
- when nil
108
+ if @prepare.nil?
101
109
  value
102
- when Symbol, String
110
+ elsif @prepare.is_a?(String) || @prepare.is_a?(Symbol)
103
111
  obj.public_send(@prepare, value)
104
- when Proc
112
+ elsif @prepare.respond_to?(:call)
105
113
  @prepare.call(value, obj.context)
106
114
  else
107
115
  raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
@@ -6,13 +6,13 @@ module GraphQL
6
6
  class Schema
7
7
  # @api private
8
8
  module Base64Encoder
9
- def self.encode(plaintext, nonce: false)
10
- Base64.strict_encode64(plaintext)
9
+ def self.encode(unencoded_text, nonce: false)
10
+ Base64Bp.urlsafe_encode64(unencoded_text, padding: false)
11
11
  end
12
12
 
13
- def self.decode(ciphertext, nonce: false)
13
+ def self.decode(encoded_text, nonce: false)
14
14
  # urlsafe_decode64 is for forward compatibility
15
- Base64Bp.urlsafe_decode64(ciphertext)
15
+ Base64Bp.urlsafe_decode64(encoded_text)
16
16
  end
17
17
  end
18
18
  end
@@ -64,9 +64,7 @@ module GraphQL
64
64
  end
65
65
  end
66
66
 
67
- GraphQL::Schema::DIRECTIVES.each do |built_in_directive|
68
- directives[built_in_directive.name] = built_in_directive unless directives[built_in_directive.name]
69
- end
67
+ directives = GraphQL::Schema.default_directives.merge(directives)
70
68
 
71
69
  if schema_definition
72
70
  if schema_definition.query
@@ -113,7 +111,7 @@ module GraphQL
113
111
  end
114
112
 
115
113
  NullResolveType = ->(type, obj, ctx) {
116
- raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution.")
114
+ raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
117
115
  }
118
116
 
119
117
  NullScalarCoerce = ->(val, _ctx) { val }
@@ -6,7 +6,7 @@ module GraphQL
6
6
  case type_error
7
7
  when GraphQL::InvalidNullError
8
8
  ctx.errors << type_error
9
- when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError
9
+ when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
10
10
  raise type_error
11
11
  end
12
12
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ # An example directive to show how you might interact with the runtime.
6
+ #
7
+ # This directive might be used along with a server-side feature flag system like Flipper.
8
+ #
9
+ # With that system, you could use this directive to exclude parts of a query
10
+ # if the current viewer doesn't have certain flags enabled.
11
+ # (So, this flag would be for internal clients, like your iOS app, not third-party API clients.)
12
+ #
13
+ # To use it, you have to implement `.enabled?`, for example:
14
+ #
15
+ # @example Implementing the Feature directive
16
+ # # app/graphql/directives/feature.rb
17
+ # class Directives::Feature < GraphQL::Schema::Directive::Feature
18
+ # def self.enabled?(flag_name, _obj, context)
19
+ # # Translate some GraphQL data for Ruby:
20
+ # flag_key = flag_name.underscore
21
+ # current_user = context[:viewer]
22
+ # # Check the feature flag however your app does it:
23
+ # MyFeatureFlags.enabled?(current_user, flag_key)
24
+ # end
25
+ # end
26
+ #
27
+ # @example Flagging a part of the query
28
+ # viewer {
29
+ # # This field only runs if `.enabled?("recommendationEngine", obj, context)`
30
+ # # returns true. Otherwise, it's treated as if it didn't exist.
31
+ # recommendations @feature(flag: "recommendationEngine") {
32
+ # name
33
+ # rating
34
+ # }
35
+ # }
36
+ class Feature < Schema::Directive
37
+ description "Directs the executor to run this only if a certain server-side feature is enabled."
38
+
39
+ locations(
40
+ GraphQL::Schema::Directive::FIELD,
41
+ GraphQL::Schema::Directive::FRAGMENT_SPREAD,
42
+ GraphQL::Schema::Directive::INLINE_FRAGMENT
43
+ )
44
+
45
+ argument :flag, String, required: true,
46
+ description: "The name of the feature to check before continuing"
47
+
48
+ # Implement the Directive API
49
+ def self.include?(object, arguments, context)
50
+ flag_name = arguments[:flag]
51
+ self.enabled?(flag_name, object, context)
52
+ end
53
+
54
+ # Override this method in your app's subclass of this directive.
55
+ #
56
+ # @param flag_name [String] The client-provided string of a feature to check
57
+ # @param object [GraphQL::Schema::Objct] The currently-evaluated GraphQL object instance
58
+ # @param context [GraphQL::Query::Context]
59
+ # @return [Boolean] If truthy, execution will continue
60
+ def self.enabled?(flag_name, object, context)
61
+ raise NotImplementedError, "Implement `.enabled?(flag_name, object, context)` to return true or false for the feature flag (#{flag_name.inspect})"
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ class Include < GraphQL::Schema::Directive
6
+ description "Directs the executor to include this field or fragment only when the `if` argument is true."
7
+
8
+ locations(
9
+ GraphQL::Schema::Directive::FIELD,
10
+ GraphQL::Schema::Directive::FRAGMENT_SPREAD,
11
+ GraphQL::Schema::Directive::INLINE_FRAGMENT
12
+ )
13
+
14
+ argument :if, Boolean, required: true,
15
+ description: "Included when true."
16
+
17
+ default_directive true
18
+
19
+ def self.include?(obj, args, ctx)
20
+ !!args[:if]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ class Skip < Schema::Directive
6
+ description "Directs the executor to skip this field or fragment when the `if` argument is true."
7
+
8
+ locations(
9
+ GraphQL::Schema::Directive::FIELD,
10
+ GraphQL::Schema::Directive::FRAGMENT_SPREAD,
11
+ GraphQL::Schema::Directive::INLINE_FRAGMENT
12
+ )
13
+
14
+ argument :if, Boolean, required: true,
15
+ description: "Skipped when true."
16
+
17
+ default_directive true
18
+
19
+ def self.include?(obj, args, ctx)
20
+ !args[:if]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ # An example directive to show how you might interact with the runtime.
6
+ #
7
+ # This directive takes the return value of the tagged part of the query,
8
+ # and if the named transform is whitelisted and applies to the return value,
9
+ # it's applied by calling a method with that name.
10
+ #
11
+ # @example Installing the directive
12
+ # class MySchema < GraphQL::Schema
13
+ # directive(GraphQL::Schema::Directive::Transform)
14
+ # end
15
+ #
16
+ # @example Transforming strings
17
+ # viewer {
18
+ # username @transform(by: "upcase")
19
+ # }
20
+ class Transform < Schema::Directive
21
+ description "Directs the executor to run named transform on the return value."
22
+
23
+ locations(
24
+ GraphQL::Schema::Directive::FIELD,
25
+ )
26
+
27
+ argument :by, String, required: true,
28
+ description: "The name of the transform to run if applicable"
29
+
30
+ TRANSFORMS = [
31
+ "upcase",
32
+ "downcase",
33
+ # ??
34
+ ]
35
+ # Implement the Directive API
36
+ def self.resolve(object, arguments, context)
37
+ path = context.namespace(:interpreter)[:current_path]
38
+ return_value = yield
39
+ transform_name = arguments[:by]
40
+ if TRANSFORMS.include?(transform_name) && return_value.respond_to?(transform_name)
41
+ return_value = return_value.public_send(transform_name)
42
+ context.namespace(:interpreter)[:runtime].write_in_response(path, return_value)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ # Subclasses of this can influence how {GraphQL::Execution::Interpreter} runs queries.
6
+ #
7
+ # - {.include?}: if it returns `false`, the field or fragment will be skipped altogether, as if it were absent
8
+ # - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
9
+ class Directive < GraphQL::Schema::Member
10
+ extend GraphQL::Schema::Member::HasArguments
11
+ class << self
12
+ def default_graphql_name
13
+ super.downcase
14
+ end
15
+
16
+ def locations(*new_locations)
17
+ if new_locations.any?
18
+ @locations = new_locations
19
+ else
20
+ @locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
21
+ end
22
+ end
23
+
24
+ def default_directive(new_default_directive = nil)
25
+ if new_default_directive != nil
26
+ @default_directive = new_default_directive
27
+ elsif @default_directive.nil?
28
+ @default_directive = (superclass.respond_to?(:default_directive) ? superclass.default_directive : false)
29
+ else
30
+ @default_directive
31
+ end
32
+ end
33
+
34
+ def to_graphql
35
+ defn = GraphQL::Directive.new
36
+ defn.name = self.graphql_name
37
+ defn.description = self.description
38
+ defn.locations = self.locations
39
+ defn.default_directive = self.default_directive
40
+ defn.metadata[:type_class] = self
41
+ arguments.each do |name, arg_defn|
42
+ arg_graphql = arg_defn.to_graphql
43
+ defn.arguments[arg_graphql.name] = arg_graphql
44
+ end
45
+ defn
46
+ end
47
+
48
+ # If false, this part of the query won't be evaluated
49
+ def include?(_object, _arguments, _context)
50
+ true
51
+ end
52
+
53
+ # Continuing is passed as a block; `yield` to continue
54
+ def resolve(object, arguments, context)
55
+ yield
56
+ end
57
+ end
58
+
59
+ LOCATIONS = [
60
+ QUERY = :QUERY,
61
+ MUTATION = :MUTATION,
62
+ SUBSCRIPTION = :SUBSCRIPTION,
63
+ FIELD = :FIELD,
64
+ FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION,
65
+ FRAGMENT_SPREAD = :FRAGMENT_SPREAD,
66
+ INLINE_FRAGMENT = :INLINE_FRAGMENT,
67
+ SCHEMA = :SCHEMA,
68
+ SCALAR = :SCALAR,
69
+ OBJECT = :OBJECT,
70
+ FIELD_DEFINITION = :FIELD_DEFINITION,
71
+ ARGUMENT_DEFINITION = :ARGUMENT_DEFINITION,
72
+ INTERFACE = :INTERFACE,
73
+ UNION = :UNION,
74
+ ENUM = :ENUM,
75
+ ENUM_VALUE = :ENUM_VALUE,
76
+ INPUT_OBJECT = :INPUT_OBJECT,
77
+ INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
78
+ ]
79
+
80
+ DEFAULT_DEPRECATION_REASON = 'No longer supported'
81
+ LOCATION_DESCRIPTIONS = {
82
+ QUERY: 'Location adjacent to a query operation.',
83
+ MUTATION: 'Location adjacent to a mutation operation.',
84
+ SUBSCRIPTION: 'Location adjacent to a subscription operation.',
85
+ FIELD: 'Location adjacent to a field.',
86
+ FRAGMENT_DEFINITION: 'Location adjacent to a fragment definition.',
87
+ FRAGMENT_SPREAD: 'Location adjacent to a fragment spread.',
88
+ INLINE_FRAGMENT: 'Location adjacent to an inline fragment.',
89
+ SCHEMA: 'Location adjacent to a schema definition.',
90
+ SCALAR: 'Location adjacent to a scalar definition.',
91
+ OBJECT: 'Location adjacent to an object type definition.',
92
+ FIELD_DEFINITION: 'Location adjacent to a field definition.',
93
+ ARGUMENT_DEFINITION: 'Location adjacent to an argument definition.',
94
+ INTERFACE: 'Location adjacent to an interface definition.',
95
+ UNION: 'Location adjacent to a union definition.',
96
+ ENUM: 'Location adjacent to an enum definition.',
97
+ ENUM_VALUE: 'Location adjacent to an enum value definition.',
98
+ INPUT_OBJECT: 'Location adjacent to an input object type definition.',
99
+ INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
100
+ }
101
+ end
102
+ end
103
+ end
@@ -27,6 +27,7 @@ module GraphQL
27
27
  # end
28
28
  class EnumValue < GraphQL::Schema::Member
29
29
  include GraphQL::Schema::Member::AcceptsDefinition
30
+ include GraphQL::Schema::Member::HasPath
30
31
 
31
32
  attr_reader :graphql_name
32
33
 
@@ -39,7 +40,7 @@ module GraphQL
39
40
  def initialize(graphql_name, desc = nil, owner:, description: nil, value: nil, deprecation_reason: nil, &block)
40
41
  @graphql_name = graphql_name.to_s
41
42
  @description = desc || description
42
- @value = value || @graphql_name
43
+ @value = value.nil? ? @graphql_name : value
43
44
  @deprecation_reason = deprecation_reason
44
45
  @owner = owner
45
46
 
@@ -56,7 +57,7 @@ module GraphQL
56
57
  end
57
58
 
58
59
  def value(new_val = nil)
59
- if new_val
60
+ unless new_val.nil?
60
61
  @value = new_val
61
62
  end
62
63
  @value