graphql 2.0.13 → 2.3.10

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/relay.rb +18 -1
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_object.erb +2 -0
  17. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +8 -0
  26. data/lib/graphql/analysis/analyzer.rb +89 -0
  27. data/lib/graphql/analysis/field_usage.rb +82 -0
  28. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  29. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  30. data/lib/graphql/analysis/query_complexity.rb +183 -0
  31. data/lib/graphql/analysis/query_depth.rb +58 -0
  32. data/lib/graphql/analysis/visitor.rb +283 -0
  33. data/lib/graphql/analysis.rb +92 -1
  34. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  35. data/lib/graphql/backtrace/table.rb +2 -2
  36. data/lib/graphql/backtrace/trace.rb +93 -0
  37. data/lib/graphql/backtrace/tracer.rb +1 -1
  38. data/lib/graphql/backtrace.rb +2 -1
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/request.rb +5 -0
  43. data/lib/graphql/dataloader/source.rb +89 -45
  44. data/lib/graphql/dataloader.rb +115 -142
  45. data/lib/graphql/duration_encoding_error.rb +16 -0
  46. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  47. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  48. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
  49. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  50. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +331 -455
  52. data/lib/graphql/execution/interpreter.rb +125 -61
  53. data/lib/graphql/execution/lazy.rb +6 -12
  54. data/lib/graphql/execution/lookahead.rb +124 -46
  55. data/lib/graphql/execution/multiplex.rb +3 -117
  56. data/lib/graphql/execution.rb +0 -1
  57. data/lib/graphql/introspection/directive_type.rb +3 -3
  58. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  59. data/lib/graphql/introspection/entry_points.rb +11 -5
  60. data/lib/graphql/introspection/field_type.rb +2 -2
  61. data/lib/graphql/introspection/schema_type.rb +10 -13
  62. data/lib/graphql/introspection/type_type.rb +17 -10
  63. data/lib/graphql/introspection.rb +3 -2
  64. data/lib/graphql/language/block_string.rb +34 -18
  65. data/lib/graphql/language/definition_slice.rb +1 -1
  66. data/lib/graphql/language/document_from_schema_definition.rb +75 -59
  67. data/lib/graphql/language/lexer.rb +358 -1506
  68. data/lib/graphql/language/nodes.rb +166 -93
  69. data/lib/graphql/language/parser.rb +795 -1953
  70. data/lib/graphql/language/printer.rb +340 -160
  71. data/lib/graphql/language/sanitized_printer.rb +21 -23
  72. data/lib/graphql/language/static_visitor.rb +167 -0
  73. data/lib/graphql/language/visitor.rb +188 -141
  74. data/lib/graphql/language.rb +61 -1
  75. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  76. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  77. data/lib/graphql/pagination/array_connection.rb +6 -6
  78. data/lib/graphql/pagination/connection.rb +33 -6
  79. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  80. data/lib/graphql/query/context/scoped_context.rb +101 -0
  81. data/lib/graphql/query/context.rb +117 -112
  82. data/lib/graphql/query/null_context.rb +12 -25
  83. data/lib/graphql/query/validation_pipeline.rb +6 -5
  84. data/lib/graphql/query/variables.rb +3 -3
  85. data/lib/graphql/query.rb +86 -30
  86. data/lib/graphql/railtie.rb +9 -6
  87. data/lib/graphql/rake_task.rb +29 -11
  88. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  89. data/lib/graphql/schema/addition.rb +59 -23
  90. data/lib/graphql/schema/always_visible.rb +11 -0
  91. data/lib/graphql/schema/argument.rb +55 -26
  92. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  93. data/lib/graphql/schema/build_from_definition.rb +56 -32
  94. data/lib/graphql/schema/directive/one_of.rb +24 -0
  95. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  96. data/lib/graphql/schema/directive/transform.rb +1 -1
  97. data/lib/graphql/schema/directive.rb +15 -3
  98. data/lib/graphql/schema/enum.rb +35 -24
  99. data/lib/graphql/schema/enum_value.rb +2 -3
  100. data/lib/graphql/schema/field/connection_extension.rb +2 -16
  101. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  102. data/lib/graphql/schema/field.rb +147 -107
  103. data/lib/graphql/schema/field_extension.rb +1 -4
  104. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  105. data/lib/graphql/schema/has_single_input_argument.rb +158 -0
  106. data/lib/graphql/schema/input_object.rb +47 -11
  107. data/lib/graphql/schema/interface.rb +15 -21
  108. data/lib/graphql/schema/introspection_system.rb +7 -17
  109. data/lib/graphql/schema/late_bound_type.rb +10 -0
  110. data/lib/graphql/schema/list.rb +2 -2
  111. data/lib/graphql/schema/loader.rb +2 -3
  112. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
  113. data/lib/graphql/schema/member/build_type.rb +11 -3
  114. data/lib/graphql/schema/member/has_arguments.rb +170 -130
  115. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  116. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  117. data/lib/graphql/schema/member/has_directives.rb +81 -61
  118. data/lib/graphql/schema/member/has_fields.rb +100 -38
  119. data/lib/graphql/schema/member/has_interfaces.rb +65 -10
  120. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  121. data/lib/graphql/schema/member/has_validators.rb +32 -6
  122. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  123. data/lib/graphql/schema/member/scoped.rb +19 -0
  124. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  125. data/lib/graphql/schema/member/validates_input.rb +3 -3
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +16 -5
  128. data/lib/graphql/schema/printer.rb +11 -8
  129. data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
  130. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  131. data/lib/graphql/schema/resolver.rb +47 -32
  132. data/lib/graphql/schema/scalar.rb +3 -3
  133. data/lib/graphql/schema/subscription.rb +11 -4
  134. data/lib/graphql/schema/subset.rb +397 -0
  135. data/lib/graphql/schema/timeout.rb +25 -29
  136. data/lib/graphql/schema/type_expression.rb +2 -2
  137. data/lib/graphql/schema/type_membership.rb +3 -0
  138. data/lib/graphql/schema/union.rb +11 -2
  139. data/lib/graphql/schema/unique_within_type.rb +1 -1
  140. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  141. data/lib/graphql/schema/validator.rb +4 -2
  142. data/lib/graphql/schema/warden.rb +238 -93
  143. data/lib/graphql/schema.rb +498 -103
  144. data/lib/graphql/static_validation/all_rules.rb +2 -1
  145. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  146. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  147. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  148. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  149. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  150. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  151. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  152. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  153. data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
  154. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  155. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  156. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  158. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  159. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  160. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  161. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  163. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  164. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  165. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  166. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  167. data/lib/graphql/static_validation/validation_context.rb +5 -5
  168. data/lib/graphql/static_validation/validator.rb +4 -1
  169. data/lib/graphql/static_validation.rb +0 -1
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
  171. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  172. data/lib/graphql/subscriptions/event.rb +11 -10
  173. data/lib/graphql/subscriptions/serialize.rb +2 -0
  174. data/lib/graphql/subscriptions.rb +20 -13
  175. data/lib/graphql/testing/helpers.rb +151 -0
  176. data/lib/graphql/testing.rb +2 -0
  177. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  178. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  179. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  180. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  181. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  182. data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
  183. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  184. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  185. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  186. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  187. data/lib/graphql/tracing/platform_trace.rb +118 -0
  188. data/lib/graphql/tracing/platform_tracing.rb +17 -3
  189. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  190. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  191. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  192. data/lib/graphql/tracing/scout_trace.rb +72 -0
  193. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  194. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  195. data/lib/graphql/tracing/trace.rb +76 -0
  196. data/lib/graphql/tracing.rb +20 -40
  197. data/lib/graphql/type_kinds.rb +7 -4
  198. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  199. data/lib/graphql/types/relay/base_connection.rb +1 -1
  200. data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
  201. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  202. data/lib/graphql/types/relay/node_behaviors.rb +8 -2
  203. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  204. data/lib/graphql/types/relay.rb +0 -1
  205. data/lib/graphql/types/string.rb +1 -1
  206. data/lib/graphql/types.rb +1 -0
  207. data/lib/graphql/version.rb +1 -1
  208. data/lib/graphql.rb +27 -20
  209. data/readme.md +13 -3
  210. metadata +96 -47
  211. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  212. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  213. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  214. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  215. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  216. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  217. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  218. data/lib/graphql/analysis/ast.rb +0 -81
  219. data/lib/graphql/deprecation.rb +0 -9
  220. data/lib/graphql/filter.rb +0 -53
  221. data/lib/graphql/language/lexer.rl +0 -280
  222. data/lib/graphql/language/parser.y +0 -554
  223. data/lib/graphql/language/token.rb +0 -34
  224. data/lib/graphql/schema/base_64_bp.rb +0 -26
  225. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  226. data/lib/graphql/static_validation/type_stack.rb +0 -216
  227. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
  228. data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module StatsdTrace
6
+ include PlatformTrace
7
+
8
+ # @param statsd [Object] A statsd client
9
+ def initialize(statsd:, **rest)
10
+ @statsd = statsd
11
+ super(**rest)
12
+ end
13
+
14
+ {
15
+ 'lex' => "graphql.lex",
16
+ 'parse' => "graphql.parse",
17
+ 'validate' => "graphql.validate",
18
+ 'analyze_query' => "graphql.analyze_query",
19
+ 'analyze_multiplex' => "graphql.analyze_multiplex",
20
+ 'execute_multiplex' => "graphql.execute_multiplex",
21
+ 'execute_query' => "graphql.execute_query",
22
+ 'execute_query_lazy' => "graphql.execute_query_lazy",
23
+ }.each do |trace_method, platform_key|
24
+ module_eval <<-RUBY, __FILE__, __LINE__
25
+ def #{trace_method}(**data)
26
+ @statsd.time("#{platform_key}") do
27
+ super
28
+ end
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ def platform_execute_field(platform_key, &block)
34
+ @statsd.time(platform_key, &block)
35
+ end
36
+
37
+ def platform_authorized(key, &block)
38
+ @statsd.time(key, &block)
39
+ end
40
+
41
+ alias :platform_resolve_type :platform_authorized
42
+
43
+ def platform_field_key(field)
44
+ "graphql.#{field.path}"
45
+ end
46
+
47
+ def platform_authorized_key(type)
48
+ "graphql.authorized.#{type.graphql_name}"
49
+ end
50
+
51
+ def platform_resolve_type_key(type)
52
+ "graphql.resolve_type.#{type.graphql_name}"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Tracing
4
+ # This is the base class for a `trace` instance whose methods are called during query execution.
5
+ # "Trace modes" are subclasses of this with custom tracing modules mixed in.
6
+ #
7
+ # A trace module may implement any of the methods on `Trace`, being sure to call `super`
8
+ # to continue any tracing hooks and call the actual runtime behavior. See {GraphQL::Backtrace::Trace} for example.
9
+ #
10
+ class Trace
11
+ # @param multiplex [GraphQL::Execution::Multiplex, nil]
12
+ # @param query [GraphQL::Query, nil]
13
+ def initialize(multiplex: nil, query: nil, **_options)
14
+ @multiplex = multiplex
15
+ @query = query
16
+ end
17
+
18
+ # The Ruby parser doesn't call this method (`graphql/c_parser` does.)
19
+ def lex(query_string:)
20
+ yield
21
+ end
22
+
23
+ def parse(query_string:)
24
+ yield
25
+ end
26
+
27
+ def validate(query:, validate:)
28
+ yield
29
+ end
30
+
31
+ def analyze_multiplex(multiplex:)
32
+ yield
33
+ end
34
+
35
+ def analyze_query(query:)
36
+ yield
37
+ end
38
+
39
+ def execute_multiplex(multiplex:)
40
+ yield
41
+ end
42
+
43
+ def execute_query(query:)
44
+ yield
45
+ end
46
+
47
+ def execute_query_lazy(query:, multiplex:)
48
+ yield
49
+ end
50
+
51
+ def execute_field(field:, query:, ast_node:, arguments:, object:)
52
+ yield
53
+ end
54
+
55
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
56
+ yield
57
+ end
58
+
59
+ def authorized(query:, type:, object:)
60
+ yield
61
+ end
62
+
63
+ def authorized_lazy(query:, type:, object:)
64
+ yield
65
+ end
66
+
67
+ def resolve_type(query:, type:, object:)
68
+ yield
69
+ end
70
+
71
+ def resolve_type_lazy(query:, type:, object:)
72
+ yield
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,4 +1,9 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/tracing/trace"
3
+ require "graphql/tracing/legacy_trace"
4
+ require "graphql/tracing/legacy_hooks_trace"
5
+
6
+ # Legacy tracing:
2
7
  require "graphql/tracing/active_support_notifications_tracing"
3
8
  require "graphql/tracing/platform_tracing"
4
9
  require "graphql/tracing/appoptics_tracing"
@@ -9,51 +14,26 @@ require "graphql/tracing/scout_tracing"
9
14
  require "graphql/tracing/statsd_tracing"
10
15
  require "graphql/tracing/prometheus_tracing"
11
16
 
17
+ # New Tracing:
18
+ require "graphql/tracing/active_support_notifications_trace"
19
+ require "graphql/tracing/platform_trace"
20
+ require "graphql/tracing/appoptics_trace"
21
+ require "graphql/tracing/appsignal_trace"
22
+ require "graphql/tracing/data_dog_trace"
23
+ require "graphql/tracing/new_relic_trace"
24
+ require "graphql/tracing/notifications_trace"
25
+ require "graphql/tracing/sentry_trace"
26
+ require "graphql/tracing/scout_trace"
27
+ require "graphql/tracing/statsd_trace"
28
+ require "graphql/tracing/prometheus_trace"
12
29
  if defined?(PrometheusExporter::Server)
13
- require "graphql/tracing/prometheus_tracing/graphql_collector"
30
+ require "graphql/tracing/prometheus_trace/graphql_collector"
14
31
  end
15
32
 
16
33
  module GraphQL
17
- # Library entry point for performance metric reporting.
18
- #
19
- # @example Sending custom events
20
- # query.trace("my_custom_event", { ... }) do
21
- # # do stuff ...
22
- # end
23
- #
24
- # @example Adding a tracer to a schema
25
- # class MySchema < GraphQL::Schema
26
- # tracer MyTracer # <= responds to .trace(key, data, &block)
27
- # end
28
- #
29
- # @example Adding a tracer to a single query
30
- # MySchema.execute(query_str, context: { backtrace: true })
31
- #
32
- # Events:
33
- #
34
- # Key | Metadata
35
- # ----|---------
36
- # lex | `{ query_string: String }`
37
- # parse | `{ query_string: String }`
38
- # validate | `{ query: GraphQL::Query, validate: Boolean }`
39
- # analyze_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
40
- # analyze_query | `{ query: GraphQL::Query }`
41
- # execute_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
42
- # execute_query | `{ query: GraphQL::Query }`
43
- # execute_query_lazy | `{ query: GraphQL::Query?, multiplex: GraphQL::Execution::Multiplex? }`
44
- # execute_field | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
45
- # execute_field_lazy | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
46
- # authorized | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
47
- # authorized_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
48
- # resolve_type | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
49
- # resolve_type_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
50
- #
51
- # Note that `execute_field` and `execute_field_lazy` receive different data in different settings:
52
- #
53
- # - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:, query:}`
54
- # - Otherwise, they receive `{context: ...}`
55
- #
56
34
  module Tracing
35
+ NullTrace = Trace.new
36
+
57
37
  # Objects may include traceable to gain a `.trace(...)` method.
58
38
  # The object must have a `@tracers` ivar of type `Array<<#trace(k, d, &b)>>`.
59
39
  # @api private
@@ -5,17 +5,18 @@ module GraphQL
5
5
  # These objects are singletons, eg `GraphQL::TypeKinds::UNION`, `GraphQL::TypeKinds::SCALAR`.
6
6
  class TypeKind
7
7
  attr_reader :name, :description
8
- def initialize(name, abstract: false, fields: false, wraps: false, input: false, description: nil)
8
+ def initialize(name, abstract: false, leaf: false, fields: false, wraps: false, input: false, description: nil)
9
9
  @name = name
10
10
  @abstract = abstract
11
11
  @fields = fields
12
12
  @wraps = wraps
13
13
  @input = input
14
+ @leaf = leaf
14
15
  @composite = fields? || abstract?
15
16
  @description = description
16
17
  end
17
18
 
18
- # Does this TypeKind have multiple possible implementors?
19
+ # Does this TypeKind have multiple possible implementers?
19
20
  # @deprecated Use `abstract?` instead of `resolves?`.
20
21
  def resolves?; @abstract; end
21
22
  # Is this TypeKind abstract?
@@ -27,6 +28,8 @@ module GraphQL
27
28
  # Is this TypeKind a valid query input?
28
29
  def input?; @input; end
29
30
  def to_s; @name; end
31
+ # Is this TypeKind a primitive value?
32
+ def leaf?; @leaf; end
30
33
  # Is this TypeKind composed of many values?
31
34
  def composite?; @composite; end
32
35
 
@@ -64,11 +67,11 @@ module GraphQL
64
67
  end
65
68
 
66
69
  TYPE_KINDS = [
67
- SCALAR = TypeKind.new("SCALAR", input: true, description: 'Indicates this type is a scalar.'),
70
+ SCALAR = TypeKind.new("SCALAR", input: true, leaf: true, description: 'Indicates this type is a scalar.'),
68
71
  OBJECT = TypeKind.new("OBJECT", fields: true, description: 'Indicates this type is an object. `fields` and `interfaces` are valid fields.'),
69
72
  INTERFACE = TypeKind.new("INTERFACE", abstract: true, fields: true, description: 'Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.'),
70
73
  UNION = TypeKind.new("UNION", abstract: true, description: 'Indicates this type is a union. `possibleTypes` is a valid field.'),
71
- ENUM = TypeKind.new("ENUM", input: true, description: 'Indicates this type is an enum. `enumValues` is a valid field.'),
74
+ ENUM = TypeKind.new("ENUM", input: true, leaf: true, description: 'Indicates this type is an enum. `enumValues` is a valid field.'),
72
75
  INPUT_OBJECT = TypeKind.new("INPUT_OBJECT", input: true, description: 'Indicates this type is an input object. `inputFields` is a valid field.'),
73
76
  LIST = TypeKind.new("LIST", wraps: true, description: 'Indicates this type is a list. `ofType` is a valid field.'),
74
77
  NON_NULL = TypeKind.new("NON_NULL", wraps: true, description: 'Indicates this type is a non-null. `ofType` is a valid field.'),
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Types
4
+ # This scalar takes `Duration`s and transmits them as strings,
5
+ # using ISO 8601 format. ActiveSupport >= 5.0 must be loaded to use
6
+ # this scalar.
7
+ #
8
+ # Use it for fields or arguments as follows:
9
+ #
10
+ # field :age, GraphQL::Types::ISO8601Duration, null: false
11
+ #
12
+ # argument :interval, GraphQL::Types::ISO8601Duration, null: false
13
+ #
14
+ # Alternatively, use this built-in scalar as inspiration for your
15
+ # own Duration type.
16
+ class ISO8601Duration < GraphQL::Schema::Scalar
17
+ description "An ISO 8601-encoded duration"
18
+
19
+ # @return [Integer, nil]
20
+ def self.seconds_precision
21
+ # ActiveSupport::Duration precision defaults to whatever input was given
22
+ @seconds_precision
23
+ end
24
+
25
+ # @param [Integer, nil] value
26
+ def self.seconds_precision=(value)
27
+ @seconds_precision = value
28
+ end
29
+
30
+ # @param value [ActiveSupport::Duration, String]
31
+ # @return [String]
32
+ # @raise [GraphQL::Error] if ActiveSupport::Duration is not defined or if an incompatible object is passed
33
+ def self.coerce_result(value, _ctx)
34
+ unless defined?(ActiveSupport::Duration)
35
+ raise GraphQL::Error, "ActiveSupport >= 5.0 must be loaded to use the built-in ISO8601Duration type."
36
+ end
37
+
38
+ begin
39
+ case value
40
+ when ActiveSupport::Duration
41
+ value.iso8601(precision: seconds_precision)
42
+ when ::String
43
+ ActiveSupport::Duration.parse(value).iso8601(precision: seconds_precision)
44
+ else
45
+ # Try calling as ActiveSupport::Duration compatible as a fallback
46
+ value.iso8601(precision: seconds_precision)
47
+ end
48
+ rescue StandardError => error
49
+ raise GraphQL::Error, "An incompatible object (#{value.class}) was given to #{self}. Make sure that only ActiveSupport::Durations and well-formatted Strings are used with this type. (#{error.message})"
50
+ end
51
+ end
52
+
53
+ # @param value [String, ActiveSupport::Duration]
54
+ # @return [ActiveSupport::Duration, nil]
55
+ # @raise [GraphQL::Error] if ActiveSupport::Duration is not defined
56
+ # @raise [GraphQL::DurationEncodingError] if duration cannot be parsed
57
+ def self.coerce_input(value, ctx)
58
+ unless defined?(ActiveSupport::Duration)
59
+ raise GraphQL::Error, "ActiveSupport >= 5.0 must be loaded to use the built-in ISO8601Duration type."
60
+ end
61
+
62
+ begin
63
+ if value.is_a?(ActiveSupport::Duration)
64
+ value
65
+ elsif value.nil?
66
+ nil
67
+ else
68
+ ActiveSupport::Duration.parse(value)
69
+ end
70
+ rescue ArgumentError, TypeError
71
+ err = GraphQL::DurationEncodingError.new(value)
72
+ ctx.schema.type_error(err, ctx)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -35,7 +35,7 @@ module GraphQL
35
35
  # # Alternatively, you can call the class methods followed by your edge type
36
36
  # # edges_nullable true
37
37
  # # edge_nullable true
38
- # # nodes_nullable true
38
+ # # node_nullable true
39
39
  # # has_nodes_field true
40
40
  # # edge_type Types::PostEdge
41
41
  # end
@@ -9,16 +9,44 @@ module GraphQL
9
9
 
10
10
  def self.included(child_class)
11
11
  child_class.extend(ClassMethods)
12
- child_class.extend(Relay::DefaultRelay)
13
- child_class.default_relay(true)
14
12
  child_class.has_nodes_field(true)
15
13
  child_class.node_nullable(true)
16
14
  child_class.edges_nullable(true)
17
15
  child_class.edge_nullable(true)
16
+ child_class.module_eval {
17
+ self.edge_type = nil
18
+ self.node_type = nil
19
+ self.edge_class = nil
20
+ }
21
+ child_class.default_broadcastable(nil)
18
22
  add_page_info_field(child_class)
19
23
  end
20
24
 
21
25
  module ClassMethods
26
+ def inherited(child_class)
27
+ super
28
+ child_class.has_nodes_field(has_nodes_field)
29
+ child_class.node_nullable(node_nullable)
30
+ child_class.edges_nullable(edges_nullable)
31
+ child_class.edge_nullable(edge_nullable)
32
+ child_class.edge_type = nil
33
+ child_class.node_type = nil
34
+ child_class.edge_class = nil
35
+ child_class.default_broadcastable(default_broadcastable?)
36
+ end
37
+
38
+ def default_relay?
39
+ true
40
+ end
41
+
42
+ def default_broadcastable?
43
+ @default_broadcastable
44
+ end
45
+
46
+ def default_broadcastable(new_value)
47
+ @default_broadcastable = new_value
48
+ end
49
+
22
50
  # @return [Class]
23
51
  attr_reader :node_type
24
52
 
@@ -49,6 +77,7 @@ module GraphQL
49
77
  type: [edge_type_class, null: edge_nullable],
50
78
  null: edges_nullable,
51
79
  description: "A list of edges.",
80
+ scope: false, # Assume that the connection was already scoped.
52
81
  connection: false,
53
82
  }
54
83
 
@@ -68,6 +97,19 @@ module GraphQL
68
97
  node_type.scope_items(items, context)
69
98
  end
70
99
 
100
+ # The connection will skip auth on its nodes if the node_type is configured for that
101
+ def reauthorize_scoped_objects(new_value = nil)
102
+ if new_value.nil?
103
+ if @reauthorize_scoped_objects != nil
104
+ @reauthorize_scoped_objects
105
+ else
106
+ node_type.reauthorize_scoped_objects
107
+ end
108
+ else
109
+ @reauthorize_scoped_objects = new_value
110
+ end
111
+ end
112
+
71
113
  # Add the shortcut `nodes` field to this connection and its subclasses
72
114
  def nodes_field(node_nullable: self.node_nullable, field_options: nil)
73
115
  define_nodes_field(node_nullable, field_options: field_options)
@@ -77,10 +119,6 @@ module GraphQL
77
119
  true # Let nodes be filtered out
78
120
  end
79
121
 
80
- def accessible?(ctx)
81
- node_type.accessible?(ctx)
82
- end
83
-
84
122
  def visible?(ctx)
85
123
  # if this is an abstract base class, there may be no `node_type`
86
124
  node_type ? node_type.visible?(ctx) : super
@@ -126,6 +164,10 @@ module GraphQL
126
164
  end
127
165
  end
128
166
 
167
+ protected
168
+
169
+ attr_writer :edge_type, :node_type, :edge_class
170
+
129
171
  private
130
172
 
131
173
  def define_nodes_field(nullable, field_options: nil)
@@ -135,6 +177,8 @@ module GraphQL
135
177
  null: nullable,
136
178
  description: "A list of nodes.",
137
179
  connection: false,
180
+ # Assume that the connection was scoped before this step:
181
+ scope: false,
138
182
  }
139
183
  if field_options
140
184
  base_field_options.merge!(field_options)
@@ -148,6 +192,24 @@ module GraphQL
148
192
  obj_type.field :page_info, GraphQL::Types::Relay::PageInfo, null: false, description: "Information to aid in pagination."
149
193
  end
150
194
  end
195
+
196
+ def edges
197
+ # Assume that whatever authorization needed to happen
198
+ # already happened at the connection level.
199
+ current_runtime_state = Thread.current[:__graphql_runtime_info]
200
+ query_runtime_state = current_runtime_state[context.query]
201
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
202
+ @object.edges
203
+ end
204
+
205
+ def nodes
206
+ # Assume that whatever authorization needed to happen
207
+ # already happened at the connection level.
208
+ current_runtime_state = Thread.current[:__graphql_runtime_info]
209
+ query_runtime_state = current_runtime_state[context.query]
210
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
211
+ @object.nodes
212
+ end
151
213
  end
152
214
  end
153
215
  end
@@ -8,10 +8,38 @@ module GraphQL
8
8
  child_class.description("An edge in a connection.")
9
9
  child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
10
10
  child_class.extend(ClassMethods)
11
+ child_class.class_eval { self.node_type = nil }
11
12
  child_class.node_nullable(true)
13
+ child_class.default_broadcastable(nil)
14
+ end
15
+
16
+ def node
17
+ current_runtime_state = Thread.current[:__graphql_runtime_info]
18
+ query_runtime_state = current_runtime_state[context.query]
19
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
20
+ @object.node
12
21
  end
13
22
 
14
23
  module ClassMethods
24
+ def inherited(child_class)
25
+ super
26
+ child_class.node_type = nil
27
+ child_class.node_nullable = nil
28
+ child_class.default_broadcastable(default_broadcastable?)
29
+ end
30
+
31
+ def default_relay?
32
+ true
33
+ end
34
+
35
+ def default_broadcastable?
36
+ @default_broadcastable
37
+ end
38
+
39
+ def default_broadcastable(new_value)
40
+ @default_broadcastable = new_value
41
+ end
42
+
15
43
  # Get or set the Object type that this edge wraps.
16
44
  #
17
45
  # @param node_type [Class] A `Schema::Object` subclass
@@ -40,10 +68,6 @@ module GraphQL
40
68
  true
41
69
  end
42
70
 
43
- def accessible?(ctx)
44
- node_type.accessible?(ctx)
45
- end
46
-
47
71
  def visible?(ctx)
48
72
  node_type.visible?(ctx)
49
73
  end
@@ -52,11 +76,15 @@ module GraphQL
52
76
  # Use `node_nullable(false)` in your base class to make non-null `node` field.
53
77
  def node_nullable(new_value = nil)
54
78
  if new_value.nil?
55
- defined?(@node_nullable) ? @node_nullable : superclass.node_nullable
79
+ @node_nullable != nil ? @node_nullable : superclass.node_nullable
56
80
  else
57
81
  @node_nullable = new_value
58
82
  end
59
83
  end
84
+
85
+ protected
86
+
87
+ attr_writer :node_type, :node_nullable
60
88
  end
61
89
  end
62
90
  end
@@ -5,13 +5,19 @@ module GraphQL
5
5
  module Relay
6
6
  module NodeBehaviors
7
7
  def self.included(child_module)
8
- child_module.extend(DefaultRelay)
8
+ child_module.extend(ClassMethods)
9
9
  child_module.description("An object with an ID.")
10
10
  child_module.field(:id, ID, null: false, description: "ID of the object.", resolver_method: :default_global_id)
11
11
  end
12
12
 
13
13
  def default_global_id
14
- context.schema.id_from_object(object, self, context)
14
+ context.schema.id_from_object(object, self.class, context)
15
+ end
16
+
17
+ module ClassMethods
18
+ def default_relay?
19
+ true
20
+ end
15
21
  end
16
22
  end
17
23
  end
@@ -4,8 +4,7 @@ module GraphQL
4
4
  module Relay
5
5
  module PageInfoBehaviors
6
6
  def self.included(child_class)
7
- child_class.extend GraphQL::Types::Relay::DefaultRelay
8
-
7
+ child_class.extend ClassMethods
9
8
  child_class.description "Information about pagination in a connection."
10
9
  child_class.field :has_next_page, Boolean, null: false,
11
10
  description: "When paginating forwards, are there more items?"
@@ -20,6 +19,16 @@ module GraphQL
20
19
  description: "When paginating forwards, the cursor to continue."
21
20
  end
22
21
  end
22
+
23
+ module ClassMethods
24
+ def default_relay?
25
+ true
26
+ end
27
+
28
+ def default_broadcastable?
29
+ true
30
+ end
31
+ end
23
32
  end
24
33
  end
25
34
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # behavior modules:
4
- require "graphql/types/relay/default_relay"
5
4
  require "graphql/types/relay/connection_behaviors"
6
5
  require "graphql/types/relay/edge_behaviors"
7
6
  require "graphql/types/relay/node_behaviors"
@@ -7,7 +7,7 @@ module GraphQL
7
7
 
8
8
  def self.coerce_result(value, ctx)
9
9
  str = value.to_s
10
- if str.encoding == Encoding::UTF_8
10
+ if str.encoding == Encoding::UTF_8 || str.ascii_only?
11
11
  str
12
12
  elsif str.frozen?
13
13
  str.encode(Encoding::UTF_8)
data/lib/graphql/types.rb CHANGED
@@ -6,6 +6,7 @@ require "graphql/types/id"
6
6
  require "graphql/types/int"
7
7
  require "graphql/types/iso_8601_date"
8
8
  require "graphql/types/iso_8601_date_time"
9
+ require "graphql/types/iso_8601_duration"
9
10
  require "graphql/types/json"
10
11
  require "graphql/types/string"
11
12
  require "graphql/types/relay"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.0.13"
3
+ VERSION = "2.3.10"
4
4
  end