graphql 1.9.17 → 1.11.7
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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/object_generator.rb +52 -8
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/analysis/ast.rb +12 -11
- data/lib/graphql/argument.rb +10 -38
- data/lib/graphql/backtrace/table.rb +10 -2
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +3 -3
- data/lib/graphql/define/defined_object_proxy.rb +3 -0
- data/lib/graphql/define/instance_definable.rb +18 -108
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/directive.rb +8 -1
- data/lib/graphql/enum_type.rb +5 -71
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +2 -3
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +227 -254
- data/lib/graphql/execution/interpreter.rb +34 -11
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +14 -5
- data/lib/graphql/field.rb +14 -118
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/function.rb +1 -30
- data/lib/graphql/input_object_type.rb +6 -24
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +7 -23
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +7 -7
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +33 -9
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -9
- data/lib/graphql/introspection/type_type.rb +11 -7
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +89 -64
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +52 -91
- data/lib/graphql/language/parser.rb +719 -717
- data/lib/graphql/language/parser.y +104 -98
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -1
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +45 -56
- data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +208 -0
- data/lib/graphql/pagination/connections.rb +145 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +185 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/query/arguments.rb +4 -2
- data/lib/graphql/query/context.rb +36 -9
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +30 -10
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +16 -7
- data/lib/graphql/query.rb +64 -15
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +23 -13
- data/lib/graphql/relay/connection_type.rb +2 -1
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -86
- data/lib/graphql/relay/node.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/scalar_type.rb +15 -59
- data/lib/graphql/schema/argument.rb +113 -11
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +212 -190
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive.rb +34 -3
- data/lib/graphql/schema/enum.rb +52 -4
- data/lib/graphql/schema/enum_value.rb +6 -1
- data/lib/graphql/schema/field/connection_extension.rb +44 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +200 -129
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +131 -22
- data/lib/graphql/schema/interface.rb +26 -8
- data/lib/graphql/schema/introspection_system.rb +108 -37
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +47 -0
- data/lib/graphql/schema/loader.rb +134 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
- data/lib/graphql/schema/member/build_type.rb +19 -5
- data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +105 -5
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_fields.rb +20 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +5 -1
- data/lib/graphql/schema/non_null.rb +30 -0
- data/lib/graphql/schema/object.rb +65 -12
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +0 -15
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
- data/lib/graphql/schema/resolver.rb +26 -18
- data/lib/graphql/schema/scalar.rb +27 -3
- data/lib/graphql/schema/subscription.rb +8 -18
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +2 -2
- data/lib/graphql/schema/union.rb +37 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -2
- data/lib/graphql/schema/warden.rb +115 -29
- data/lib/graphql/schema.rb +903 -195
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/literal_validator.rb +52 -27
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +30 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +23 -5
- data/lib/graphql/subscriptions/instrumentation.rb +10 -5
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +108 -35
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
- data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/platform_tracing.rb +53 -9
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +8 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +14 -34
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +11 -7
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +13 -28
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +31 -6
- data/readme.md +1 -1
- metadata +34 -9
- data/lib/graphql/literal_validation_error.rb +0 -6
@@ -5,43 +5,57 @@ module GraphQL
|
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
6
|
extend Forwardable
|
7
7
|
extend GraphQL::Schema::Member::HasArguments
|
8
|
+
extend GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader
|
9
|
+
extend GraphQL::Schema::Member::ValidatesInput
|
10
|
+
|
8
11
|
include GraphQL::Dig
|
9
12
|
|
10
|
-
def initialize(
|
13
|
+
def initialize(arguments = nil, ruby_kwargs: nil, context:, defaults_used:)
|
11
14
|
@context = context
|
12
15
|
if ruby_kwargs
|
13
16
|
@ruby_style_hash = ruby_kwargs
|
17
|
+
@arguments = arguments
|
14
18
|
else
|
15
|
-
@arguments = self.class.arguments_class.new(
|
19
|
+
@arguments = self.class.arguments_class.new(arguments, context: context, defaults_used: defaults_used)
|
16
20
|
# Symbolized, underscored hash:
|
17
21
|
@ruby_style_hash = @arguments.to_kwargs
|
18
22
|
end
|
19
23
|
# Apply prepares, not great to have it duplicated here.
|
20
|
-
|
21
|
-
self.class.arguments.
|
22
|
-
@arguments_by_keyword[arg_defn.keyword] = arg_defn
|
24
|
+
maybe_lazies = []
|
25
|
+
self.class.arguments.each_value do |arg_defn|
|
23
26
|
ruby_kwargs_key = arg_defn.keyword
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
|
28
|
+
if @ruby_style_hash.key?(ruby_kwargs_key)
|
29
|
+
loads = arg_defn.loads
|
30
|
+
# Resolvers do this loading themselves;
|
31
|
+
# With the interpreter, it's done during `coerce_arguments`
|
32
|
+
if loads && !arg_defn.from_resolver? && !context.interpreter?
|
33
|
+
value = @ruby_style_hash[ruby_kwargs_key]
|
34
|
+
loaded_value = if arg_defn.type.list?
|
35
|
+
value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
36
|
+
else
|
37
|
+
load_application_object(arg_defn, loads, value, context)
|
38
|
+
end
|
39
|
+
maybe_lazies << context.schema.after_lazy(loaded_value) do |loaded_value|
|
40
|
+
@ruby_style_hash[ruby_kwargs_key] = loaded_value
|
41
|
+
end
|
32
42
|
end
|
33
|
-
end
|
34
43
|
|
35
|
-
|
36
|
-
|
44
|
+
# Weirdly, procs are applied during coercion, but not methods.
|
45
|
+
# Probably because these methods require a `self`.
|
46
|
+
if arg_defn.prepare.is_a?(Symbol) || context.nil? || !context.interpreter?
|
47
|
+
@ruby_style_hash[ruby_kwargs_key] = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
|
48
|
+
end
|
37
49
|
end
|
38
50
|
end
|
51
|
+
|
52
|
+
@maybe_lazies = maybe_lazies
|
39
53
|
end
|
40
54
|
|
41
55
|
# @return [GraphQL::Query::Context] The context for this query
|
42
56
|
attr_reader :context
|
43
57
|
|
44
|
-
# @return [GraphQL::Query::Arguments] The underlying arguments instance
|
58
|
+
# @return [GraphQL::Query::Arguments, GraphQL::Execution::Interpereter::Arguments] The underlying arguments instance
|
45
59
|
attr_reader :arguments
|
46
60
|
|
47
61
|
# Ruby-like hash behaviors, read-only
|
@@ -58,7 +72,13 @@ module GraphQL
|
|
58
72
|
end
|
59
73
|
|
60
74
|
def prepare
|
61
|
-
|
75
|
+
if context
|
76
|
+
context.schema.after_any_lazies(@maybe_lazies) do
|
77
|
+
self
|
78
|
+
end
|
79
|
+
else
|
80
|
+
self
|
81
|
+
end
|
62
82
|
end
|
63
83
|
|
64
84
|
def unwrap_value(value)
|
@@ -90,7 +110,7 @@ module GraphQL
|
|
90
110
|
end
|
91
111
|
|
92
112
|
def key?(key)
|
93
|
-
@ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key))
|
113
|
+
@ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key)) || false
|
94
114
|
end
|
95
115
|
|
96
116
|
# A copy of the Ruby-style hash
|
@@ -106,9 +126,11 @@ module GraphQL
|
|
106
126
|
argument_defn = super(*args, **kwargs, &block)
|
107
127
|
# Add a method access
|
108
128
|
method_name = argument_defn.keyword
|
109
|
-
|
110
|
-
|
111
|
-
|
129
|
+
class_eval <<-RUBY, __FILE__, __LINE__
|
130
|
+
def #{method_name}
|
131
|
+
self[#{method_name.inspect}]
|
132
|
+
end
|
133
|
+
RUBY
|
112
134
|
end
|
113
135
|
|
114
136
|
def to_graphql
|
@@ -117,6 +139,7 @@ module GraphQL
|
|
117
139
|
type_defn.description = description
|
118
140
|
type_defn.metadata[:type_class] = self
|
119
141
|
type_defn.mutation = mutation
|
142
|
+
type_defn.ast_node = ast_node
|
120
143
|
arguments.each do |name, arg|
|
121
144
|
type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
|
122
145
|
end
|
@@ -130,6 +153,92 @@ module GraphQL
|
|
130
153
|
def kind
|
131
154
|
GraphQL::TypeKinds::INPUT_OBJECT
|
132
155
|
end
|
156
|
+
|
157
|
+
# @api private
|
158
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
|
159
|
+
|
160
|
+
|
161
|
+
def validate_non_null_input(input, ctx)
|
162
|
+
result = GraphQL::Query::InputValidationResult.new
|
163
|
+
|
164
|
+
warden = ctx.warden
|
165
|
+
|
166
|
+
if input.is_a?(Array)
|
167
|
+
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
168
|
+
return result
|
169
|
+
end
|
170
|
+
|
171
|
+
input = begin
|
172
|
+
input.to_h
|
173
|
+
rescue
|
174
|
+
begin
|
175
|
+
# Handle ActionController::Parameters:
|
176
|
+
input.to_unsafe_h
|
177
|
+
rescue
|
178
|
+
# We're not sure it'll act like a hash, so reject it:
|
179
|
+
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
180
|
+
return result
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Inject missing required arguments
|
185
|
+
missing_required_inputs = self.arguments.reduce({}) do |m, (argument_name, argument)|
|
186
|
+
if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
|
187
|
+
m[argument_name] = nil
|
188
|
+
end
|
189
|
+
|
190
|
+
m
|
191
|
+
end
|
192
|
+
|
193
|
+
input.merge(missing_required_inputs).each do |argument_name, value|
|
194
|
+
argument = warden.get_argument(self, argument_name)
|
195
|
+
# Items in the input that are unexpected
|
196
|
+
unless argument
|
197
|
+
result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
|
198
|
+
next
|
199
|
+
end
|
200
|
+
# Items in the input that are expected, but have invalid values
|
201
|
+
argument_result = argument.type.validate_input(value, ctx)
|
202
|
+
result.merge_result!(argument_name, argument_result) unless argument_result.valid?
|
203
|
+
end
|
204
|
+
|
205
|
+
result
|
206
|
+
end
|
207
|
+
|
208
|
+
def coerce_input(value, ctx)
|
209
|
+
if value.nil?
|
210
|
+
return nil
|
211
|
+
end
|
212
|
+
|
213
|
+
arguments = coerce_arguments(nil, value, ctx)
|
214
|
+
|
215
|
+
ctx.schema.after_lazy(arguments) do |resolved_arguments|
|
216
|
+
input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
|
217
|
+
input_obj_instance.prepare
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# It's funny to think of a _result_ of an input object.
|
222
|
+
# This is used for rendering the default value in introspection responses.
|
223
|
+
def coerce_result(value, ctx)
|
224
|
+
# Allow the application to provide values as :symbols, and convert them to the strings
|
225
|
+
value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
|
226
|
+
|
227
|
+
result = {}
|
228
|
+
|
229
|
+
arguments.each do |input_key, input_field_defn|
|
230
|
+
input_value = value[input_key]
|
231
|
+
if value.key?(input_key)
|
232
|
+
result[input_key] = if input_value.nil?
|
233
|
+
nil
|
234
|
+
else
|
235
|
+
input_field_defn.type.coerce_result(input_value, ctx)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
result
|
241
|
+
end
|
133
242
|
end
|
134
243
|
end
|
135
244
|
end
|
@@ -7,11 +7,14 @@ module GraphQL
|
|
7
7
|
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
8
8
|
include GraphQL::Relay::TypeExtensions
|
9
9
|
include GraphQL::Schema::Member::BaseDSLMethods
|
10
|
+
# ConfigurationExtension's responsibilities are in `def included` below
|
10
11
|
include GraphQL::Schema::Member::TypeSystemHelpers
|
11
12
|
include GraphQL::Schema::Member::HasFields
|
12
13
|
include GraphQL::Schema::Member::HasPath
|
13
14
|
include GraphQL::Schema::Member::RelayShortcuts
|
14
15
|
include GraphQL::Schema::Member::Scoped
|
16
|
+
include GraphQL::Schema::Member::HasAstNode
|
17
|
+
include GraphQL::Schema::Member::HasUnresolvedTypeError
|
15
18
|
|
16
19
|
# Methods defined in this block will be:
|
17
20
|
# - Added as class methods to this interface
|
@@ -20,19 +23,14 @@ module GraphQL
|
|
20
23
|
self::DefinitionMethods.module_eval(&block)
|
21
24
|
end
|
22
25
|
|
23
|
-
#
|
26
|
+
# @see {Schema::Warden} hides interfaces without visible implementations
|
24
27
|
def visible?(context)
|
25
|
-
|
26
|
-
if context.schema.visible?(type, context)
|
27
|
-
return true
|
28
|
-
end
|
29
|
-
end
|
30
|
-
false
|
28
|
+
true
|
31
29
|
end
|
32
30
|
|
33
31
|
# The interface is accessible if any of its possible types are accessible
|
34
32
|
def accessible?(context)
|
35
|
-
context.schema.possible_types(self).each do |type|
|
33
|
+
context.schema.possible_types(self, context).each do |type|
|
36
34
|
if context.schema.accessible?(type, context)
|
37
35
|
return true
|
38
36
|
end
|
@@ -40,6 +38,14 @@ module GraphQL
|
|
40
38
|
false
|
41
39
|
end
|
42
40
|
|
41
|
+
def type_membership_class(membership_class = nil)
|
42
|
+
if membership_class
|
43
|
+
@type_membership_class = membership_class
|
44
|
+
else
|
45
|
+
@type_membership_class || find_inherited_value(:type_membership_class, GraphQL::Schema::TypeMembership)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
43
49
|
# Here's the tricky part. Make sure behavior keeps making its way down the inheritance chain.
|
44
50
|
def included(child_class)
|
45
51
|
if !child_class.is_a?(Class)
|
@@ -49,6 +55,7 @@ module GraphQL
|
|
49
55
|
# We need this before we can call `own_interfaces`
|
50
56
|
child_class.extend(Schema::Interface::DefinitionMethods)
|
51
57
|
|
58
|
+
child_class.type_membership_class(self.type_membership_class)
|
52
59
|
child_class.own_interfaces << self
|
53
60
|
child_class.interfaces.reverse_each do |interface_defn|
|
54
61
|
child_class.extend(interface_defn::DefinitionMethods)
|
@@ -63,6 +70,15 @@ module GraphQL
|
|
63
70
|
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
64
71
|
child_class.extend(child_class::DefinitionMethods)
|
65
72
|
end
|
73
|
+
child_class.introspection(introspection)
|
74
|
+
child_class.description(description)
|
75
|
+
if overridden_graphql_name
|
76
|
+
child_class.graphql_name(overridden_graphql_name)
|
77
|
+
end
|
78
|
+
# If interfaces are mixed into each other, only define this class once
|
79
|
+
if !child_class.const_defined?(:UnresolvedTypeError, false)
|
80
|
+
add_unresolved_type_error(child_class)
|
81
|
+
end
|
66
82
|
elsif child_class < GraphQL::Schema::Object
|
67
83
|
# This is being included into an object type, make sure it's using `implements(...)`
|
68
84
|
backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
|
@@ -89,6 +105,8 @@ module GraphQL
|
|
89
105
|
type_defn.name = graphql_name
|
90
106
|
type_defn.description = description
|
91
107
|
type_defn.orphan_types = orphan_types
|
108
|
+
type_defn.type_membership_class = self.type_membership_class
|
109
|
+
type_defn.ast_node = ast_node
|
92
110
|
fields.each do |field_name, field_inst|
|
93
111
|
field_defn = field_inst.graphql_definition
|
94
112
|
type_defn.fields[field_defn.name] = field_defn
|
@@ -2,44 +2,46 @@
|
|
2
2
|
module GraphQL
|
3
3
|
class Schema
|
4
4
|
class IntrospectionSystem
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :types, :possible_types
|
6
6
|
|
7
7
|
def initialize(schema)
|
8
8
|
@schema = schema
|
9
|
+
@class_based = !!@schema.is_a?(Class)
|
9
10
|
@built_in_namespace = GraphQL::Introspection
|
10
|
-
@custom_namespace =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
@custom_namespace = if @class_based
|
12
|
+
schema.introspection || @built_in_namespace
|
13
|
+
else
|
14
|
+
schema.introspection_namespace || @built_in_namespace
|
15
|
+
end
|
16
|
+
|
17
|
+
type_defns = [
|
18
|
+
load_constant(:SchemaType),
|
19
|
+
load_constant(:TypeType),
|
20
|
+
load_constant(:FieldType),
|
21
|
+
load_constant(:DirectiveType),
|
22
|
+
load_constant(:EnumValueType),
|
23
|
+
load_constant(:InputValueType),
|
24
|
+
load_constant(:TypeKindEnum),
|
25
|
+
load_constant(:DirectiveLocationEnum)
|
26
|
+
]
|
27
|
+
@types = {}
|
28
|
+
@possible_types = {}
|
29
|
+
type_defns.each do |t|
|
30
|
+
@types[t.graphql_name] = t
|
31
|
+
@possible_types[t.graphql_name] = [t]
|
32
|
+
end
|
21
33
|
@entry_point_fields =
|
22
|
-
if schema.disable_introspection_entry_points
|
34
|
+
if schema.disable_introspection_entry_points?
|
23
35
|
{}
|
24
36
|
else
|
25
|
-
get_fields_from_class(class_sym: :EntryPoints)
|
37
|
+
entry_point_fields = get_fields_from_class(class_sym: :EntryPoints)
|
38
|
+
entry_point_fields.delete('__schema') if schema.disable_schema_introspection_entry_point?
|
39
|
+
entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
|
40
|
+
entry_point_fields
|
26
41
|
end
|
27
42
|
@dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
|
28
43
|
end
|
29
44
|
|
30
|
-
def object_types
|
31
|
-
[
|
32
|
-
@schema_type,
|
33
|
-
@type_type,
|
34
|
-
@field_type,
|
35
|
-
@directive_type,
|
36
|
-
@enum_value_type,
|
37
|
-
@input_value_type,
|
38
|
-
@type_kind_enum,
|
39
|
-
@directive_location_enum,
|
40
|
-
]
|
41
|
-
end
|
42
|
-
|
43
45
|
def entry_points
|
44
46
|
@entry_point_fields.values
|
45
47
|
end
|
@@ -56,25 +58,94 @@ module GraphQL
|
|
56
58
|
@dynamic_fields[name]
|
57
59
|
end
|
58
60
|
|
61
|
+
# The introspection system is prepared with a bunch of LateBoundTypes.
|
62
|
+
# Replace those with the objects that they refer to, since LateBoundTypes
|
63
|
+
# aren't handled at runtime.
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
# @return void
|
67
|
+
def resolve_late_bindings
|
68
|
+
@types.each do |name, t|
|
69
|
+
if t.kind.fields?
|
70
|
+
t.fields.each do |_name, field_defn|
|
71
|
+
field_defn.type = resolve_late_binding(field_defn.type)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@entry_point_fields.each do |name, f|
|
77
|
+
f.type = resolve_late_binding(f.type)
|
78
|
+
end
|
79
|
+
|
80
|
+
@dynamic_fields.each do |name, f|
|
81
|
+
f.type = resolve_late_binding(f.type)
|
82
|
+
end
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
|
59
86
|
private
|
60
87
|
|
88
|
+
def resolve_late_binding(late_bound_type)
|
89
|
+
case late_bound_type
|
90
|
+
when GraphQL::Schema::LateBoundType
|
91
|
+
@schema.get_type(late_bound_type.name)
|
92
|
+
when GraphQL::Schema::List, GraphQL::ListType
|
93
|
+
resolve_late_binding(late_bound_type.of_type).to_list_type
|
94
|
+
when GraphQL::Schema::NonNull, GraphQL::NonNullType
|
95
|
+
resolve_late_binding(late_bound_type.of_type).to_non_null_type
|
96
|
+
when Module
|
97
|
+
# It's a normal type -- no change required
|
98
|
+
late_bound_type
|
99
|
+
else
|
100
|
+
raise "Invariant: unexpected type: #{late_bound_type} (#{late_bound_type.class})"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
61
104
|
def load_constant(class_name)
|
62
|
-
@custom_namespace.const_get(class_name)
|
105
|
+
const = @custom_namespace.const_get(class_name)
|
106
|
+
if @class_based
|
107
|
+
dup_type_class(const)
|
108
|
+
else
|
109
|
+
# Use `.to_graphql` to get a freshly-made version, not shared between schemas
|
110
|
+
const.to_graphql
|
111
|
+
end
|
63
112
|
rescue NameError
|
64
113
|
# Dup the built-in so that the cached fields aren't shared
|
65
|
-
@built_in_namespace.const_get(class_name)
|
114
|
+
dup_type_class(@built_in_namespace.const_get(class_name))
|
66
115
|
end
|
67
116
|
|
68
117
|
def get_fields_from_class(class_sym:)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
118
|
+
object_type_defn = load_constant(class_sym)
|
119
|
+
|
120
|
+
if object_type_defn.is_a?(Module)
|
121
|
+
object_type_defn.fields
|
122
|
+
else
|
123
|
+
extracted_field_defns = {}
|
124
|
+
object_class = object_type_defn.metadata[:type_class]
|
125
|
+
object_type_defn.all_fields.each do |field_defn|
|
126
|
+
inner_resolve = field_defn.resolve_proc
|
127
|
+
resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
|
128
|
+
extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
|
129
|
+
end
|
130
|
+
extracted_field_defns
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
|
135
|
+
def dup_type_class(type_class)
|
136
|
+
type_name = type_class.graphql_name
|
137
|
+
Class.new(type_class) do
|
138
|
+
# This won't be inherited like other things will
|
139
|
+
graphql_name(type_name)
|
140
|
+
|
141
|
+
if type_class.kind.fields?
|
142
|
+
type_class.fields.each do |_name, field_defn|
|
143
|
+
dup_field = field_defn.dup
|
144
|
+
dup_field.owner = self
|
145
|
+
add_field(dup_field)
|
146
|
+
end
|
147
|
+
end
|
76
148
|
end
|
77
|
-
extracted_field_defns
|
78
149
|
end
|
79
150
|
|
80
151
|
class PerFieldProxyResolve
|
@@ -6,6 +6,7 @@ module GraphQL
|
|
6
6
|
# @api Private
|
7
7
|
class LateBoundType
|
8
8
|
attr_reader :name
|
9
|
+
alias :graphql_name :name
|
9
10
|
def initialize(local_name)
|
10
11
|
@name = local_name
|
11
12
|
end
|
@@ -15,11 +16,11 @@ module GraphQL
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def to_non_null_type
|
18
|
-
GraphQL::NonNullType.new(of_type: self)
|
19
|
+
@to_non_null_type ||= GraphQL::NonNullType.new(of_type: self)
|
19
20
|
end
|
20
21
|
|
21
22
|
def to_list_type
|
22
|
-
GraphQL::ListType.new(of_type: self)
|
23
|
+
@to_list_type ||= GraphQL::ListType.new(of_type: self)
|
23
24
|
end
|
24
25
|
|
25
26
|
def inspect
|
data/lib/graphql/schema/list.rb
CHANGED
@@ -6,6 +6,8 @@ module GraphQL
|
|
6
6
|
# Wraps a {Schema::Member} as a list type.
|
7
7
|
# @see {Schema::Member::TypeSystemHelpers#to_list_type}
|
8
8
|
class List < GraphQL::Schema::Wrapper
|
9
|
+
include Schema::Member::ValidatesInput
|
10
|
+
|
9
11
|
def to_graphql
|
10
12
|
@of_type.graphql_definition.to_list_type
|
11
13
|
end
|
@@ -23,6 +25,51 @@ module GraphQL
|
|
23
25
|
def to_type_signature
|
24
26
|
"[#{@of_type.to_type_signature}]"
|
25
27
|
end
|
28
|
+
|
29
|
+
# This is for introspection, where it's expected the name will be `null`
|
30
|
+
def graphql_name
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Also for implementing introspection
|
35
|
+
def description
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def coerce_result(value, ctx)
|
40
|
+
value.map { |i| i.nil? ? nil : of_type.coerce_result(i, ctx) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def coerce_input(value, ctx)
|
44
|
+
if value.nil?
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
coerced = ensure_array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
|
48
|
+
ctx.schema.after_any_lazies(coerced, &:itself)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_non_null_input(value, ctx)
|
53
|
+
result = GraphQL::Query::InputValidationResult.new
|
54
|
+
ensure_array(value).each_with_index do |item, index|
|
55
|
+
item_result = of_type.validate_input(item, ctx)
|
56
|
+
if !item_result.valid?
|
57
|
+
result.merge_result!(index, item_result)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def ensure_array(value)
|
66
|
+
# `Array({ a: 1 })` makes `[[:a, 1]]`, so do it manually
|
67
|
+
if value.is_a?(Array)
|
68
|
+
value
|
69
|
+
else
|
70
|
+
[value]
|
71
|
+
end
|
72
|
+
end
|
26
73
|
end
|
27
74
|
end
|
28
75
|
end
|