graphql 1.11.5 → 1.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +5 -5
  3. data/lib/generators/graphql/object_generator.rb +2 -0
  4. data/lib/generators/graphql/relay_generator.rb +63 -0
  5. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  6. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  7. data/lib/generators/graphql/templates/node_type.erb +9 -0
  8. data/lib/generators/graphql/templates/object.erb +1 -1
  9. data/lib/generators/graphql/templates/query_type.erb +1 -3
  10. data/lib/generators/graphql/templates/schema.erb +8 -35
  11. data/lib/graphql.rb +39 -4
  12. data/lib/graphql/analysis/analyze_query.rb +7 -0
  13. data/lib/graphql/analysis/ast.rb +11 -2
  14. data/lib/graphql/analysis/ast/visitor.rb +9 -1
  15. data/lib/graphql/backtrace.rb +28 -19
  16. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  17. data/lib/graphql/backtrace/table.rb +22 -2
  18. data/lib/graphql/backtrace/tracer.rb +40 -9
  19. data/lib/graphql/backwards_compatibility.rb +2 -1
  20. data/lib/graphql/base_type.rb +1 -1
  21. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  22. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  23. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  24. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  25. data/lib/graphql/dataloader.rb +198 -0
  26. data/lib/graphql/dataloader/null_dataloader.rb +21 -0
  27. data/lib/graphql/dataloader/request.rb +24 -0
  28. data/lib/graphql/dataloader/request_all.rb +22 -0
  29. data/lib/graphql/dataloader/source.rb +93 -0
  30. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  31. data/lib/graphql/define/instance_definable.rb +32 -2
  32. data/lib/graphql/define/type_definer.rb +5 -5
  33. data/lib/graphql/deprecated_dsl.rb +7 -2
  34. data/lib/graphql/deprecation.rb +13 -0
  35. data/lib/graphql/enum_type.rb +2 -0
  36. data/lib/graphql/execution/errors.rb +4 -0
  37. data/lib/graphql/execution/execute.rb +7 -0
  38. data/lib/graphql/execution/interpreter.rb +10 -6
  39. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  40. data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
  41. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  42. data/lib/graphql/execution/interpreter/runtime.rb +219 -117
  43. data/lib/graphql/execution/multiplex.rb +20 -6
  44. data/lib/graphql/function.rb +4 -0
  45. data/lib/graphql/input_object_type.rb +2 -0
  46. data/lib/graphql/integer_decoding_error.rb +17 -0
  47. data/lib/graphql/interface_type.rb +3 -1
  48. data/lib/graphql/internal_representation/document.rb +2 -2
  49. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  50. data/lib/graphql/invalid_null_error.rb +1 -1
  51. data/lib/graphql/language/document_from_schema_definition.rb +50 -23
  52. data/lib/graphql/object_type.rb +2 -0
  53. data/lib/graphql/pagination/connection.rb +5 -1
  54. data/lib/graphql/pagination/connections.rb +15 -19
  55. data/lib/graphql/query.rb +6 -1
  56. data/lib/graphql/query/arguments.rb +1 -1
  57. data/lib/graphql/query/context.rb +8 -1
  58. data/lib/graphql/query/serial_execution.rb +1 -0
  59. data/lib/graphql/query/validation_pipeline.rb +1 -1
  60. data/lib/graphql/relay/array_connection.rb +2 -2
  61. data/lib/graphql/relay/base_connection.rb +7 -0
  62. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  63. data/lib/graphql/relay/connection_type.rb +1 -1
  64. data/lib/graphql/relay/mutation.rb +1 -0
  65. data/lib/graphql/relay/node.rb +3 -0
  66. data/lib/graphql/relay/range_add.rb +14 -5
  67. data/lib/graphql/relay/type_extensions.rb +2 -0
  68. data/lib/graphql/scalar_type.rb +2 -0
  69. data/lib/graphql/schema.rb +80 -29
  70. data/lib/graphql/schema/argument.rb +25 -7
  71. data/lib/graphql/schema/build_from_definition.rb +150 -58
  72. data/lib/graphql/schema/default_type_error.rb +2 -0
  73. data/lib/graphql/schema/directive.rb +76 -0
  74. data/lib/graphql/schema/directive/flagged.rb +57 -0
  75. data/lib/graphql/schema/enum.rb +3 -0
  76. data/lib/graphql/schema/enum_value.rb +12 -6
  77. data/lib/graphql/schema/field.rb +52 -23
  78. data/lib/graphql/schema/field/connection_extension.rb +10 -8
  79. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  80. data/lib/graphql/schema/input_object.rb +33 -22
  81. data/lib/graphql/schema/interface.rb +1 -0
  82. data/lib/graphql/schema/member.rb +4 -0
  83. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
  84. data/lib/graphql/schema/member/build_type.rb +3 -3
  85. data/lib/graphql/schema/member/has_arguments.rb +67 -50
  86. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  87. data/lib/graphql/schema/member/has_directives.rb +98 -0
  88. data/lib/graphql/schema/member/has_fields.rb +2 -2
  89. data/lib/graphql/schema/member/has_validators.rb +31 -0
  90. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  91. data/lib/graphql/schema/middleware_chain.rb +1 -1
  92. data/lib/graphql/schema/object.rb +11 -0
  93. data/lib/graphql/schema/printer.rb +5 -4
  94. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  95. data/lib/graphql/schema/resolver.rb +7 -0
  96. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
  97. data/lib/graphql/schema/subscription.rb +19 -1
  98. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  99. data/lib/graphql/schema/unique_within_type.rb +1 -2
  100. data/lib/graphql/schema/validation.rb +4 -2
  101. data/lib/graphql/schema/validator.rb +163 -0
  102. data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
  103. data/lib/graphql/schema/validator/format_validator.rb +49 -0
  104. data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
  105. data/lib/graphql/schema/validator/length_validator.rb +57 -0
  106. data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
  107. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  108. data/lib/graphql/static_validation.rb +1 -0
  109. data/lib/graphql/static_validation/all_rules.rb +1 -0
  110. data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
  111. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  112. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  113. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  114. data/lib/graphql/static_validation/validator.rb +32 -9
  115. data/lib/graphql/subscriptions.rb +17 -20
  116. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  117. data/lib/graphql/tracing.rb +2 -2
  118. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  119. data/lib/graphql/tracing/platform_tracing.rb +4 -2
  120. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  121. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  122. data/lib/graphql/types/int.rb +9 -2
  123. data/lib/graphql/types/relay.rb +11 -3
  124. data/lib/graphql/types/relay/base_connection.rb +2 -91
  125. data/lib/graphql/types/relay/base_edge.rb +2 -34
  126. data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
  127. data/lib/graphql/types/relay/default_relay.rb +27 -0
  128. data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
  129. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  130. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  131. data/lib/graphql/types/relay/node.rb +2 -4
  132. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  133. data/lib/graphql/types/relay/node_field.rb +1 -19
  134. data/lib/graphql/types/relay/nodes_field.rb +1 -19
  135. data/lib/graphql/types/relay/page_info.rb +2 -14
  136. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  137. data/lib/graphql/types/string.rb +7 -1
  138. data/lib/graphql/unauthorized_error.rb +1 -1
  139. data/lib/graphql/union_type.rb +2 -0
  140. data/lib/graphql/upgrader/member.rb +1 -0
  141. data/lib/graphql/upgrader/schema.rb +1 -0
  142. data/lib/graphql/version.rb +1 -1
  143. data/readme.md +1 -1
  144. metadata +50 -6
  145. data/lib/graphql/types/relay/base_field.rb +0 -22
  146. data/lib/graphql/types/relay/base_interface.rb +0 -29
  147. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -4,8 +4,11 @@ require 'graphql/schema/member/base_dsl_methods'
4
4
  require 'graphql/schema/member/cached_graphql_definition'
5
5
  require 'graphql/schema/member/graphql_type_names'
6
6
  require 'graphql/schema/member/has_ast_node'
7
+ require 'graphql/schema/member/has_directives'
8
+ require 'graphql/schema/member/has_deprecation_reason'
7
9
  require 'graphql/schema/member/has_path'
8
10
  require 'graphql/schema/member/has_unresolved_type_error'
11
+ require 'graphql/schema/member/has_validators'
9
12
  require 'graphql/schema/member/relay_shortcuts'
10
13
  require 'graphql/schema/member/scoped'
11
14
  require 'graphql/schema/member/type_system_helpers'
@@ -30,6 +33,7 @@ module GraphQL
30
33
  extend RelayShortcuts
31
34
  extend HasPath
32
35
  extend HasAstNode
36
+ extend HasDirectives
33
37
  end
34
38
  end
35
39
  end
@@ -19,6 +19,7 @@ module GraphQL
19
19
  # @return [String]
20
20
  def graphql_name(new_name = nil)
21
21
  if new_name
22
+ GraphQL::NameValidator.validate!(new_name)
22
23
  @graphql_name = new_name
23
24
  else
24
25
  overridden_graphql_name || default_graphql_name
@@ -60,11 +60,11 @@ module GraphQL
60
60
  parse_type(type_expr.first, null: false)
61
61
  when 2
62
62
  inner_type, nullable_option = type_expr
63
- if nullable_option.keys != [:null] || nullable_option.values != [true]
63
+ if nullable_option.keys != [:null] || (nullable_option[:null] != true && nullable_option[:null] != false)
64
64
  raise ArgumentError, LIST_TYPE_ERROR
65
65
  end
66
66
  list_type = true
67
- parse_type(inner_type, null: true)
67
+ parse_type(inner_type, null: nullable_option[:null])
68
68
  else
69
69
  raise ArgumentError, LIST_TYPE_ERROR
70
70
  end
@@ -75,7 +75,7 @@ module GraphQL
75
75
  if type_expr.respond_to?(:graphql_definition)
76
76
  type_expr
77
77
  else
78
- # Eg `String` => GraphQL::STRING_TYPE
78
+ # Eg `String` => GraphQL::Types::String
79
79
  parse_type(type_expr.name, null: true)
80
80
  end
81
81
  when Proc
@@ -85,70 +85,87 @@ module GraphQL
85
85
  # @param context [GraphQL::Query::Context]
86
86
  # @return [Hash<Symbol, Object>, Execution::Lazy<Hash>]
87
87
  def coerce_arguments(parent_object, values, context)
88
- argument_values = {}
89
- kwarg_arguments = {}
90
88
  # Cache this hash to avoid re-merging it
91
89
  arg_defns = self.arguments
92
90
 
93
- maybe_lazies = []
94
- arg_lazies = arg_defns.map do |arg_name, arg_defn|
95
- arg_key = arg_defn.keyword
96
- has_value = false
97
- default_used = false
98
- if values.key?(arg_name)
99
- has_value = true
100
- value = values[arg_name]
101
- elsif values.key?(arg_key)
102
- has_value = true
103
- value = values[arg_key]
104
- elsif arg_defn.default_value?
105
- has_value = true
106
- value = arg_defn.default_value
107
- default_used = true
108
- end
109
-
110
- if has_value
111
- loads = arg_defn.loads
112
- loaded_value = nil
113
- if loads && !arg_defn.from_resolver?
114
- loaded_value = if arg_defn.type.list?
115
- loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, context) }
116
- context.schema.after_any_lazies(loaded_values) { |result| result }
117
- else
118
- load_application_object(arg_defn, loads, value, context)
119
- end
91
+ if arg_defns.empty?
92
+ GraphQL::Execution::Interpreter::Arguments::EMPTY
93
+ else
94
+ argument_values = {}
95
+ arg_lazies = arg_defns.map do |arg_name, arg_defn|
96
+ arg_key = arg_defn.keyword
97
+ has_value = false
98
+ default_used = false
99
+ if values.key?(arg_name)
100
+ has_value = true
101
+ value = values[arg_name]
102
+ elsif values.key?(arg_key)
103
+ has_value = true
104
+ value = values[arg_key]
105
+ elsif arg_defn.default_value?
106
+ has_value = true
107
+ value = arg_defn.default_value
108
+ default_used = true
120
109
  end
121
110
 
122
- coerced_value = if loaded_value
123
- loaded_value
124
- else
125
- context.schema.error_handler.with_error_handling(context) do
111
+ if has_value
112
+ loads = arg_defn.loads
113
+ loaded_value = nil
114
+ coerced_value = context.schema.error_handler.with_error_handling(context) do
126
115
  arg_defn.type.coerce_input(value, context)
127
116
  end
128
- end
129
117
 
130
- context.schema.after_lazy(coerced_value) do |coerced_value|
131
- prepared_value = context.schema.error_handler.with_error_handling(context) do
132
- arg_defn.prepare_value(parent_object, coerced_value, context: context)
118
+ # TODO this should probably be inside after_lazy
119
+ if loads && !arg_defn.from_resolver?
120
+ loaded_value = if arg_defn.type.list?
121
+ loaded_values = coerced_value.map { |val| load_application_object(arg_defn, loads, val, context) }
122
+ context.schema.after_any_lazies(loaded_values) { |result| result }
123
+ else
124
+ load_application_object(arg_defn, loads, coerced_value, context)
125
+ end
126
+ end
127
+
128
+ coerced_value = if loaded_value
129
+ loaded_value
130
+ else
131
+ coerced_value
133
132
  end
134
133
 
135
- kwarg_arguments[arg_key] = prepared_value
136
- # TODO code smell to access such a deeply-nested constant in a distant module
137
- argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
138
- value: prepared_value,
139
- definition: arg_defn,
140
- default_used: default_used,
141
- )
134
+ context.schema.after_lazy(coerced_value) do |coerced_value|
135
+ validate_directive_argument(arg_defn, coerced_value)
136
+ prepared_value = context.schema.error_handler.with_error_handling(context) do
137
+ arg_defn.prepare_value(parent_object, coerced_value, context: context)
138
+ end
139
+
140
+ # TODO code smell to access such a deeply-nested constant in a distant module
141
+ argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
142
+ value: prepared_value,
143
+ definition: arg_defn,
144
+ default_used: default_used,
145
+ )
146
+ end
147
+ else
148
+ # has_value is false
149
+ validate_directive_argument(arg_defn, nil)
142
150
  end
143
151
  end
152
+
153
+ context.schema.after_any_lazies(arg_lazies) do
154
+ GraphQL::Execution::Interpreter::Arguments.new(
155
+ argument_values: argument_values,
156
+ )
157
+ end
144
158
  end
159
+ end
145
160
 
146
- maybe_lazies.concat(arg_lazies)
147
- context.schema.after_any_lazies(maybe_lazies) do
148
- GraphQL::Execution::Interpreter::Arguments.new(
149
- keyword_arguments: kwarg_arguments,
150
- argument_values: argument_values,
151
- )
161
+ # Usually, this is validated statically by RequiredArgumentsArePresent,
162
+ # but not for directives.
163
+ # TODO apply static validations on schema definitions?
164
+ def validate_directive_argument(arg_defn, value)
165
+ if arg_defn.owner.is_a?(Class) && arg_defn.owner < GraphQL::Schema::Directive
166
+ if value.nil? && arg_defn.type.non_null?
167
+ raise ArgumentError, "#{arg_defn.path} is required, but no value was given"
168
+ end
152
169
  end
153
170
  end
154
171
 
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDeprecationReason
7
+ # @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
8
+ def deprecation_reason
9
+ dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
10
+ dir && dir.arguments[:reason]
11
+ end
12
+
13
+ # Set the deprecation reason for this member, or remove it by assigning `nil`
14
+ # @param text [String, nil]
15
+ def deprecation_reason=(text)
16
+ if text.nil?
17
+ remove_directive(GraphQL::Schema::Directive::Deprecated)
18
+ else
19
+ directive(GraphQL::Schema::Directive::Deprecated, reason: text)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ module HasDirectives
7
+ # Create an instance of `dir_class` for `self`, using `options`.
8
+ #
9
+ # It removes a previously-attached instance of `dir_class`, if there is one.
10
+ #
11
+ # @return [void]
12
+ def directive(dir_class, **options)
13
+ @own_directives ||= []
14
+ remove_directive(dir_class)
15
+ @own_directives << dir_class.new(self, **options)
16
+ nil
17
+ end
18
+
19
+ # Remove an attached instance of `dir_class`, if there is one
20
+ # @param dir_class [Class<GraphQL::Schema::Directive>]
21
+ # @return [viod]
22
+ def remove_directive(dir_class)
23
+ @own_directives && @own_directives.reject! { |d| d.is_a?(dir_class) }
24
+ nil
25
+ end
26
+
27
+ NO_DIRECTIVES = [].freeze
28
+
29
+ def directives
30
+ case self
31
+ when Class
32
+ inherited_directives = if superclass.respond_to?(:directives)
33
+ superclass.directives
34
+ else
35
+ NO_DIRECTIVES
36
+ end
37
+ if inherited_directives.any? && @own_directives
38
+ dirs = []
39
+ merge_directives(dirs, inherited_directives)
40
+ merge_directives(dirs, @own_directives)
41
+ dirs
42
+ elsif @own_directives
43
+ @own_directives
44
+ elsif inherited_directives.any?
45
+ inherited_directives
46
+ else
47
+ NO_DIRECTIVES
48
+ end
49
+ when Module
50
+ dirs = nil
51
+ self.ancestors.reverse_each do |ancestor|
52
+ if ancestor.respond_to?(:own_directives) &&
53
+ (anc_dirs = ancestor.own_directives).any?
54
+ dirs ||= []
55
+ merge_directives(dirs, anc_dirs)
56
+ end
57
+ end
58
+ if own_directives
59
+ dirs ||= []
60
+ merge_directives(dirs, own_directives)
61
+ end
62
+ dirs || NO_DIRECTIVES
63
+ when HasDirectives
64
+ @own_directives || NO_DIRECTIVES
65
+ else
66
+ raise "Invariant: how could #{self} not be a Class, Module, or instance of HasDirectives?"
67
+ end
68
+ end
69
+
70
+ protected
71
+
72
+ def own_directives
73
+ @own_directives
74
+ end
75
+
76
+ private
77
+
78
+ # Modify `target` by adding items from `dirs` such that:
79
+ # - Any name conflict is overriden by the incoming member of `dirs`
80
+ # - Any other member of `dirs` is appended
81
+ # @param target [Array<GraphQL::Schema::Directive>]
82
+ # @param dirs [Array<GraphQL::Schema::Directive>]
83
+ # @return [void]
84
+ def merge_directives(target, dirs)
85
+ dirs.each do |dir|
86
+ if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
87
+ target.slice!(idx)
88
+ target.insert(idx, dir)
89
+ else
90
+ target << dir
91
+ end
92
+ end
93
+ nil
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -82,9 +82,9 @@ module GraphQL
82
82
  end
83
83
  end
84
84
 
85
- def global_id_field(field_name)
85
+ def global_id_field(field_name, **kwargs)
86
86
  id_resolver = GraphQL::Relay::GlobalIdResolve.new(type: self)
87
- field field_name, "ID", null: false
87
+ field field_name, "ID", **kwargs, null: false
88
88
  define_method(field_name) do
89
89
  id_resolver.call(object, {}, context)
90
90
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Member
5
+ module HasValidators
6
+ include Schema::FindInheritedValue::EmptyObjects
7
+
8
+ # Build {GraphQL::Schema::Validator}s based on the given configuration
9
+ # and use them for this schema member
10
+ # @param validation_config [Hash{Symbol => Hash}]
11
+ # @return [void]
12
+ def validates(validation_config)
13
+ new_validators = GraphQL::Schema::Validator.from_config(self, validation_config)
14
+ @own_validators ||= []
15
+ @own_validators.concat(new_validators)
16
+ nil
17
+ end
18
+
19
+ # @return [Array<GraphQL::Schema::Validator>]
20
+ def validators
21
+ own_validators = @own_validators || EMPTY_ARRAY
22
+ if self.is_a?(Class) && superclass.respond_to?(:validators) && (inherited_validators = superclass.validators).any?
23
+ inherited_validators + own_validators
24
+ else
25
+ own_validators
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  # @return [GraphQL::TypeKinds::TypeKind]
32
32
  def kind
33
- raise GraphQL::RequiredImplementationMissingError
33
+ raise GraphQL::RequiredImplementationMissingError, "No `.kind` defined for #{self}"
34
34
  end
35
35
  end
36
36
  end
@@ -71,7 +71,7 @@ module GraphQL
71
71
 
72
72
  def wrap(callable)
73
73
  if BackwardsCompatibility.get_arity(callable) == 6
74
- warn("Middleware that takes a next_middleware parameter is deprecated (#{callable.inspect}); instead, accept a block and use yield.")
74
+ GraphQL::Deprecation.warn("Middleware that takes a next_middleware parameter is deprecated (#{callable.inspect}); instead, accept a block and use yield.")
75
75
  MiddlewareWrapper.new(callable)
76
76
  else
77
77
  callable
@@ -14,6 +14,17 @@ module GraphQL
14
14
  # @return [GraphQL::Query::Context] the context instance for this query
15
15
  attr_reader :context
16
16
 
17
+ # @return [GraphQL::Dataloader]
18
+ def dataloader
19
+ context.dataloader
20
+ end
21
+
22
+ # Call this in a field method to return a value that should be returned to the client
23
+ # without any further handling by GraphQL.
24
+ def raw_value(obj)
25
+ GraphQL::Execution::Interpreter::RawValue.new(obj)
26
+ end
27
+
17
28
  class << self
18
29
  # This is protected so that we can be sure callers use the public method, {.authorized_new}
19
30
  # @see authorized_new to make instances
@@ -59,14 +59,15 @@ module GraphQL
59
59
 
60
60
  # Return the GraphQL schema string for the introspection type system
61
61
  def self.print_introspection_schema
62
- query_root = ObjectType.define(name: "Root") do
63
- field :throwaway_field, types.String
62
+ query_root = Class.new(GraphQL::Schema::Object) do
63
+ graphql_name "Root"
64
+ field :throwaway_field, String, null: true
64
65
  end
65
- schema = GraphQL::Schema.define(query: query_root)
66
+ schema = Class.new(GraphQL::Schema) { query(query_root) }
66
67
 
67
68
  introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
68
69
  schema,
69
- except: ->(member, _) { member.name == "Root" },
70
+ except: ->(member, _) { member.graphql_name == "Root" },
70
71
  include_introspection_types: true,
71
72
  include_built_in_directives: true,
72
73
  ).document
@@ -105,7 +105,7 @@ module GraphQL
105
105
  sig = super
106
106
  # Arguments were added at the root, but they should be nested
107
107
  sig[:arguments].clear
108
- sig[:arguments][:input] = { type: input_type, required: true }
108
+ sig[:arguments][:input] = { type: input_type, required: true, description: "Parameters for #{graphql_name}" }
109
109
  sig
110
110
  end
111
111
 
@@ -24,6 +24,7 @@ module GraphQL
24
24
  # Really we only need description from here, but:
25
25
  extend Schema::Member::BaseDSLMethods
26
26
  extend GraphQL::Schema::Member::HasArguments
27
+ extend GraphQL::Schema::Member::HasValidators
27
28
  include Schema::Member::HasPath
28
29
  extend Schema::Member::HasPath
29
30
 
@@ -49,6 +50,11 @@ module GraphQL
49
50
  # @return [GraphQL::Query::Context]
50
51
  attr_reader :context
51
52
 
53
+ # @return [GraphQL::Dataloader]
54
+ def dataloader
55
+ context.dataloader
56
+ end
57
+
52
58
  # @return [GraphQL::Schema::Field]
53
59
  attr_reader :field
54
60
 
@@ -80,6 +86,7 @@ module GraphQL
80
86
  load_arguments_val = load_arguments(args)
81
87
  context.schema.after_lazy(load_arguments_val) do |loaded_args|
82
88
  @prepared_arguments = loaded_args
89
+ Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
83
90
  # Then call `authorized?`, which may raise or may return a lazy object
84
91
  authorized_val = if loaded_args.any?
85
92
  authorized?(**loaded_args)