graphql 0.16.0 → 2.0.15

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (490) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +5 -0
  3. data/lib/generators/graphql/core.rb +69 -0
  4. data/lib/generators/graphql/enum_generator.rb +27 -0
  5. data/lib/generators/graphql/field_extractor.rb +31 -0
  6. data/lib/generators/graphql/input_generator.rb +50 -0
  7. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  8. data/lib/generators/graphql/install/templates/base_mutation.erb +10 -0
  9. data/lib/generators/graphql/install/templates/mutation_type.erb +12 -0
  10. data/lib/generators/graphql/install_generator.rb +197 -0
  11. data/lib/generators/graphql/interface_generator.rb +27 -0
  12. data/lib/generators/graphql/loader_generator.rb +21 -0
  13. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  15. data/lib/generators/graphql/mutation_generator.rb +30 -0
  16. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  17. data/lib/generators/graphql/object_generator.rb +50 -0
  18. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  19. data/lib/generators/graphql/relay.rb +49 -0
  20. data/lib/generators/graphql/relay_generator.rb +21 -0
  21. data/lib/generators/graphql/scalar_generator.rb +22 -0
  22. data/lib/generators/graphql/templates/base_argument.erb +6 -0
  23. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  24. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  25. data/lib/generators/graphql/templates/base_enum.erb +6 -0
  26. data/lib/generators/graphql/templates/base_field.erb +7 -0
  27. data/lib/generators/graphql/templates/base_input_object.erb +7 -0
  28. data/lib/generators/graphql/templates/base_interface.erb +9 -0
  29. data/lib/generators/graphql/templates/base_object.erb +7 -0
  30. data/lib/generators/graphql/templates/base_scalar.erb +6 -0
  31. data/lib/generators/graphql/templates/base_union.erb +6 -0
  32. data/lib/generators/graphql/templates/enum.erb +11 -0
  33. data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
  34. data/lib/generators/graphql/templates/input.erb +9 -0
  35. data/lib/generators/graphql/templates/interface.erb +10 -0
  36. data/lib/generators/graphql/templates/loader.erb +19 -0
  37. data/lib/generators/graphql/templates/mutation.erb +16 -0
  38. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  40. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  41. data/lib/generators/graphql/templates/node_type.erb +9 -0
  42. data/lib/generators/graphql/templates/object.erb +10 -0
  43. data/lib/generators/graphql/templates/query_type.erb +15 -0
  44. data/lib/generators/graphql/templates/scalar.erb +17 -0
  45. data/lib/generators/graphql/templates/schema.erb +30 -0
  46. data/lib/generators/graphql/templates/union.erb +9 -0
  47. data/lib/generators/graphql/type_generator.rb +135 -0
  48. data/lib/generators/graphql/union_generator.rb +33 -0
  49. data/lib/graphql/analysis/ast/analyzer.rb +84 -0
  50. data/lib/graphql/analysis/ast/field_usage.rb +57 -0
  51. data/lib/graphql/analysis/ast/max_query_complexity.rb +22 -0
  52. data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
  53. data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
  54. data/lib/graphql/analysis/ast/query_depth.rb +55 -0
  55. data/lib/graphql/analysis/ast/visitor.rb +269 -0
  56. data/lib/graphql/analysis/ast.rb +81 -0
  57. data/lib/graphql/analysis.rb +2 -5
  58. data/lib/graphql/analysis_error.rb +1 -0
  59. data/lib/graphql/backtrace/inspect_result.rb +50 -0
  60. data/lib/graphql/backtrace/table.rb +141 -0
  61. data/lib/graphql/backtrace/traced_error.rb +54 -0
  62. data/lib/graphql/backtrace/tracer.rb +80 -0
  63. data/lib/graphql/backtrace.rb +58 -0
  64. data/lib/graphql/coercion_error.rb +13 -0
  65. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  66. data/lib/graphql/dataloader/request.rb +19 -0
  67. data/lib/graphql/dataloader/request_all.rb +19 -0
  68. data/lib/graphql/dataloader/source.rb +164 -0
  69. data/lib/graphql/dataloader.rb +311 -0
  70. data/lib/graphql/date_encoding_error.rb +16 -0
  71. data/lib/graphql/deprecation.rb +9 -0
  72. data/lib/graphql/dig.rb +19 -0
  73. data/lib/graphql/execution/directive_checks.rb +37 -0
  74. data/lib/graphql/execution/errors.rb +93 -0
  75. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  76. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  77. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  78. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  79. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  80. data/lib/graphql/execution/interpreter/resolve.rb +77 -0
  81. data/lib/graphql/execution/interpreter/runtime.rb +994 -0
  82. data/lib/graphql/execution/interpreter.rb +226 -0
  83. data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
  84. data/lib/graphql/execution/lazy.rb +75 -0
  85. data/lib/graphql/execution/lookahead.rb +311 -0
  86. data/lib/graphql/execution/multiplex.rb +45 -0
  87. data/lib/graphql/execution.rb +18 -0
  88. data/lib/graphql/execution_error.rb +34 -1
  89. data/lib/graphql/filter.rb +53 -0
  90. data/lib/graphql/integer_decoding_error.rb +17 -0
  91. data/lib/graphql/integer_encoding_error.rb +36 -0
  92. data/lib/graphql/introspection/base_object.rb +13 -0
  93. data/lib/graphql/introspection/directive_location_enum.rb +12 -5
  94. data/lib/graphql/introspection/directive_type.rb +30 -10
  95. data/lib/graphql/introspection/dynamic_fields.rb +12 -0
  96. data/lib/graphql/introspection/entry_points.rb +22 -0
  97. data/lib/graphql/introspection/enum_value_type.rb +21 -8
  98. data/lib/graphql/introspection/field_type.rb +26 -10
  99. data/lib/graphql/introspection/input_value_type.rb +64 -14
  100. data/lib/graphql/introspection/introspection_query.rb +7 -76
  101. data/lib/graphql/introspection/schema_type.rb +42 -17
  102. data/lib/graphql/introspection/type_kind_enum.rb +11 -5
  103. data/lib/graphql/introspection/type_type.rb +104 -16
  104. data/lib/graphql/introspection.rb +104 -13
  105. data/lib/graphql/invalid_name_error.rb +11 -0
  106. data/lib/graphql/invalid_null_error.rb +36 -8
  107. data/lib/graphql/language/block_string.rb +99 -0
  108. data/lib/graphql/language/cache.rb +37 -0
  109. data/lib/graphql/language/definition_slice.rb +41 -0
  110. data/lib/graphql/language/document_from_schema_definition.rb +335 -0
  111. data/lib/graphql/language/generation.rb +16 -86
  112. data/lib/graphql/language/lexer.rb +1436 -705
  113. data/lib/graphql/language/lexer.rl +172 -64
  114. data/lib/graphql/language/nodes.rb +617 -105
  115. data/lib/graphql/language/parser.rb +1524 -430
  116. data/lib/graphql/language/parser.y +348 -73
  117. data/lib/graphql/language/printer.rb +386 -0
  118. data/lib/graphql/language/sanitized_printer.rb +222 -0
  119. data/lib/graphql/language/token.rb +16 -3
  120. data/lib/graphql/language/visitor.rb +169 -25
  121. data/lib/graphql/language.rb +30 -0
  122. data/lib/graphql/load_application_object_failed_error.rb +22 -0
  123. data/lib/graphql/name_validator.rb +11 -0
  124. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  125. data/lib/graphql/pagination/array_connection.rb +79 -0
  126. data/lib/graphql/pagination/connection.rb +253 -0
  127. data/lib/graphql/pagination/connections.rb +135 -0
  128. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  129. data/lib/graphql/pagination/relation_connection.rb +228 -0
  130. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  131. data/lib/graphql/pagination.rb +6 -0
  132. data/lib/graphql/parse_error.rb +24 -0
  133. data/lib/graphql/query/context.rb +266 -12
  134. data/lib/graphql/query/fingerprint.rb +26 -0
  135. data/lib/graphql/query/input_validation_result.rb +34 -7
  136. data/lib/graphql/query/null_context.rb +52 -0
  137. data/lib/graphql/query/result.rb +63 -0
  138. data/lib/graphql/query/validation_pipeline.rb +114 -0
  139. data/lib/graphql/query/variable_validation_error.rb +27 -3
  140. data/lib/graphql/query/variables.rb +75 -24
  141. data/lib/graphql/query.rb +359 -92
  142. data/lib/graphql/railtie.rb +13 -0
  143. data/lib/graphql/rake_task/validate.rb +63 -0
  144. data/lib/graphql/rake_task.rb +146 -0
  145. data/lib/graphql/relay/range_add.rb +52 -0
  146. data/lib/graphql/relay.rb +3 -0
  147. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  148. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  149. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  150. data/lib/graphql/rubocop.rb +4 -0
  151. data/lib/graphql/runtime_type_error.rb +5 -0
  152. data/lib/graphql/schema/addition.rb +245 -0
  153. data/lib/graphql/schema/argument.rb +395 -0
  154. data/lib/graphql/schema/base_64_bp.rb +26 -0
  155. data/lib/graphql/schema/base_64_encoder.rb +21 -0
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
  158. data/lib/graphql/schema/build_from_definition.rb +492 -0
  159. data/lib/graphql/schema/built_in_types.rb +12 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  161. data/lib/graphql/schema/directive/feature.rb +66 -0
  162. data/lib/graphql/schema/directive/flagged.rb +57 -0
  163. data/lib/graphql/schema/directive/include.rb +25 -0
  164. data/lib/graphql/schema/directive/one_of.rb +12 -0
  165. data/lib/graphql/schema/directive/skip.rb +25 -0
  166. data/lib/graphql/schema/directive/transform.rb +60 -0
  167. data/lib/graphql/schema/directive.rb +212 -0
  168. data/lib/graphql/schema/enum.rb +176 -0
  169. data/lib/graphql/schema/enum_value.rb +77 -0
  170. data/lib/graphql/schema/field/connection_extension.rb +80 -0
  171. data/lib/graphql/schema/field/scope_extension.rb +22 -0
  172. data/lib/graphql/schema/field.rb +862 -0
  173. data/lib/graphql/schema/field_extension.rb +156 -0
  174. data/lib/graphql/schema/find_inherited_value.rb +36 -0
  175. data/lib/graphql/schema/finder.rb +155 -0
  176. data/lib/graphql/schema/input_object.rb +258 -0
  177. data/lib/graphql/schema/interface.rb +113 -0
  178. data/lib/graphql/schema/introspection_system.rb +164 -0
  179. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  180. data/lib/graphql/schema/late_bound_type.rb +37 -0
  181. data/lib/graphql/schema/list.rb +86 -0
  182. data/lib/graphql/schema/loader.rb +228 -0
  183. data/lib/graphql/schema/member/base_dsl_methods.rb +124 -0
  184. data/lib/graphql/schema/member/build_type.rb +178 -0
  185. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  186. data/lib/graphql/schema/member/has_arguments.rb +376 -0
  187. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  188. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  189. data/lib/graphql/schema/member/has_directives.rb +113 -0
  190. data/lib/graphql/schema/member/has_fields.rb +163 -0
  191. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  192. data/lib/graphql/schema/member/has_path.rb +25 -0
  193. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  194. data/lib/graphql/schema/member/has_validators.rb +31 -0
  195. data/lib/graphql/schema/member/relay_shortcuts.rb +73 -0
  196. data/lib/graphql/schema/member/scoped.rb +21 -0
  197. data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
  198. data/lib/graphql/schema/member/validates_input.rb +33 -0
  199. data/lib/graphql/schema/member.rb +39 -0
  200. data/lib/graphql/schema/mutation.rb +85 -0
  201. data/lib/graphql/schema/non_null.rb +67 -0
  202. data/lib/graphql/schema/null_mask.rb +11 -0
  203. data/lib/graphql/schema/object.rb +117 -0
  204. data/lib/graphql/schema/printer.rb +72 -128
  205. data/lib/graphql/schema/relay_classic_mutation.rb +179 -0
  206. data/lib/graphql/schema/resolver/has_payload_type.rb +106 -0
  207. data/lib/graphql/schema/resolver.rb +402 -0
  208. data/lib/graphql/schema/scalar.rb +68 -0
  209. data/lib/graphql/schema/subscription.rb +148 -0
  210. data/lib/graphql/schema/timeout.rb +123 -0
  211. data/lib/graphql/schema/type_expression.rb +29 -5
  212. data/lib/graphql/schema/type_membership.rb +51 -0
  213. data/lib/graphql/schema/union.rb +81 -0
  214. data/lib/graphql/schema/unique_within_type.rb +34 -0
  215. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  216. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  217. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  218. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  219. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  220. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  221. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  222. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  223. data/lib/graphql/schema/validator.rb +171 -0
  224. data/lib/graphql/schema/warden.rb +413 -0
  225. data/lib/graphql/schema/wrapper.rb +24 -0
  226. data/lib/graphql/schema.rb +1179 -104
  227. data/lib/graphql/static_validation/all_rules.rb +14 -0
  228. data/lib/graphql/static_validation/base_visitor.rb +200 -0
  229. data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
  230. data/lib/graphql/static_validation/error.rb +46 -0
  231. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  232. data/lib/graphql/static_validation/literal_validator.rb +113 -22
  233. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +59 -11
  234. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
  235. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
  236. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  237. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +62 -8
  238. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
  239. data/lib/graphql/static_validation/rules/directives_are_defined.rb +20 -13
  240. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  241. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +32 -26
  242. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  243. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +21 -23
  244. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  245. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +55 -18
  246. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  247. data/lib/graphql/static_validation/rules/fields_will_merge.rb +390 -70
  248. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
  249. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
  250. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  251. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +54 -37
  252. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  253. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +26 -16
  254. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  255. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +13 -19
  256. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  257. data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
  258. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  259. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
  260. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  261. data/lib/graphql/static_validation/rules/fragments_are_used.rb +22 -33
  262. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  263. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  264. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  265. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
  266. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  267. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
  268. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  269. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  270. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  271. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
  272. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  273. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  274. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  275. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +22 -21
  276. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  277. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
  278. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  279. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
  280. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  281. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +56 -0
  282. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  283. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +36 -18
  284. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  285. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
  286. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  287. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +103 -39
  288. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  289. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +22 -14
  290. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  291. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +92 -70
  292. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  293. data/lib/graphql/static_validation/type_stack.rb +85 -24
  294. data/lib/graphql/static_validation/validation_context.rb +25 -46
  295. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  296. data/lib/graphql/static_validation/validator.rb +46 -15
  297. data/lib/graphql/static_validation.rb +6 -3
  298. data/lib/graphql/string_encoding_error.rb +20 -0
  299. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +247 -0
  300. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  301. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  302. data/lib/graphql/subscriptions/event.rb +144 -0
  303. data/lib/graphql/subscriptions/instrumentation.rb +28 -0
  304. data/lib/graphql/subscriptions/serialize.rb +158 -0
  305. data/lib/graphql/subscriptions.rb +306 -0
  306. data/lib/graphql/tracing/active_support_notifications_tracing.rb +21 -0
  307. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  308. data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
  309. data/lib/graphql/tracing/data_dog_tracing.rb +100 -0
  310. data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
  311. data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
  312. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  313. data/lib/graphql/tracing/platform_tracing.rb +122 -0
  314. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
  315. data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
  316. data/lib/graphql/tracing/scout_tracing.rb +54 -0
  317. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  318. data/lib/graphql/tracing.rb +94 -0
  319. data/lib/graphql/type_kinds.rb +50 -22
  320. data/lib/graphql/types/big_int.rb +23 -0
  321. data/lib/graphql/types/boolean.rb +18 -0
  322. data/lib/graphql/types/float.rb +19 -0
  323. data/lib/graphql/types/id.rb +24 -0
  324. data/lib/graphql/types/int.rb +36 -0
  325. data/lib/graphql/types/iso_8601_date.rb +45 -0
  326. data/lib/graphql/types/iso_8601_date_time.rb +76 -0
  327. data/lib/graphql/types/json.rb +25 -0
  328. data/lib/graphql/types/relay/base_connection.rb +49 -0
  329. data/lib/graphql/types/relay/base_edge.rb +29 -0
  330. data/lib/graphql/types/relay/connection_behaviors.rb +154 -0
  331. data/lib/graphql/types/relay/default_relay.rb +21 -0
  332. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  333. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  334. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  335. data/lib/graphql/types/relay/node.rb +15 -0
  336. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  337. data/lib/graphql/types/relay/page_info.rb +11 -0
  338. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  339. data/lib/graphql/types/relay.rb +39 -0
  340. data/lib/graphql/types/string.rb +29 -0
  341. data/lib/graphql/types.rb +11 -0
  342. data/lib/graphql/unauthorized_error.rb +29 -0
  343. data/lib/graphql/unauthorized_field_error.rb +23 -0
  344. data/lib/graphql/unresolved_type_error.rb +35 -0
  345. data/lib/graphql/version.rb +2 -1
  346. data/lib/graphql.rb +86 -41
  347. data/readme.md +15 -101
  348. metadata +394 -279
  349. data/lib/graphql/analysis/analyze_query.rb +0 -73
  350. data/lib/graphql/analysis/max_query_complexity.rb +0 -25
  351. data/lib/graphql/analysis/max_query_depth.rb +0 -25
  352. data/lib/graphql/analysis/query_complexity.rb +0 -122
  353. data/lib/graphql/analysis/query_depth.rb +0 -54
  354. data/lib/graphql/argument.rb +0 -25
  355. data/lib/graphql/base_type.rb +0 -115
  356. data/lib/graphql/boolean_type.rb +0 -9
  357. data/lib/graphql/define/assign_argument.rb +0 -20
  358. data/lib/graphql/define/assign_enum_value.rb +0 -16
  359. data/lib/graphql/define/assign_object_field.rb +0 -21
  360. data/lib/graphql/define/assignment_dictionary.rb +0 -26
  361. data/lib/graphql/define/defined_object_proxy.rb +0 -32
  362. data/lib/graphql/define/instance_definable.rb +0 -79
  363. data/lib/graphql/define/non_null_with_bang.rb +0 -15
  364. data/lib/graphql/define/type_definer.rb +0 -30
  365. data/lib/graphql/define.rb +0 -8
  366. data/lib/graphql/directive/include_directive.rb +0 -10
  367. data/lib/graphql/directive/skip_directive.rb +0 -11
  368. data/lib/graphql/directive.rb +0 -49
  369. data/lib/graphql/enum_type.rb +0 -95
  370. data/lib/graphql/field.rb +0 -131
  371. data/lib/graphql/float_type.rb +0 -5
  372. data/lib/graphql/id_type.rb +0 -12
  373. data/lib/graphql/input_object_type.rb +0 -71
  374. data/lib/graphql/int_type.rb +0 -5
  375. data/lib/graphql/interface_type.rb +0 -38
  376. data/lib/graphql/internal_representation/node.rb +0 -81
  377. data/lib/graphql/internal_representation/rewrite.rb +0 -177
  378. data/lib/graphql/internal_representation.rb +0 -2
  379. data/lib/graphql/introspection/arguments_field.rb +0 -5
  380. data/lib/graphql/introspection/enum_values_field.rb +0 -13
  381. data/lib/graphql/introspection/fields_field.rb +0 -13
  382. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  383. data/lib/graphql/introspection/interfaces_field.rb +0 -5
  384. data/lib/graphql/introspection/of_type_field.rb +0 -6
  385. data/lib/graphql/introspection/possible_types_field.rb +0 -11
  386. data/lib/graphql/introspection/schema_field.rb +0 -15
  387. data/lib/graphql/introspection/type_by_name_field.rb +0 -16
  388. data/lib/graphql/introspection/typename_field.rb +0 -15
  389. data/lib/graphql/list_type.rb +0 -46
  390. data/lib/graphql/non_null_type.rb +0 -43
  391. data/lib/graphql/object_type.rb +0 -93
  392. data/lib/graphql/query/arguments.rb +0 -76
  393. data/lib/graphql/query/directive_resolution.rb +0 -16
  394. data/lib/graphql/query/executor.rb +0 -45
  395. data/lib/graphql/query/literal_input.rb +0 -90
  396. data/lib/graphql/query/serial_execution/execution_context.rb +0 -31
  397. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -82
  398. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -27
  399. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -42
  400. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -107
  401. data/lib/graphql/query/serial_execution.rb +0 -41
  402. data/lib/graphql/query/type_resolver.rb +0 -25
  403. data/lib/graphql/scalar_type.rb +0 -53
  404. data/lib/graphql/schema/catchall_middleware.rb +0 -34
  405. data/lib/graphql/schema/middleware_chain.rb +0 -28
  406. data/lib/graphql/schema/possible_types.rb +0 -34
  407. data/lib/graphql/schema/reduce_types.rb +0 -68
  408. data/lib/graphql/schema/rescue_middleware.rb +0 -53
  409. data/lib/graphql/schema/timeout_middleware.rb +0 -67
  410. data/lib/graphql/schema/type_map.rb +0 -30
  411. data/lib/graphql/schema/validation.rb +0 -164
  412. data/lib/graphql/static_validation/arguments_validator.rb +0 -48
  413. data/lib/graphql/static_validation/message.rb +0 -36
  414. data/lib/graphql/string_type.rb +0 -5
  415. data/lib/graphql/union_type.rb +0 -38
  416. data/spec/graphql/analysis/analyze_query_spec.rb +0 -50
  417. data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -62
  418. data/spec/graphql/analysis/max_query_depth_spec.rb +0 -100
  419. data/spec/graphql/analysis/query_complexity_spec.rb +0 -235
  420. data/spec/graphql/analysis/query_depth_spec.rb +0 -80
  421. data/spec/graphql/argument_spec.rb +0 -20
  422. data/spec/graphql/base_type_spec.rb +0 -24
  423. data/spec/graphql/boolean_type_spec.rb +0 -20
  424. data/spec/graphql/define/instance_definable_spec.rb +0 -55
  425. data/spec/graphql/directive_spec.rb +0 -77
  426. data/spec/graphql/enum_type_spec.rb +0 -31
  427. data/spec/graphql/execution_error_spec.rb +0 -61
  428. data/spec/graphql/field_spec.rb +0 -92
  429. data/spec/graphql/float_type_spec.rb +0 -15
  430. data/spec/graphql/id_type_spec.rb +0 -32
  431. data/spec/graphql/input_object_type_spec.rb +0 -162
  432. data/spec/graphql/int_type_spec.rb +0 -15
  433. data/spec/graphql/interface_type_spec.rb +0 -56
  434. data/spec/graphql/internal_representation/rewrite_spec.rb +0 -120
  435. data/spec/graphql/introspection/directive_type_spec.rb +0 -50
  436. data/spec/graphql/introspection/input_value_type_spec.rb +0 -42
  437. data/spec/graphql/introspection/introspection_query_spec.rb +0 -10
  438. data/spec/graphql/introspection/schema_type_spec.rb +0 -45
  439. data/spec/graphql/introspection/type_type_spec.rb +0 -122
  440. data/spec/graphql/language/generation_spec.rb +0 -42
  441. data/spec/graphql/language/parser_spec.rb +0 -442
  442. data/spec/graphql/language/visitor_spec.rb +0 -49
  443. data/spec/graphql/list_type_spec.rb +0 -32
  444. data/spec/graphql/non_null_type_spec.rb +0 -31
  445. data/spec/graphql/object_type_spec.rb +0 -42
  446. data/spec/graphql/query/arguments_spec.rb +0 -25
  447. data/spec/graphql/query/context_spec.rb +0 -83
  448. data/spec/graphql/query/executor_spec.rb +0 -273
  449. data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -53
  450. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -66
  451. data/spec/graphql/query/type_resolver_spec.rb +0 -8
  452. data/spec/graphql/query/variables_spec.rb +0 -28
  453. data/spec/graphql/query_spec.rb +0 -363
  454. data/spec/graphql/scalar_type_spec.rb +0 -61
  455. data/spec/graphql/schema/catchall_middleware_spec.rb +0 -32
  456. data/spec/graphql/schema/middleware_chain_spec.rb +0 -42
  457. data/spec/graphql/schema/printer_spec.rb +0 -190
  458. data/spec/graphql/schema/reduce_types_spec.rb +0 -102
  459. data/spec/graphql/schema/rescue_middleware_spec.rb +0 -33
  460. data/spec/graphql/schema/timeout_middleware_spec.rb +0 -180
  461. data/spec/graphql/schema/type_expression_spec.rb +0 -38
  462. data/spec/graphql/schema/validation_spec.rb +0 -219
  463. data/spec/graphql/schema_spec.rb +0 -23
  464. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -63
  465. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -48
  466. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -34
  467. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -39
  468. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -60
  469. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -31
  470. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -48
  471. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -47
  472. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -39
  473. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -44
  474. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -49
  475. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -25
  476. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -42
  477. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -44
  478. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -63
  479. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -37
  480. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -53
  481. data/spec/graphql/static_validation/type_stack_spec.rb +0 -37
  482. data/spec/graphql/static_validation/validator_spec.rb +0 -69
  483. data/spec/graphql/string_type_spec.rb +0 -15
  484. data/spec/graphql/union_type_spec.rb +0 -31
  485. data/spec/spec_helper.rb +0 -18
  486. data/spec/support/dairy_app.rb +0 -309
  487. data/spec/support/dairy_data.rb +0 -23
  488. data/spec/support/minimum_input_object.rb +0 -16
  489. data/spec/support/star_wars_data.rb +0 -71
  490. data/spec/support/star_wars_schema.rb +0 -76
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module StaticValidation
3
4
  # Default rules for {GraphQL::StaticValidation::Validator}
@@ -6,9 +7,14 @@ module GraphQL
6
7
  # which stops the visit on that node. That way it doesn't try to find fields on types that
7
8
  # don't exist, etc.
8
9
  ALL_RULES = [
10
+ GraphQL::StaticValidation::NoDefinitionsArePresent,
9
11
  GraphQL::StaticValidation::DirectivesAreDefined,
10
12
  GraphQL::StaticValidation::DirectivesAreInValidLocations,
13
+ GraphQL::StaticValidation::UniqueDirectivesPerLocation,
14
+ GraphQL::StaticValidation::OperationNamesAreValid,
15
+ GraphQL::StaticValidation::FragmentNamesAreUnique,
11
16
  GraphQL::StaticValidation::FragmentsAreFinite,
17
+ GraphQL::StaticValidation::FragmentsAreNamed,
12
18
  GraphQL::StaticValidation::FragmentsAreUsed,
13
19
  GraphQL::StaticValidation::FragmentTypesExist,
14
20
  GraphQL::StaticValidation::FragmentsAreOnCompositeTypes,
@@ -19,10 +25,18 @@ module GraphQL
19
25
  GraphQL::StaticValidation::ArgumentsAreDefined,
20
26
  GraphQL::StaticValidation::ArgumentLiteralsAreCompatible,
21
27
  GraphQL::StaticValidation::RequiredArgumentsArePresent,
28
+ GraphQL::StaticValidation::RequiredInputObjectAttributesArePresent,
29
+ GraphQL::StaticValidation::ArgumentNamesAreUnique,
30
+ GraphQL::StaticValidation::VariableNamesAreUnique,
22
31
  GraphQL::StaticValidation::VariablesAreInputTypes,
23
32
  GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped,
24
33
  GraphQL::StaticValidation::VariablesAreUsedAndDefined,
25
34
  GraphQL::StaticValidation::VariableUsagesAreAllowed,
35
+ GraphQL::StaticValidation::MutationRootExists,
36
+ GraphQL::StaticValidation::QueryRootExists,
37
+ GraphQL::StaticValidation::SubscriptionRootExists,
38
+ GraphQL::StaticValidation::InputObjectNamesAreUnique,
39
+ GraphQL::StaticValidation::OneOfInputObjectsAreValid,
26
40
  ]
27
41
  end
28
42
  end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class BaseVisitor < GraphQL::Language::Visitor
5
+ def initialize(document, context)
6
+ @path = []
7
+ @object_types = []
8
+ @directives = []
9
+ @field_definitions = []
10
+ @argument_definitions = []
11
+ @directive_definitions = []
12
+ @context = context
13
+ @schema = context.schema
14
+ super(document)
15
+ end
16
+
17
+ attr_reader :context
18
+
19
+ # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
20
+ attr_reader :object_types
21
+
22
+ # @return [Array<String>] The nesting of the current position in the AST
23
+ def path
24
+ @path.dup
25
+ end
26
+
27
+ # Build a class to visit the AST and perform validation,
28
+ # or use a pre-built class if rules is `ALL_RULES` or empty.
29
+ # @param rules [Array<Module, Class>]
30
+ # @return [Class] A class for validating `rules` during visitation
31
+ def self.including_rules(rules)
32
+ if rules.empty?
33
+ # It's not doing _anything?!?_
34
+ BaseVisitor
35
+ elsif rules == ALL_RULES
36
+ InterpreterVisitor
37
+ else
38
+ visitor_class = Class.new(self) do
39
+ include(GraphQL::StaticValidation::DefinitionDependencies)
40
+ end
41
+
42
+ rules.reverse_each do |r|
43
+ # If it's a class, it gets attached later.
44
+ if !r.is_a?(Class)
45
+ visitor_class.include(r)
46
+ end
47
+ end
48
+
49
+ visitor_class.include(ContextMethods)
50
+ visitor_class
51
+ end
52
+ end
53
+
54
+ module ContextMethods
55
+ def on_operation_definition(node, parent)
56
+ object_type = @schema.root_type_for_operation(node.operation_type)
57
+ push_type(object_type)
58
+ @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
59
+ super
60
+ @object_types.pop
61
+ @path.pop
62
+ end
63
+
64
+ def on_fragment_definition(node, parent)
65
+ on_fragment_with_type(node) do
66
+ @path.push("fragment #{node.name}")
67
+ super
68
+ end
69
+ end
70
+
71
+ def on_inline_fragment(node, parent)
72
+ on_fragment_with_type(node) do
73
+ @path.push("...#{node.type ? " on #{node.type.to_query_string}" : ""}")
74
+ super
75
+ end
76
+ end
77
+
78
+ def on_field(node, parent)
79
+ parent_type = @object_types.last
80
+ field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
81
+ @field_definitions.push(field_definition)
82
+ if !field_definition.nil?
83
+ next_object_type = field_definition.type.unwrap
84
+ push_type(next_object_type)
85
+ else
86
+ push_type(nil)
87
+ end
88
+ @path.push(node.alias || node.name)
89
+ super
90
+ @field_definitions.pop
91
+ @object_types.pop
92
+ @path.pop
93
+ end
94
+
95
+ def on_directive(node, parent)
96
+ directive_defn = @context.schema_directives[node.name]
97
+ @directive_definitions.push(directive_defn)
98
+ super
99
+ @directive_definitions.pop
100
+ end
101
+
102
+ def on_argument(node, parent)
103
+ argument_defn = if (arg = @argument_definitions.last)
104
+ arg_type = arg.type.unwrap
105
+ if arg_type.kind.input_object?
106
+ @context.warden.get_argument(arg_type, node.name)
107
+ else
108
+ nil
109
+ end
110
+ elsif (directive_defn = @directive_definitions.last)
111
+ @context.warden.get_argument(directive_defn, node.name)
112
+ elsif (field_defn = @field_definitions.last)
113
+ @context.warden.get_argument(field_defn, node.name)
114
+ else
115
+ nil
116
+ end
117
+
118
+ @argument_definitions.push(argument_defn)
119
+ @path.push(node.name)
120
+ super
121
+ @argument_definitions.pop
122
+ @path.pop
123
+ end
124
+
125
+ def on_fragment_spread(node, parent)
126
+ @path.push("... #{node.name}")
127
+ super
128
+ @path.pop
129
+ end
130
+
131
+ def on_input_object(node, parent)
132
+ arg_defn = @argument_definitions.last
133
+ if arg_defn && arg_defn.type.list?
134
+ @path.push(parent.children.index(node))
135
+ super
136
+ @path.pop
137
+ else
138
+ super
139
+ end
140
+ end
141
+
142
+ # @return [GraphQL::BaseType] The current object type
143
+ def type_definition
144
+ @object_types.last
145
+ end
146
+
147
+ # @return [GraphQL::BaseType] The type which the current type came from
148
+ def parent_type_definition
149
+ @object_types[-2]
150
+ end
151
+
152
+ # @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
153
+ def field_definition
154
+ @field_definitions.last
155
+ end
156
+
157
+ # @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
158
+ def directive_definition
159
+ @directive_definitions.last
160
+ end
161
+
162
+ # @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
163
+ def argument_definition
164
+ # Don't get the _last_ one because that's the current one.
165
+ # Get the second-to-last one, which is the parent of the current one.
166
+ @argument_definitions[-2]
167
+ end
168
+
169
+ private
170
+
171
+ def on_fragment_with_type(node)
172
+ object_type = if node.type
173
+ @context.warden.get_type(node.type.name)
174
+ else
175
+ @object_types.last
176
+ end
177
+ push_type(object_type)
178
+ yield(node)
179
+ @object_types.pop
180
+ @path.pop
181
+ end
182
+
183
+ def push_type(t)
184
+ @object_types.push(t)
185
+ end
186
+ end
187
+
188
+ private
189
+
190
+ def add_error(error, path: nil)
191
+ if @context.too_many_errors?
192
+ throw :too_many_validation_errors
193
+ end
194
+ error.path ||= (path || @path.dup)
195
+ context.errors << error
196
+ end
197
+
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ # Track fragment dependencies for operations
5
+ # and expose the fragment definitions which
6
+ # are used by a given operation
7
+ module DefinitionDependencies
8
+ attr_reader :dependencies
9
+
10
+ def initialize(*)
11
+ super
12
+ @defdep_node_paths = {}
13
+
14
+ # { name => [node, ...] } pairs for fragments (although duplicate-named fragments are _invalid_, they are _possible_)
15
+ @defdep_fragment_definitions = Hash.new{ |h, k| h[k] = [] }
16
+
17
+ # This tracks dependencies from fragment to Node where it was used
18
+ # { fragment_definition_name => [dependent_node, dependent_node]}
19
+ @defdep_dependent_definitions = Hash.new { |h, k| h[k] = Set.new }
20
+
21
+ # First-level usages of spreads within definitions
22
+ # (When a key has an empty list as its value,
23
+ # we can resolve that key's dependents)
24
+ # { definition_node => [node, node ...] }
25
+ @defdep_immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
26
+
27
+ # When we encounter a spread,
28
+ # this node is the one who depends on it
29
+ @defdep_current_parent = nil
30
+ end
31
+
32
+ def on_document(node, parent)
33
+ node.definitions.each do |definition|
34
+ if definition.is_a? GraphQL::Language::Nodes::FragmentDefinition
35
+ @defdep_fragment_definitions[definition.name] << definition
36
+ end
37
+ end
38
+ super
39
+ @dependencies = dependency_map { |defn, spreads, frag|
40
+ context.on_dependency_resolve_handlers.each { |h| h.call(defn, spreads, frag) }
41
+ }
42
+ end
43
+
44
+ def on_operation_definition(node, prev_node)
45
+ @defdep_node_paths[node.name] = NodeWithPath.new(node, context.path)
46
+ @defdep_current_parent = node
47
+ super
48
+ @defdep_current_parent = nil
49
+ end
50
+
51
+ def on_fragment_definition(node, parent)
52
+ @defdep_node_paths[node] = NodeWithPath.new(node, context.path)
53
+ @defdep_current_parent = node
54
+ super
55
+ @defdep_current_parent = nil
56
+ end
57
+
58
+ def on_fragment_spread(node, parent)
59
+ @defdep_node_paths[node] = NodeWithPath.new(node, context.path)
60
+
61
+ # Track both sides of the dependency
62
+ @defdep_dependent_definitions[node.name] << @defdep_current_parent
63
+ @defdep_immediate_dependencies[@defdep_current_parent] << node
64
+ super
65
+ end
66
+
67
+ # A map of operation definitions to an array of that operation's dependencies
68
+ # @return [DependencyMap]
69
+ def dependency_map(&block)
70
+ @dependency_map ||= resolve_dependencies(&block)
71
+ end
72
+
73
+ # Map definition AST nodes to the definition AST nodes they depend on.
74
+ # Expose circular dependencies.
75
+ class DependencyMap
76
+ # @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
77
+ attr_reader :cyclical_definitions
78
+
79
+ # @return [Hash<Node, Array<GraphQL::Language::Nodes::FragmentSpread>>]
80
+ attr_reader :unmet_dependencies
81
+
82
+ # @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
83
+ attr_reader :unused_dependencies
84
+
85
+ def initialize
86
+ @dependencies = Hash.new { |h, k| h[k] = [] }
87
+ @cyclical_definitions = []
88
+ @unmet_dependencies = Hash.new { |h, k| h[k] = [] }
89
+ @unused_dependencies = []
90
+ end
91
+
92
+ # @return [Array<GraphQL::Language::Nodes::AbstractNode>] dependencies for `definition_node`
93
+ def [](definition_node)
94
+ @dependencies[definition_node]
95
+ end
96
+ end
97
+
98
+ class NodeWithPath
99
+ extend Forwardable
100
+ attr_reader :node, :path
101
+ def initialize(node, path)
102
+ @node = node
103
+ @path = path
104
+ end
105
+
106
+ def_delegators :@node, :name, :eql?, :hash
107
+ end
108
+
109
+ private
110
+
111
+ # Return a hash of { node => [node, node ... ]} pairs
112
+ # Keys are top-level definitions
113
+ # Values are arrays of flattened dependencies
114
+ def resolve_dependencies
115
+ dependency_map = DependencyMap.new
116
+ # Don't allow the loop to run more times
117
+ # than the number of fragments in the document
118
+ max_loops = 0
119
+ @defdep_fragment_definitions.each_value do |v|
120
+ max_loops += v.size
121
+ end
122
+
123
+ loops = 0
124
+
125
+ # Instead of tracking independent fragments _as you visit_,
126
+ # determine them at the end. This way, we can treat fragments with the
127
+ # same name as if they were the same name. If _any_ of the fragments
128
+ # with that name has a dependency, we record it.
129
+ independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
130
+
131
+ while fragment_node = independent_fragment_nodes.pop
132
+ loops += 1
133
+ if loops > max_loops
134
+ raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
135
+ end
136
+ # Since it's independent, let's remove it from here.
137
+ # That way, we can use the remainder to identify cycles
138
+ @defdep_immediate_dependencies.delete(fragment_node)
139
+ fragment_usages = @defdep_dependent_definitions[fragment_node.name]
140
+ if fragment_usages.empty?
141
+ # If we didn't record any usages during the visit,
142
+ # then this fragment is unused.
143
+ dependency_map.unused_dependencies << @defdep_node_paths[fragment_node]
144
+ else
145
+ fragment_usages.each do |definition_node|
146
+ # Register the dependency AND second-order dependencies
147
+ dependency_map[definition_node] << fragment_node
148
+ dependency_map[definition_node].concat(dependency_map[fragment_node])
149
+ # Since we've registered it, remove it from our to-do list
150
+ deps = @defdep_immediate_dependencies[definition_node]
151
+ # Can't find a way to _just_ delete from `deps` and return the deleted entries
152
+ removed, remaining = deps.partition { |spread| spread.name == fragment_node.name }
153
+ @defdep_immediate_dependencies[definition_node] = remaining
154
+ if block_given?
155
+ yield(definition_node, removed, fragment_node)
156
+ end
157
+ if remaining.empty? &&
158
+ definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition) &&
159
+ definition_node.name != fragment_node.name
160
+ # If all of this definition's dependencies have
161
+ # been resolved, we can now resolve its
162
+ # own dependents.
163
+ #
164
+ # But, it's possible to have a duplicate-named fragment here.
165
+ # Skip it in that case
166
+ independent_fragment_nodes << definition_node
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ # If any dependencies were _unmet_
173
+ # (eg, spreads with no corresponding definition)
174
+ # then they're still in there
175
+ @defdep_immediate_dependencies.each do |defn_node, deps|
176
+ deps.each do |spread|
177
+ if !@defdep_fragment_definitions.key?(spread.name)
178
+ dependency_map.unmet_dependencies[@defdep_node_paths[defn_node]] << @defdep_node_paths[spread]
179
+ deps.delete(spread)
180
+ end
181
+ end
182
+ if deps.empty?
183
+ @defdep_immediate_dependencies.delete(defn_node)
184
+ end
185
+ end
186
+
187
+ # Anything left in @immediate_dependencies is cyclical
188
+ cyclical_nodes = @defdep_immediate_dependencies.keys.map { |n| @defdep_node_paths[n] }
189
+ # @immediate_dependencies also includes operation names, but we don't care about
190
+ # those. They became nil when we looked them up on `@fragment_definitions`, so remove them.
191
+ cyclical_nodes.compact!
192
+ dependency_map.cyclical_definitions.concat(cyclical_nodes)
193
+
194
+ dependency_map
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ # Generates GraphQL-compliant validation message.
5
+ class Error
6
+ # Convenience for validators
7
+ module ErrorHelper
8
+ # Error `error_message` is located at `node`
9
+ def error(error_message, nodes, context: nil, path: nil, extensions: {})
10
+ path ||= context.path
11
+ nodes = Array(nodes)
12
+ GraphQL::StaticValidation::Error.new(error_message, nodes: nodes, path: path)
13
+ end
14
+ end
15
+
16
+ attr_reader :message
17
+ attr_accessor :path
18
+
19
+ def initialize(message, path: nil, nodes: [])
20
+ @message = message
21
+ @nodes = Array(nodes)
22
+ @path = path
23
+ end
24
+
25
+ # A hash representation of this Message
26
+ def to_h
27
+ {
28
+ "message" => message,
29
+ "locations" => locations
30
+ }.tap { |h| h["path"] = path unless path.nil? }
31
+ end
32
+
33
+ attr_reader :nodes
34
+
35
+ private
36
+
37
+ def locations
38
+ nodes.map do |node|
39
+ h = {"line" => node.line, "column" => node.col}
40
+ h["filename"] = node.filename if node.filename
41
+ h
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class InterpreterVisitor < BaseVisitor
5
+ include(GraphQL::StaticValidation::DefinitionDependencies)
6
+
7
+ StaticValidation::ALL_RULES.reverse_each do |r|
8
+ include(r)
9
+ end
10
+
11
+ include(ContextMethods)
12
+ end
13
+ end
14
+ end
@@ -1,52 +1,143 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module StaticValidation
3
4
  # Test whether `ast_value` is a valid input for `type`
4
5
  class LiteralValidator
6
+ def initialize(context:)
7
+ @context = context
8
+ @warden = context.warden
9
+ @invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
10
+ @valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
11
+ end
12
+
5
13
  def validate(ast_value, type)
6
- if type.kind.non_null?
7
- (!ast_value.nil?) && validate(ast_value, type.of_type)
14
+ catch(:invalid) do
15
+ recursively_validate(ast_value, type)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def recursively_validate(ast_value, type)
22
+ if type.nil?
23
+ # this means we're an undefined argument, see #present_input_field_values_are_valid
24
+ maybe_raise_if_invalid(ast_value) do
25
+ @invalid_response
26
+ end
27
+ elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
28
+ maybe_raise_if_invalid(ast_value) do
29
+ type.kind.non_null? ? @invalid_response : @valid_response
30
+ end
31
+ elsif type.kind.non_null?
32
+ maybe_raise_if_invalid(ast_value) do
33
+ ast_value.nil? ?
34
+ @invalid_response :
35
+ recursively_validate(ast_value, type.of_type)
36
+ end
8
37
  elsif type.kind.list?
9
38
  item_type = type.of_type
10
- ensure_array(ast_value).all? { |val| validate(val, item_type) }
11
- elsif type.kind.scalar? && !ast_value.is_a?(GraphQL::Language::Nodes::AbstractNode) && !ast_value.is_a?(Array)
12
- type.valid_input?(ast_value)
13
- elsif type.kind.enum? && ast_value.is_a?(GraphQL::Language::Nodes::Enum)
14
- type.valid_input?(ast_value.name)
15
- elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
16
- required_input_fields_are_present(type, ast_value) &&
17
- present_input_field_values_are_valid(type, ast_value)
39
+ results = ensure_array(ast_value).map { |val| recursively_validate(val, item_type) }
40
+ merge_results(results)
18
41
  elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
19
- true
42
+ @valid_response
43
+ elsif type.kind.scalar? && constant_scalar?(ast_value)
44
+ maybe_raise_if_invalid(ast_value) do
45
+ type.validate_input(ast_value, @context)
46
+ end
47
+ elsif type.kind.enum?
48
+ maybe_raise_if_invalid(ast_value) do
49
+ if ast_value.is_a?(GraphQL::Language::Nodes::Enum)
50
+ type.validate_input(ast_value.name, @context)
51
+ else
52
+ # if our ast_value isn't an Enum it's going to be invalid so return false
53
+ @invalid_response
54
+ end
55
+ end
56
+ elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
57
+ maybe_raise_if_invalid(ast_value) do
58
+ merge_results([
59
+ required_input_fields_are_present(type, ast_value),
60
+ present_input_field_values_are_valid(type, ast_value)
61
+ ])
62
+ end
20
63
  else
21
- false
64
+ maybe_raise_if_invalid(ast_value) do
65
+ @invalid_response
66
+ end
22
67
  end
23
68
  end
24
69
 
70
+ # When `error_bubbling` is false, we want to bail on the first failure that we find.
71
+ # Use `throw` to escape the current call stack, returning the invalid response.
72
+ def maybe_raise_if_invalid(ast_value)
73
+ ret = yield
74
+ if !@context.schema.error_bubbling && !ret.valid?
75
+ throw(:invalid, ret)
76
+ else
77
+ ret
78
+ end
79
+ end
25
80
 
26
- private
27
-
81
+ # The GraphQL grammar supports variables embedded within scalars but graphql.js
82
+ # doesn't support it so we won't either for simplicity
83
+ def constant_scalar?(ast_value)
84
+ if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
85
+ false
86
+ elsif ast_value.is_a?(Array)
87
+ ast_value.all? { |element| constant_scalar?(element) }
88
+ elsif ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
89
+ ast_value.arguments.all? { |arg| constant_scalar?(arg.value) }
90
+ else
91
+ true
92
+ end
93
+ end
28
94
 
29
95
  def required_input_fields_are_present(type, ast_node)
30
- required_field_names = type.input_fields
31
- .values
32
- .select { |f| f.type.kind.non_null? }
96
+ # TODO - would be nice to use these to create an error message so the caller knows
97
+ # that required fields are missing
98
+ required_field_names = @warden.arguments(type)
99
+ .select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
33
100
  .map(&:name)
101
+
34
102
  present_field_names = ast_node.arguments.map(&:name)
35
103
  missing_required_field_names = required_field_names - present_field_names
36
- missing_required_field_names.none?
104
+ if @context.schema.error_bubbling
105
+ missing_required_field_names.empty? ? @valid_response : @invalid_response
106
+ else
107
+ results = missing_required_field_names.map do |name|
108
+ arg_type = @warden.get_argument(type, name).type
109
+ recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
110
+ end
111
+
112
+ if type.one_of? && ast_node.arguments.size != 1
113
+ results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
114
+ end
115
+ merge_results(results)
116
+ end
37
117
  end
38
118
 
39
119
  def present_input_field_values_are_valid(type, ast_node)
40
- fields = type.input_fields
41
- ast_node.arguments.all? do |value|
42
- field = fields[value.name]
43
- field ? validate(value.value, field.type) : true
120
+ results = ast_node.arguments.map do |value|
121
+ field = @warden.get_argument(type, value.name)
122
+ # we want to call validate on an argument even if it's an invalid one
123
+ # so that our raise exception is on it instead of the entire InputObject
124
+ field_type = field && field.type
125
+ recursively_validate(value.value, field_type)
44
126
  end
127
+ merge_results(results)
45
128
  end
46
129
 
47
130
  def ensure_array(value)
48
131
  value.is_a?(Array) ? value : [value]
49
132
  end
133
+
134
+ def merge_results(results_list)
135
+ merged_result = Query::InputValidationResult.new
136
+ results_list.each do |inner_result|
137
+ merged_result.merge_result!([], inner_result)
138
+ end
139
+ merged_result
140
+ end
50
141
  end
51
142
  end
52
143
  end