graphql_cody 1.13.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 (444) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/MIT-LICENSE +20 -0
  4. data/lib/generators/graphql/core.rb +74 -0
  5. data/lib/generators/graphql/enum_generator.rb +33 -0
  6. data/lib/generators/graphql/install_generator.rb +190 -0
  7. data/lib/generators/graphql/interface_generator.rb +27 -0
  8. data/lib/generators/graphql/loader_generator.rb +21 -0
  9. data/lib/generators/graphql/mutation_generator.rb +55 -0
  10. data/lib/generators/graphql/object_generator.rb +79 -0
  11. data/lib/generators/graphql/relay.rb +63 -0
  12. data/lib/generators/graphql/relay_generator.rb +21 -0
  13. data/lib/generators/graphql/scalar_generator.rb +20 -0
  14. data/lib/generators/graphql/templates/base_argument.erb +6 -0
  15. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  16. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  17. data/lib/generators/graphql/templates/base_enum.erb +6 -0
  18. data/lib/generators/graphql/templates/base_field.erb +7 -0
  19. data/lib/generators/graphql/templates/base_input_object.erb +7 -0
  20. data/lib/generators/graphql/templates/base_interface.erb +9 -0
  21. data/lib/generators/graphql/templates/base_mutation.erb +10 -0
  22. data/lib/generators/graphql/templates/base_object.erb +7 -0
  23. data/lib/generators/graphql/templates/base_scalar.erb +6 -0
  24. data/lib/generators/graphql/templates/base_union.erb +6 -0
  25. data/lib/generators/graphql/templates/enum.erb +7 -0
  26. data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
  27. data/lib/generators/graphql/templates/interface.erb +8 -0
  28. data/lib/generators/graphql/templates/loader.erb +19 -0
  29. data/lib/generators/graphql/templates/mutation.erb +16 -0
  30. data/lib/generators/graphql/templates/mutation_type.erb +12 -0
  31. data/lib/generators/graphql/templates/node_type.erb +9 -0
  32. data/lib/generators/graphql/templates/object.erb +8 -0
  33. data/lib/generators/graphql/templates/query_type.erb +15 -0
  34. data/lib/generators/graphql/templates/scalar.erb +15 -0
  35. data/lib/generators/graphql/templates/schema.erb +27 -0
  36. data/lib/generators/graphql/templates/union.erb +7 -0
  37. data/lib/generators/graphql/type_generator.rb +98 -0
  38. data/lib/generators/graphql/union_generator.rb +33 -0
  39. data/lib/graphql/analysis/analyze_query.rb +98 -0
  40. data/lib/graphql/analysis/ast/analyzer.rb +84 -0
  41. data/lib/graphql/analysis/ast/field_usage.rb +51 -0
  42. data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
  43. data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
  44. data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
  45. data/lib/graphql/analysis/ast/query_depth.rb +56 -0
  46. data/lib/graphql/analysis/ast/visitor.rb +268 -0
  47. data/lib/graphql/analysis/ast.rb +91 -0
  48. data/lib/graphql/analysis/field_usage.rb +45 -0
  49. data/lib/graphql/analysis/max_query_complexity.rb +26 -0
  50. data/lib/graphql/analysis/max_query_depth.rb +26 -0
  51. data/lib/graphql/analysis/query_complexity.rb +88 -0
  52. data/lib/graphql/analysis/query_depth.rb +43 -0
  53. data/lib/graphql/analysis/reducer_state.rb +48 -0
  54. data/lib/graphql/analysis.rb +9 -0
  55. data/lib/graphql/analysis_error.rb +5 -0
  56. data/lib/graphql/argument.rb +131 -0
  57. data/lib/graphql/authorization.rb +82 -0
  58. data/lib/graphql/backtrace/inspect_result.rb +50 -0
  59. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  60. data/lib/graphql/backtrace/table.rb +159 -0
  61. data/lib/graphql/backtrace/traced_error.rb +54 -0
  62. data/lib/graphql/backtrace/tracer.rb +81 -0
  63. data/lib/graphql/backtrace.rb +64 -0
  64. data/lib/graphql/backwards_compatibility.rb +61 -0
  65. data/lib/graphql/base_type.rb +230 -0
  66. data/lib/graphql/boolean_type.rb +2 -0
  67. data/lib/graphql/coercion_error.rb +13 -0
  68. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
  69. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +200 -0
  70. data/lib/graphql/compatibility/execution_specification.rb +436 -0
  71. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +111 -0
  72. data/lib/graphql/compatibility/lazy_execution_specification.rb +215 -0
  73. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +87 -0
  74. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +79 -0
  75. data/lib/graphql/compatibility/query_parser_specification.rb +266 -0
  76. data/lib/graphql/compatibility/schema_parser_specification.rb +682 -0
  77. data/lib/graphql/compatibility.rb +5 -0
  78. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  79. data/lib/graphql/dataloader/request.rb +19 -0
  80. data/lib/graphql/dataloader/request_all.rb +19 -0
  81. data/lib/graphql/dataloader/source.rb +155 -0
  82. data/lib/graphql/dataloader.rb +308 -0
  83. data/lib/graphql/define/assign_argument.rb +12 -0
  84. data/lib/graphql/define/assign_connection.rb +13 -0
  85. data/lib/graphql/define/assign_enum_value.rb +18 -0
  86. data/lib/graphql/define/assign_global_id_field.rb +11 -0
  87. data/lib/graphql/define/assign_mutation_function.rb +34 -0
  88. data/lib/graphql/define/assign_object_field.rb +42 -0
  89. data/lib/graphql/define/defined_object_proxy.rb +53 -0
  90. data/lib/graphql/define/instance_definable.rb +240 -0
  91. data/lib/graphql/define/no_definition_error.rb +7 -0
  92. data/lib/graphql/define/non_null_with_bang.rb +16 -0
  93. data/lib/graphql/define/type_definer.rb +31 -0
  94. data/lib/graphql/define.rb +31 -0
  95. data/lib/graphql/deprecated_dsl.rb +55 -0
  96. data/lib/graphql/deprecation.rb +9 -0
  97. data/lib/graphql/dig.rb +19 -0
  98. data/lib/graphql/directive/deprecated_directive.rb +2 -0
  99. data/lib/graphql/directive/include_directive.rb +2 -0
  100. data/lib/graphql/directive/skip_directive.rb +2 -0
  101. data/lib/graphql/directive.rb +107 -0
  102. data/lib/graphql/enum_type.rb +133 -0
  103. data/lib/graphql/execution/directive_checks.rb +37 -0
  104. data/lib/graphql/execution/errors.rb +163 -0
  105. data/lib/graphql/execution/execute.rb +333 -0
  106. data/lib/graphql/execution/flatten.rb +40 -0
  107. data/lib/graphql/execution/instrumentation.rb +92 -0
  108. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  109. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  110. data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
  111. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  112. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  113. data/lib/graphql/execution/interpreter/resolve.rb +70 -0
  114. data/lib/graphql/execution/interpreter/runtime.rb +949 -0
  115. data/lib/graphql/execution/interpreter.rb +122 -0
  116. data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
  117. data/lib/graphql/execution/lazy/resolve.rb +91 -0
  118. data/lib/graphql/execution/lazy.rb +83 -0
  119. data/lib/graphql/execution/lookahead.rb +307 -0
  120. data/lib/graphql/execution/multiplex.rb +214 -0
  121. data/lib/graphql/execution/typecast.rb +50 -0
  122. data/lib/graphql/execution.rb +11 -0
  123. data/lib/graphql/execution_error.rb +58 -0
  124. data/lib/graphql/field/resolve.rb +59 -0
  125. data/lib/graphql/field.rb +226 -0
  126. data/lib/graphql/filter.rb +53 -0
  127. data/lib/graphql/float_type.rb +2 -0
  128. data/lib/graphql/function.rb +128 -0
  129. data/lib/graphql/id_type.rb +2 -0
  130. data/lib/graphql/input_object_type.rb +138 -0
  131. data/lib/graphql/int_type.rb +2 -0
  132. data/lib/graphql/integer_decoding_error.rb +17 -0
  133. data/lib/graphql/integer_encoding_error.rb +36 -0
  134. data/lib/graphql/interface_type.rb +72 -0
  135. data/lib/graphql/internal_representation/document.rb +27 -0
  136. data/lib/graphql/internal_representation/node.rb +206 -0
  137. data/lib/graphql/internal_representation/print.rb +51 -0
  138. data/lib/graphql/internal_representation/rewrite.rb +184 -0
  139. data/lib/graphql/internal_representation/scope.rb +88 -0
  140. data/lib/graphql/internal_representation/visit.rb +36 -0
  141. data/lib/graphql/internal_representation.rb +7 -0
  142. data/lib/graphql/introspection/base_object.rb +13 -0
  143. data/lib/graphql/introspection/directive_location_enum.rb +15 -0
  144. data/lib/graphql/introspection/directive_type.rb +29 -0
  145. data/lib/graphql/introspection/dynamic_fields.rb +17 -0
  146. data/lib/graphql/introspection/entry_points.rb +35 -0
  147. data/lib/graphql/introspection/enum_value_type.rb +23 -0
  148. data/lib/graphql/introspection/field_type.rb +28 -0
  149. data/lib/graphql/introspection/input_value_type.rb +67 -0
  150. data/lib/graphql/introspection/introspection_query.rb +7 -0
  151. data/lib/graphql/introspection/schema_type.rb +44 -0
  152. data/lib/graphql/introspection/type_kind_enum.rb +13 -0
  153. data/lib/graphql/introspection/type_type.rb +95 -0
  154. data/lib/graphql/introspection.rb +114 -0
  155. data/lib/graphql/invalid_name_error.rb +11 -0
  156. data/lib/graphql/invalid_null_error.rb +50 -0
  157. data/lib/graphql/language/block_string.rb +99 -0
  158. data/lib/graphql/language/cache.rb +37 -0
  159. data/lib/graphql/language/definition_slice.rb +41 -0
  160. data/lib/graphql/language/document_from_schema_definition.rb +347 -0
  161. data/lib/graphql/language/generation.rb +24 -0
  162. data/lib/graphql/language/lexer.rb +1467 -0
  163. data/lib/graphql/language/lexer.rl +258 -0
  164. data/lib/graphql/language/nodes.rb +707 -0
  165. data/lib/graphql/language/parser.rb +1974 -0
  166. data/lib/graphql/language/parser.y +544 -0
  167. data/lib/graphql/language/printer.rb +366 -0
  168. data/lib/graphql/language/sanitized_printer.rb +222 -0
  169. data/lib/graphql/language/token.rb +34 -0
  170. data/lib/graphql/language/visitor.rb +242 -0
  171. data/lib/graphql/language.rb +36 -0
  172. data/lib/graphql/list_type.rb +80 -0
  173. data/lib/graphql/load_application_object_failed_error.rb +22 -0
  174. data/lib/graphql/name_validator.rb +11 -0
  175. data/lib/graphql/non_null_type.rb +71 -0
  176. data/lib/graphql/object_type.rb +130 -0
  177. data/lib/graphql/pagination/active_record_relation_connection.rb +48 -0
  178. data/lib/graphql/pagination/array_connection.rb +77 -0
  179. data/lib/graphql/pagination/connection.rb +226 -0
  180. data/lib/graphql/pagination/connections.rb +160 -0
  181. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  182. data/lib/graphql/pagination/relation_connection.rb +196 -0
  183. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  184. data/lib/graphql/pagination.rb +6 -0
  185. data/lib/graphql/parse_error.rb +24 -0
  186. data/lib/graphql/query/arguments.rb +189 -0
  187. data/lib/graphql/query/arguments_cache.rb +24 -0
  188. data/lib/graphql/query/context.rb +371 -0
  189. data/lib/graphql/query/executor.rb +52 -0
  190. data/lib/graphql/query/fingerprint.rb +26 -0
  191. data/lib/graphql/query/input_validation_result.rb +43 -0
  192. data/lib/graphql/query/literal_input.rb +136 -0
  193. data/lib/graphql/query/null_context.rb +55 -0
  194. data/lib/graphql/query/result.rb +63 -0
  195. data/lib/graphql/query/serial_execution/field_resolution.rb +92 -0
  196. data/lib/graphql/query/serial_execution/operation_resolution.rb +19 -0
  197. data/lib/graphql/query/serial_execution/selection_resolution.rb +23 -0
  198. data/lib/graphql/query/serial_execution/value_resolution.rb +87 -0
  199. data/lib/graphql/query/serial_execution.rb +40 -0
  200. data/lib/graphql/query/validation_pipeline.rb +139 -0
  201. data/lib/graphql/query/variable_validation_error.rb +44 -0
  202. data/lib/graphql/query/variables.rb +78 -0
  203. data/lib/graphql/query.rb +454 -0
  204. data/lib/graphql/railtie.rb +117 -0
  205. data/lib/graphql/rake_task/validate.rb +63 -0
  206. data/lib/graphql/rake_task.rb +145 -0
  207. data/lib/graphql/relay/array_connection.rb +83 -0
  208. data/lib/graphql/relay/base_connection.rb +189 -0
  209. data/lib/graphql/relay/connection_instrumentation.rb +54 -0
  210. data/lib/graphql/relay/connection_resolve.rb +43 -0
  211. data/lib/graphql/relay/connection_type.rb +41 -0
  212. data/lib/graphql/relay/edge.rb +27 -0
  213. data/lib/graphql/relay/edge_type.rb +19 -0
  214. data/lib/graphql/relay/edges_instrumentation.rb +39 -0
  215. data/lib/graphql/relay/global_id_resolve.rb +18 -0
  216. data/lib/graphql/relay/mongo_relation_connection.rb +50 -0
  217. data/lib/graphql/relay/mutation/instrumentation.rb +23 -0
  218. data/lib/graphql/relay/mutation/resolve.rb +56 -0
  219. data/lib/graphql/relay/mutation/result.rb +38 -0
  220. data/lib/graphql/relay/mutation.rb +106 -0
  221. data/lib/graphql/relay/node.rb +39 -0
  222. data/lib/graphql/relay/page_info.rb +7 -0
  223. data/lib/graphql/relay/range_add.rb +59 -0
  224. data/lib/graphql/relay/relation_connection.rb +188 -0
  225. data/lib/graphql/relay/type_extensions.rb +32 -0
  226. data/lib/graphql/relay.rb +18 -0
  227. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  228. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  229. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  230. data/lib/graphql/rubocop.rb +4 -0
  231. data/lib/graphql/runtime_type_error.rb +5 -0
  232. data/lib/graphql/scalar_type.rb +91 -0
  233. data/lib/graphql/schema/addition.rb +247 -0
  234. data/lib/graphql/schema/argument.rb +383 -0
  235. data/lib/graphql/schema/base_64_bp.rb +26 -0
  236. data/lib/graphql/schema/base_64_encoder.rb +21 -0
  237. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
  238. data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
  239. data/lib/graphql/schema/build_from_definition.rb +477 -0
  240. data/lib/graphql/schema/built_in_types.rb +12 -0
  241. data/lib/graphql/schema/catchall_middleware.rb +35 -0
  242. data/lib/graphql/schema/default_parse_error.rb +10 -0
  243. data/lib/graphql/schema/default_type_error.rb +17 -0
  244. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  245. data/lib/graphql/schema/directive/feature.rb +66 -0
  246. data/lib/graphql/schema/directive/flagged.rb +57 -0
  247. data/lib/graphql/schema/directive/include.rb +25 -0
  248. data/lib/graphql/schema/directive/skip.rb +25 -0
  249. data/lib/graphql/schema/directive/transform.rb +60 -0
  250. data/lib/graphql/schema/directive.rb +210 -0
  251. data/lib/graphql/schema/enum.rb +193 -0
  252. data/lib/graphql/schema/enum_value.rb +97 -0
  253. data/lib/graphql/schema/field/connection_extension.rb +76 -0
  254. data/lib/graphql/schema/field/scope_extension.rb +22 -0
  255. data/lib/graphql/schema/field.rb +880 -0
  256. data/lib/graphql/schema/field_extension.rb +69 -0
  257. data/lib/graphql/schema/find_inherited_value.rb +36 -0
  258. data/lib/graphql/schema/finder.rb +155 -0
  259. data/lib/graphql/schema/input_object.rb +253 -0
  260. data/lib/graphql/schema/interface.rb +136 -0
  261. data/lib/graphql/schema/introspection_system.rb +169 -0
  262. data/lib/graphql/schema/invalid_type_error.rb +7 -0
  263. data/lib/graphql/schema/late_bound_type.rb +33 -0
  264. data/lib/graphql/schema/list.rb +75 -0
  265. data/lib/graphql/schema/loader.rb +226 -0
  266. data/lib/graphql/schema/member/accepts_definition.rb +159 -0
  267. data/lib/graphql/schema/member/base_dsl_methods.rb +129 -0
  268. data/lib/graphql/schema/member/build_type.rb +180 -0
  269. data/lib/graphql/schema/member/cached_graphql_definition.rb +31 -0
  270. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  271. data/lib/graphql/schema/member/has_arguments.rb +332 -0
  272. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  273. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  274. data/lib/graphql/schema/member/has_directives.rb +98 -0
  275. data/lib/graphql/schema/member/has_fields.rb +163 -0
  276. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  277. data/lib/graphql/schema/member/has_path.rb +25 -0
  278. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  279. data/lib/graphql/schema/member/has_validators.rb +31 -0
  280. data/lib/graphql/schema/member/instrumentation.rb +131 -0
  281. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -0
  282. data/lib/graphql/schema/member/scoped.rb +21 -0
  283. data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
  284. data/lib/graphql/schema/member/validates_input.rb +33 -0
  285. data/lib/graphql/schema/member.rb +161 -0
  286. data/lib/graphql/schema/middleware_chain.rb +82 -0
  287. data/lib/graphql/schema/mutation.rb +94 -0
  288. data/lib/graphql/schema/non_null.rb +67 -0
  289. data/lib/graphql/schema/null_mask.rb +11 -0
  290. data/lib/graphql/schema/object.rb +150 -0
  291. data/lib/graphql/schema/possible_types.rb +44 -0
  292. data/lib/graphql/schema/printer.rb +100 -0
  293. data/lib/graphql/schema/relay_classic_mutation.rb +160 -0
  294. data/lib/graphql/schema/rescue_middleware.rb +60 -0
  295. data/lib/graphql/schema/resolver/has_payload_type.rb +96 -0
  296. data/lib/graphql/schema/resolver.rb +397 -0
  297. data/lib/graphql/schema/scalar.rb +69 -0
  298. data/lib/graphql/schema/subscription.rb +155 -0
  299. data/lib/graphql/schema/timeout.rb +123 -0
  300. data/lib/graphql/schema/timeout_middleware.rb +88 -0
  301. data/lib/graphql/schema/traversal.rb +228 -0
  302. data/lib/graphql/schema/type_expression.rb +43 -0
  303. data/lib/graphql/schema/type_membership.rb +48 -0
  304. data/lib/graphql/schema/union.rb +95 -0
  305. data/lib/graphql/schema/unique_within_type.rb +34 -0
  306. data/lib/graphql/schema/validation.rb +313 -0
  307. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  308. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  309. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  310. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  311. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  312. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  313. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  314. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  315. data/lib/graphql/schema/validator.rb +174 -0
  316. data/lib/graphql/schema/warden.rb +409 -0
  317. data/lib/graphql/schema/wrapper.rb +29 -0
  318. data/lib/graphql/schema.rb +1945 -0
  319. data/lib/graphql/static_validation/all_rules.rb +40 -0
  320. data/lib/graphql/static_validation/base_visitor.rb +217 -0
  321. data/lib/graphql/static_validation/default_visitor.rb +15 -0
  322. data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
  323. data/lib/graphql/static_validation/error.rb +46 -0
  324. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  325. data/lib/graphql/static_validation/literal_validator.rb +139 -0
  326. data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
  327. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +66 -0
  328. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
  329. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
  330. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  331. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +71 -0
  332. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
  333. data/lib/graphql/static_validation/rules/directives_are_defined.rb +23 -0
  334. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  335. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +65 -0
  336. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  337. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +30 -0
  338. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  339. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +73 -0
  340. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  341. data/lib/graphql/static_validation/rules/fields_will_merge.rb +418 -0
  342. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
  343. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
  344. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  345. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +73 -0
  346. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  347. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +39 -0
  348. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  349. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +21 -0
  350. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  351. data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
  352. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  353. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +37 -0
  354. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  355. data/lib/graphql/static_validation/rules/fragments_are_used.rb +32 -0
  356. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  357. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  358. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  359. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
  360. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  361. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
  362. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  363. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
  364. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  365. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +37 -0
  366. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  367. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
  368. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  369. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
  370. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  371. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +50 -0
  372. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  373. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +46 -0
  374. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  375. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
  376. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  377. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +153 -0
  378. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  379. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +39 -0
  380. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  381. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +155 -0
  382. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  383. data/lib/graphql/static_validation/type_stack.rb +216 -0
  384. data/lib/graphql/static_validation/validation_context.rb +49 -0
  385. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  386. data/lib/graphql/static_validation/validator.rb +96 -0
  387. data/lib/graphql/static_validation.rb +19 -0
  388. data/lib/graphql/string_encoding_error.rb +20 -0
  389. data/lib/graphql/string_type.rb +2 -0
  390. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +245 -0
  391. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  392. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  393. data/lib/graphql/subscriptions/event.rb +144 -0
  394. data/lib/graphql/subscriptions/instrumentation.rb +79 -0
  395. data/lib/graphql/subscriptions/serialize.rb +138 -0
  396. data/lib/graphql/subscriptions/subscription_root.rb +76 -0
  397. data/lib/graphql/subscriptions.rb +299 -0
  398. data/lib/graphql/tracing/active_support_notifications_tracing.rb +35 -0
  399. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  400. data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
  401. data/lib/graphql/tracing/data_dog_tracing.rb +76 -0
  402. data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
  403. data/lib/graphql/tracing/platform_tracing.rb +139 -0
  404. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
  405. data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
  406. data/lib/graphql/tracing/scout_tracing.rb +54 -0
  407. data/lib/graphql/tracing/skylight_tracing.rb +70 -0
  408. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  409. data/lib/graphql/tracing.rb +95 -0
  410. data/lib/graphql/type_kinds.rb +77 -0
  411. data/lib/graphql/types/big_int.rb +23 -0
  412. data/lib/graphql/types/boolean.rb +18 -0
  413. data/lib/graphql/types/float.rb +19 -0
  414. data/lib/graphql/types/id.rb +24 -0
  415. data/lib/graphql/types/int.rb +36 -0
  416. data/lib/graphql/types/iso_8601_date.rb +34 -0
  417. data/lib/graphql/types/iso_8601_date_time.rb +65 -0
  418. data/lib/graphql/types/json.rb +25 -0
  419. data/lib/graphql/types/relay/base_connection.rb +39 -0
  420. data/lib/graphql/types/relay/base_edge.rb +29 -0
  421. data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
  422. data/lib/graphql/types/relay/default_relay.rb +27 -0
  423. data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
  424. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  425. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  426. data/lib/graphql/types/relay/node.rb +15 -0
  427. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  428. data/lib/graphql/types/relay/node_field.rb +25 -0
  429. data/lib/graphql/types/relay/nodes_field.rb +27 -0
  430. data/lib/graphql/types/relay/page_info.rb +11 -0
  431. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  432. data/lib/graphql/types/relay.rb +41 -0
  433. data/lib/graphql/types/string.rb +29 -0
  434. data/lib/graphql/types.rb +11 -0
  435. data/lib/graphql/unauthorized_error.rb +29 -0
  436. data/lib/graphql/unauthorized_field_error.rb +23 -0
  437. data/lib/graphql/union_type.rb +115 -0
  438. data/lib/graphql/unresolved_type_error.rb +35 -0
  439. data/lib/graphql/upgrader/member.rb +937 -0
  440. data/lib/graphql/upgrader/schema.rb +38 -0
  441. data/lib/graphql/version.rb +4 -0
  442. data/lib/graphql.rb +168 -0
  443. data/readme.md +49 -0
  444. metadata +714 -0
@@ -0,0 +1,880 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/schema/field/connection_extension"
3
+ require "graphql/schema/field/scope_extension"
4
+
5
+ module GraphQL
6
+ class Schema
7
+ class Field
8
+ include GraphQL::Schema::Member::CachedGraphQLDefinition
9
+ include GraphQL::Schema::Member::AcceptsDefinition
10
+ include GraphQL::Schema::Member::HasArguments
11
+ include GraphQL::Schema::Member::HasAstNode
12
+ include GraphQL::Schema::Member::HasPath
13
+ include GraphQL::Schema::Member::HasValidators
14
+ extend GraphQL::Schema::FindInheritedValue
15
+ include GraphQL::Schema::FindInheritedValue::EmptyObjects
16
+ include GraphQL::Schema::Member::HasDirectives
17
+ include GraphQL::Schema::Member::HasDeprecationReason
18
+
19
+ # @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
20
+ attr_reader :name
21
+ alias :graphql_name :name
22
+
23
+ attr_writer :description
24
+
25
+ # @return [Symbol] Method or hash key on the underlying object to look up
26
+ attr_reader :method_sym
27
+
28
+ # @return [String] Method or hash key on the underlying object to look up
29
+ attr_reader :method_str
30
+
31
+ # @return [Symbol] The method on the type to look up
32
+ attr_reader :resolver_method
33
+
34
+ # @return [Class] The thing this field was defined on (type, mutation, resolver)
35
+ attr_accessor :owner
36
+
37
+ # @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
38
+ def owner_type
39
+ @owner_type ||= if owner < GraphQL::Schema::Mutation
40
+ owner.payload_type
41
+ else
42
+ owner
43
+ end
44
+ end
45
+
46
+ # @return [Symbol] the original name of the field, passed in by the user
47
+ attr_reader :original_name
48
+
49
+ # @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
50
+ def resolver
51
+ @resolver_class
52
+ end
53
+
54
+ # @return [Boolean] Is this field a predefined introspection field?
55
+ def introspection?
56
+ @introspection
57
+ end
58
+
59
+ def inspect
60
+ "#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
61
+ end
62
+
63
+ alias :mutation :resolver
64
+
65
+ # @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
66
+ attr_reader :trace
67
+
68
+ # @return [String, nil]
69
+ attr_accessor :subscription_scope
70
+
71
+ # Create a field instance from a list of arguments, keyword arguments, and a block.
72
+ #
73
+ # This method implements prioritization between the `resolver` or `mutation` defaults
74
+ # and the local overrides via other keywords.
75
+ #
76
+ # It also normalizes positional arguments into keywords for {Schema::Field#initialize}.
77
+ # @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
78
+ # @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
79
+ # @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
80
+ # @return [GraphQL::Schema:Field] an instance of `self
81
+ # @see {.initialize} for other options
82
+ def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
83
+ if kwargs[:field]
84
+ if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
85
+ GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
86
+ return GraphQL::Types::Relay::NodeField
87
+ elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
88
+ GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
89
+ return GraphQL::Types::Relay::NodesField
90
+ end
91
+ end
92
+
93
+ if (parent_config = resolver || mutation || subscription)
94
+ # Get the parent config, merge in local overrides
95
+ kwargs = parent_config.field_options.merge(kwargs)
96
+ # Add a reference to that parent class
97
+ kwargs[:resolver_class] = parent_config
98
+ end
99
+
100
+ if name
101
+ kwargs[:name] = name
102
+ end
103
+
104
+ if !type.nil?
105
+ if type.is_a?(GraphQL::Field)
106
+ raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
107
+ end
108
+ if desc
109
+ if kwargs[:description]
110
+ raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
111
+ end
112
+
113
+ kwargs[:description] = desc
114
+ kwargs[:type] = type
115
+ elsif (kwargs[:field] || kwargs[:function] || resolver || mutation) && type.is_a?(String)
116
+ # The return type should be copied from `field` or `function`, and the second positional argument is the description
117
+ kwargs[:description] = type
118
+ else
119
+ kwargs[:type] = type
120
+ end
121
+ if type.is_a?(Class) && type < GraphQL::Schema::Mutation
122
+ raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
123
+ end
124
+ end
125
+ new(**kwargs, &block)
126
+ end
127
+
128
+ # Can be set with `connection: true|false` or inferred from a type name ending in `*Connection`
129
+ # @return [Boolean] if true, this field will be wrapped with Relay connection behavior
130
+ def connection?
131
+ if @connection.nil?
132
+ # Provide default based on type name
133
+ return_type_name = if (contains_type = @field || @function)
134
+ Member::BuildType.to_type_name(contains_type.type)
135
+ elsif @return_type_expr
136
+ Member::BuildType.to_type_name(@return_type_expr)
137
+ else
138
+ # As a last ditch, try to force loading the return type:
139
+ type.unwrap.name
140
+ end
141
+ @connection = return_type_name.end_with?("Connection")
142
+ else
143
+ @connection
144
+ end
145
+ end
146
+
147
+ # @return [Boolean] if true, the return type's `.scope_items` method will be applied to this field's return value
148
+ def scoped?
149
+ if !@scope.nil?
150
+ # The default was overridden
151
+ @scope
152
+ else
153
+ @return_type_expr && (@return_type_expr.is_a?(Array) || (@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) || connection?)
154
+ end
155
+ end
156
+
157
+ # This extension is applied to fields when {#connection?} is true.
158
+ #
159
+ # You can override it in your base field definition.
160
+ # @return [Class] A {FieldExtension} subclass for implementing pagination behavior.
161
+ # @example Configuring a custom extension
162
+ # class Types::BaseField < GraphQL::Schema::Field
163
+ # connection_extension(MyCustomExtension)
164
+ # end
165
+ def self.connection_extension(new_extension_class = nil)
166
+ if new_extension_class
167
+ @connection_extension = new_extension_class
168
+ else
169
+ @connection_extension ||= find_inherited_value(:connection_extension, ConnectionExtension)
170
+ end
171
+ end
172
+
173
+ # @return Boolean
174
+ attr_reader :relay_node_field
175
+
176
+ # @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
177
+ def method_conflict_warning?
178
+ @method_conflict_warning
179
+ end
180
+
181
+ # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
182
+ # @param type [Class, GraphQL::BaseType, Array] The return type of this field
183
+ # @param owner [Class] The type that this field belongs to
184
+ # @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
185
+ # @param description [String] Field description
186
+ # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
187
+ # @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
188
+ # @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
189
+ # @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
190
+ # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
191
+ # @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
192
+ # @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
193
+ # @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
194
+ # @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
195
+ # @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
196
+ # @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
197
+ # @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
198
+ # @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
199
+ # @param camelize [Boolean] If true, the field name will be camelized when building the schema
200
+ # @param complexity [Numeric] When provided, set the complexity for this field
201
+ # @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
202
+ # @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
203
+ # @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
204
+ # @param directives [Hash{Class => Hash}] Directives to apply to this field
205
+ # @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
206
+ # @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
207
+ # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
208
+ # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
209
+ # @param validates [Array<Hash>] Configurations for validating this field
210
+ # @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
211
+ def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
212
+ if name.nil?
213
+ raise ArgumentError, "missing first `name` argument or keyword `name:`"
214
+ end
215
+ if !(field || function || resolver_class)
216
+ if type.nil?
217
+ raise ArgumentError, "missing second `type` argument or keyword `type:`"
218
+ end
219
+ end
220
+ if (field || function || resolve) && extras.any?
221
+ raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
222
+ end
223
+ @original_name = name
224
+ name_s = -name.to_s
225
+ @underscored_name = -Member::BuildType.underscore(name_s)
226
+ @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
227
+ @description = description
228
+ if field.is_a?(GraphQL::Schema::Field)
229
+ raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
230
+ else
231
+ @field = field
232
+ end
233
+ @function = function
234
+ @resolve = resolve
235
+ self.deprecation_reason = deprecation_reason
236
+
237
+ if method && hash_key
238
+ raise ArgumentError, "Provide `method:` _or_ `hash_key:`, not both. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}`)"
239
+ end
240
+
241
+ if resolver_method
242
+ if method
243
+ raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
244
+ end
245
+
246
+ if hash_key
247
+ raise ArgumentError, "Provide `hash_key:` _or_ `resolver_method:`, not both. (called with: `hash_key: #{hash_key.inspect}, resolver_method: #{resolver_method.inspect}`)"
248
+ end
249
+ end
250
+
251
+ # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
252
+ method_name = method || hash_key || name_s
253
+ resolver_method ||= name_s.to_sym
254
+
255
+ @method_str = -method_name.to_s
256
+ @method_sym = method_name.to_sym
257
+ @resolver_method = resolver_method
258
+ @complexity = complexity
259
+ @return_type_expr = type
260
+ @return_type_null = null
261
+ @connection = connection
262
+ @has_max_page_size = max_page_size != :not_given
263
+ @max_page_size = max_page_size == :not_given ? nil : max_page_size
264
+ @introspection = introspection
265
+ @extras = extras
266
+ @broadcastable = broadcastable
267
+ @resolver_class = resolver_class
268
+ @scope = scope
269
+ @trace = trace
270
+ @relay_node_field = relay_node_field
271
+ @relay_nodes_field = relay_nodes_field
272
+ @ast_node = ast_node
273
+ @method_conflict_warning = method_conflict_warning
274
+ @legacy_edge_class = legacy_edge_class
275
+
276
+ arguments.each do |name, arg|
277
+ case arg
278
+ when Hash
279
+ argument(name: name, **arg)
280
+ when GraphQL::Schema::Argument
281
+ add_argument(arg)
282
+ when Array
283
+ arg.each { |a| add_argument(a) }
284
+ else
285
+ raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
286
+ end
287
+ end
288
+
289
+ @owner = owner
290
+ @subscription_scope = subscription_scope
291
+
292
+ @extensions = EMPTY_ARRAY
293
+ # This should run before connection extension,
294
+ # but should it run after the definition block?
295
+ if scoped?
296
+ self.extension(ScopeExtension)
297
+ end
298
+
299
+ # The problem with putting this after the definition_block
300
+ # is that it would override arguments
301
+ if connection? && connection_extension
302
+ self.extension(connection_extension)
303
+ end
304
+
305
+ # Do this last so we have as much context as possible when initializing them:
306
+ if extensions.any?
307
+ self.extensions(extensions)
308
+ end
309
+
310
+ if directives.any?
311
+ directives.each do |(dir_class, options)|
312
+ self.directive(dir_class, **options)
313
+ end
314
+ end
315
+
316
+ self.validates(validates)
317
+
318
+ if definition_block
319
+ if definition_block.arity == 1
320
+ yield self
321
+ else
322
+ instance_eval(&definition_block)
323
+ end
324
+ end
325
+ end
326
+
327
+ # If true, subscription updates with this field can be shared between viewers
328
+ # @return [Boolean, nil]
329
+ # @see GraphQL::Subscriptions::BroadcastAnalyzer
330
+ def broadcastable?
331
+ @broadcastable
332
+ end
333
+
334
+ # @param text [String]
335
+ # @return [String]
336
+ def description(text = nil)
337
+ if text
338
+ @description = text
339
+ else
340
+ @description
341
+ end
342
+ end
343
+
344
+ # Read extension instances from this field,
345
+ # or add new classes/options to be initialized on this field.
346
+ # Extensions are executed in the order they are added.
347
+ #
348
+ # @example adding an extension
349
+ # extensions([MyExtensionClass])
350
+ #
351
+ # @example adding multiple extensions
352
+ # extensions([MyExtensionClass, AnotherExtensionClass])
353
+ #
354
+ # @example adding an extension with options
355
+ # extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
356
+ #
357
+ # @param extensions [Array<Class, Hash<Class => Object>>] Add extensions to this field. For hash elements, only the first key/value is used.
358
+ # @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
359
+ def extensions(new_extensions = nil)
360
+ if new_extensions.nil?
361
+ # Read the value
362
+ @extensions
363
+ else
364
+ if @extensions.frozen?
365
+ @extensions = @extensions.dup
366
+ end
367
+ new_extensions.each do |extension|
368
+ if extension.is_a?(Hash)
369
+ extension = extension.to_a[0]
370
+ extension_class, options = *extension
371
+ @extensions << extension_class.new(field: self, options: options)
372
+ else
373
+ extension_class = extension
374
+ @extensions << extension_class.new(field: self, options: nil)
375
+ end
376
+ end
377
+ end
378
+ end
379
+
380
+ # Add `extension` to this field, initialized with `options` if provided.
381
+ #
382
+ # @example adding an extension
383
+ # extension(MyExtensionClass)
384
+ #
385
+ # @example adding an extension with options
386
+ # extension(MyExtensionClass, filter: true)
387
+ #
388
+ # @param extension [Class] subclass of {Schema::Fieldextension}
389
+ # @param options [Object] if provided, given as `options:` when initializing `extension`.
390
+ def extension(extension, options = nil)
391
+ extensions([{extension => options}])
392
+ end
393
+
394
+ # Read extras (as symbols) from this field,
395
+ # or add new extras to be opted into by this field's resolver.
396
+ #
397
+ # @param new_extras [Array<Symbol>] Add extras to this field
398
+ # @return [Array<Symbol>]
399
+ def extras(new_extras = nil)
400
+ if new_extras.nil?
401
+ # Read the value
402
+ @extras
403
+ else
404
+ if @extras.frozen?
405
+ @extras = @extras.dup
406
+ end
407
+ # Append to the set of extras on this field
408
+ @extras.concat(new_extras)
409
+ end
410
+ end
411
+
412
+ def calculate_complexity(query:, nodes:, child_complexity:)
413
+ if respond_to?(:complexity_for)
414
+ lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
415
+ complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
416
+ elsif connection?
417
+ arguments = query.arguments_for(nodes.first, self)
418
+ max_possible_page_size = nil
419
+ if arguments[:first]
420
+ max_possible_page_size = arguments[:first]
421
+ end
422
+ if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
423
+ max_possible_page_size = arguments[:last]
424
+ end
425
+
426
+ if max_possible_page_size.nil?
427
+ max_possible_page_size = max_page_size || query.schema.default_max_page_size
428
+ end
429
+
430
+ if max_possible_page_size.nil?
431
+ raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
432
+ else
433
+ metadata_complexity = 0
434
+ lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
435
+
436
+ if (page_info_lookahead = lookahead.selection(:page_info)).selected?
437
+ metadata_complexity += 1 # pageInfo
438
+ metadata_complexity += page_info_lookahead.selections.size # subfields
439
+ end
440
+
441
+ if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
442
+ metadata_complexity += 1
443
+ end
444
+ # Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
445
+ items_complexity = child_complexity - metadata_complexity
446
+ # Add 1 for _this_ field
447
+ 1 + (max_possible_page_size * items_complexity) + metadata_complexity
448
+ end
449
+ else
450
+ defined_complexity = complexity
451
+ case defined_complexity
452
+ when Proc
453
+ arguments = query.arguments_for(nodes.first, self)
454
+ defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
455
+ when Numeric
456
+ defined_complexity + child_complexity
457
+ else
458
+ raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
459
+ end
460
+ end
461
+ end
462
+
463
+ def complexity(new_complexity = nil)
464
+ case new_complexity
465
+ when Proc
466
+ if new_complexity.parameters.size != 3
467
+ fail(
468
+ "A complexity proc should always accept 3 parameters: ctx, args, child_complexity. "\
469
+ "E.g.: complexity ->(ctx, args, child_complexity) { child_complexity * args[:limit] }"
470
+ )
471
+ else
472
+ @complexity = new_complexity
473
+ end
474
+ when Numeric
475
+ @complexity = new_complexity
476
+ when nil
477
+ @complexity
478
+ else
479
+ raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
480
+ end
481
+ end
482
+
483
+ # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
484
+ def has_max_page_size?
485
+ @has_max_page_size
486
+ end
487
+
488
+ # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
489
+ attr_reader :max_page_size
490
+
491
+ # @return [GraphQL::Field]
492
+ def to_graphql
493
+ field_defn = if @field
494
+ @field.dup
495
+ elsif @function
496
+ GraphQL::Function.build_field(@function)
497
+ else
498
+ GraphQL::Field.new
499
+ end
500
+
501
+ field_defn.name = @name
502
+ if @return_type_expr
503
+ field_defn.type = -> { type }
504
+ end
505
+
506
+ if @description
507
+ field_defn.description = @description
508
+ end
509
+
510
+ if self.deprecation_reason
511
+ field_defn.deprecation_reason = self.deprecation_reason
512
+ end
513
+
514
+ if @resolver_class
515
+ if @resolver_class < GraphQL::Schema::Mutation
516
+ field_defn.mutation = @resolver_class
517
+ end
518
+ field_defn.metadata[:resolver] = @resolver_class
519
+ end
520
+
521
+ if !@trace.nil?
522
+ field_defn.trace = @trace
523
+ end
524
+
525
+ if @relay_node_field
526
+ field_defn.relay_node_field = @relay_node_field
527
+ end
528
+
529
+ if @relay_nodes_field
530
+ field_defn.relay_nodes_field = @relay_nodes_field
531
+ end
532
+
533
+ if @legacy_edge_class
534
+ field_defn.edge_class = @legacy_edge_class
535
+ end
536
+
537
+ field_defn.resolve = self.method(:resolve_field)
538
+ field_defn.connection = connection?
539
+ field_defn.connection_max_page_size = max_page_size
540
+ field_defn.introspection = @introspection
541
+ field_defn.complexity = @complexity
542
+ field_defn.subscription_scope = @subscription_scope
543
+ field_defn.ast_node = ast_node
544
+
545
+ all_argument_definitions.each do |defn|
546
+ arg_graphql = defn.to_graphql
547
+ field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
548
+ end
549
+
550
+ # Support a passed-in proc, one way or another
551
+ @resolve_proc = if @resolve
552
+ @resolve
553
+ elsif @function
554
+ @function
555
+ elsif @field
556
+ @field.resolve_proc
557
+ end
558
+
559
+ # Ok, `self` isn't a class, but this is for consistency with the classes
560
+ field_defn.metadata[:type_class] = self
561
+ field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
562
+ field_defn
563
+ end
564
+
565
+ class MissingReturnTypeError < GraphQL::Error; end
566
+ attr_writer :type
567
+
568
+ def type
569
+ @type ||= if @function
570
+ Member::BuildType.parse_type(@function.type, null: false)
571
+ elsif @field
572
+ Member::BuildType.parse_type(@field.type, null: false)
573
+ elsif @return_type_expr.nil?
574
+ # Not enough info to determine type
575
+ message = "Can't determine the return type for #{self.path}"
576
+ if @resolver_class
577
+ message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
578
+ end
579
+ raise MissingReturnTypeError, message
580
+ else
581
+ Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
582
+ end
583
+ rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
584
+ # Let this propagate up
585
+ raise err
586
+ rescue StandardError => err
587
+ raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
588
+ end
589
+
590
+ def visible?(context)
591
+ if @resolver_class
592
+ @resolver_class.visible?(context)
593
+ else
594
+ true
595
+ end
596
+ end
597
+
598
+ def accessible?(context)
599
+ if @resolver_class
600
+ @resolver_class.accessible?(context)
601
+ else
602
+ true
603
+ end
604
+ end
605
+
606
+ def authorized?(object, args, context)
607
+ if @resolver_class
608
+ # The resolver will check itself during `resolve()`
609
+ @resolver_class.authorized?(object, context)
610
+ else
611
+ if (arg_values = context[:current_arguments])
612
+ # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
613
+ using_arg_values = true
614
+ arg_values = arg_values.argument_values
615
+ else
616
+ arg_values = args
617
+ using_arg_values = false
618
+ end
619
+ # Faster than `.any?`
620
+ arguments(context).each_value do |arg|
621
+ arg_key = arg.keyword
622
+ if arg_values.key?(arg_key)
623
+ arg_value = arg_values[arg_key]
624
+ if using_arg_values
625
+ if arg_value.default_used?
626
+ # pass -- no auth required for default used
627
+ next
628
+ else
629
+ application_arg_value = arg_value.value
630
+ if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
631
+ application_arg_value.keyword_arguments
632
+ end
633
+ end
634
+ else
635
+ application_arg_value = arg_value
636
+ end
637
+
638
+ if !arg.authorized?(object, application_arg_value, context)
639
+ return false
640
+ end
641
+ end
642
+ end
643
+ true
644
+ end
645
+ end
646
+
647
+ # Implement {GraphQL::Field}'s resolve API.
648
+ #
649
+ # Eventually, we might hook up field instances to execution in another way. TBD.
650
+ # @see #resolve for how the interpreter hooks up to it
651
+ def resolve_field(obj, args, ctx)
652
+ ctx.schema.after_lazy(obj) do |after_obj|
653
+ # First, apply auth ...
654
+ query_ctx = ctx.query.context
655
+ # Some legacy fields can have `nil` here, not exactly sure why.
656
+ # @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
657
+ inner_obj = after_obj && after_obj.object
658
+ ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
659
+ if authorized?(inner_obj, ruby_args, query_ctx)
660
+ # Then if it passed, resolve the field
661
+ if @resolve_proc
662
+ # Might be nil, still want to call the func in that case
663
+ with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
664
+ # Pass the GraphQL args here for compatibility:
665
+ @resolve_proc.call(extended_obj, args, ctx)
666
+ end
667
+ else
668
+ public_send_field(after_obj, ruby_args, query_ctx)
669
+ end
670
+ else
671
+ err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
672
+ query_ctx.schema.unauthorized_field(err)
673
+ end
674
+ end
675
+ end
676
+ end
677
+
678
+ # This method is called by the interpreter for each field.
679
+ # You can extend it in your base field classes.
680
+ # @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
681
+ # @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
682
+ # @param ctx [GraphQL::Query::Context]
683
+ def resolve(object, args, ctx)
684
+ if @resolve_proc
685
+ raise "Can't run resolve proc for #{path} when using GraphQL::Execution::Interpreter"
686
+ end
687
+ begin
688
+ # Unwrap the GraphQL object to get the application object.
689
+ application_object = object.object
690
+
691
+ Schema::Validator.validate!(validators, application_object, ctx, args)
692
+
693
+ ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
694
+ if is_authorized
695
+ public_send_field(object, args, ctx)
696
+ else
697
+ raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
698
+ end
699
+ end
700
+ rescue GraphQL::UnauthorizedFieldError => err
701
+ err.field ||= self
702
+ ctx.schema.unauthorized_field(err)
703
+ rescue GraphQL::UnauthorizedError => err
704
+ ctx.schema.unauthorized_object(err)
705
+ end
706
+ rescue GraphQL::ExecutionError => err
707
+ err
708
+ end
709
+
710
+ # @param ctx [GraphQL::Query::Context::FieldResolutionContext]
711
+ def fetch_extra(extra_name, ctx)
712
+ if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
713
+ self.public_send(extra_name)
714
+ elsif ctx.respond_to?(extra_name)
715
+ ctx.public_send(extra_name)
716
+ else
717
+ raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
718
+ end
719
+ end
720
+
721
+ private
722
+
723
+ NO_ARGS = {}.freeze
724
+
725
+ # Convert a GraphQL arguments instance into a Ruby-style hash.
726
+ #
727
+ # @param obj [GraphQL::Schema::Object] The object where this field is being resolved
728
+ # @param graphql_args [GraphQL::Query::Arguments]
729
+ # @param field_ctx [GraphQL::Query::Context::FieldResolutionContext]
730
+ # @return [Hash<Symbol => Any>]
731
+ def to_ruby_args(obj, graphql_args, field_ctx)
732
+ if graphql_args.any? || @extras.any?
733
+ # Splat the GraphQL::Arguments to Ruby keyword arguments
734
+ ruby_kwargs = graphql_args.to_kwargs
735
+ maybe_lazies = []
736
+ # Apply any `prepare` methods. Not great code organization, can this go somewhere better?
737
+ arguments(field_ctx).each do |name, arg_defn|
738
+ ruby_kwargs_key = arg_defn.keyword
739
+
740
+ if ruby_kwargs.key?(ruby_kwargs_key)
741
+ loads = arg_defn.loads
742
+ value = ruby_kwargs[ruby_kwargs_key]
743
+ loaded_value = if loads && !arg_defn.from_resolver?
744
+ if arg_defn.type.list?
745
+ loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
746
+ field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
747
+ else
748
+ load_application_object(arg_defn, loads, value, field_ctx.query.context)
749
+ end
750
+ elsif arg_defn.type.list? && value.is_a?(Array)
751
+ field_ctx.schema.after_any_lazies(value, &:itself)
752
+ else
753
+ value
754
+ end
755
+
756
+ maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
757
+ prepared_value = if arg_defn.prepare
758
+ arg_defn.prepare_value(obj, loaded_value)
759
+ else
760
+ loaded_value
761
+ end
762
+
763
+ ruby_kwargs[ruby_kwargs_key] = prepared_value
764
+ end
765
+ end
766
+ end
767
+
768
+ @extras.each do |extra_arg|
769
+ ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
770
+ end
771
+
772
+ field_ctx.schema.after_any_lazies(maybe_lazies) do
773
+ ruby_kwargs
774
+ end
775
+ else
776
+ NO_ARGS
777
+ end
778
+ end
779
+
780
+ def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
781
+ with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
782
+ if @resolver_class
783
+ if obj.is_a?(GraphQL::Schema::Object)
784
+ obj = obj.object
785
+ end
786
+ obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
787
+ end
788
+
789
+ # Find a way to resolve this field, checking:
790
+ #
791
+ # - A method on the type instance;
792
+ # - Hash keys, if the wrapped object is a hash;
793
+ # - A method on the wrapped object;
794
+ # - Or, raise not implemented.
795
+ #
796
+ if obj.respond_to?(@resolver_method)
797
+ # Call the method with kwargs, if there are any
798
+ if ruby_kwargs.any?
799
+ obj.public_send(@resolver_method, **ruby_kwargs)
800
+ else
801
+ obj.public_send(@resolver_method)
802
+ end
803
+ elsif obj.object.is_a?(Hash)
804
+ inner_object = obj.object
805
+ if inner_object.key?(@method_sym)
806
+ inner_object[@method_sym]
807
+ else
808
+ inner_object[@method_str]
809
+ end
810
+ elsif obj.object.respond_to?(@method_sym)
811
+ if ruby_kwargs.any?
812
+ obj.object.public_send(@method_sym, **ruby_kwargs)
813
+ else
814
+ obj.object.public_send(@method_sym)
815
+ end
816
+ else
817
+ raise <<-ERR
818
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
819
+
820
+ - `#{obj.class}##{@resolver_method}`, which did not exist
821
+ - `#{obj.object.class}##{@method_sym}`, which did not exist
822
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
823
+
824
+ To implement this field, define one of the methods above (and check for typos)
825
+ ERR
826
+ end
827
+ end
828
+ end
829
+
830
+ # Wrap execution with hooks.
831
+ # Written iteratively to avoid big stack traces.
832
+ # @return [Object] Whatever the
833
+ def with_extensions(obj, args, ctx)
834
+ if @extensions.empty?
835
+ yield(obj, args)
836
+ else
837
+ # This is a hack to get the _last_ value for extended obj and args,
838
+ # in case one of the extensions doesn't `yield`.
839
+ # (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
840
+ extended = { args: args, obj: obj, memos: nil }
841
+ value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
842
+ yield(obj, args)
843
+ end
844
+
845
+ extended_obj = extended[:obj]
846
+ extended_args = extended[:args]
847
+ memos = extended[:memos] || EMPTY_HASH
848
+
849
+ ctx.schema.after_lazy(value) do |resolved_value|
850
+ idx = 0
851
+ @extensions.each do |ext|
852
+ memo = memos[idx]
853
+ # TODO after_lazy?
854
+ resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
855
+ idx += 1
856
+ end
857
+ resolved_value
858
+ end
859
+ end
860
+ end
861
+
862
+ def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
863
+ extension = @extensions[idx]
864
+ if extension
865
+ extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
866
+ if memo
867
+ memos = extended[:memos] ||= {}
868
+ memos[idx] = memo
869
+ end
870
+ extended[:obj] = extended_obj
871
+ extended[:args] = extended_args
872
+ run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
873
+ end
874
+ else
875
+ yield(obj, args)
876
+ end
877
+ end
878
+ end
879
+ end
880
+ end