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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.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_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -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/graphql_controller.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/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +8 -0
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +183 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +89 -45
- data/lib/graphql/dataloader.rb +115 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +331 -455
- data/lib/graphql/execution/interpreter.rb +125 -61
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +124 -46
- data/lib/graphql/execution/multiplex.rb +3 -117
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/directive_type.rb +3 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +10 -13
- data/lib/graphql/introspection/type_type.rb +17 -10
- data/lib/graphql/introspection.rb +3 -2
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +75 -59
- data/lib/graphql/language/lexer.rb +358 -1506
- data/lib/graphql/language/nodes.rb +166 -93
- data/lib/graphql/language/parser.rb +795 -1953
- data/lib/graphql/language/printer.rb +340 -160
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +117 -112
- data/lib/graphql/query/null_context.rb +12 -25
- data/lib/graphql/query/validation_pipeline.rb +6 -5
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +86 -30
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +29 -11
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +59 -23
- data/lib/graphql/schema/always_visible.rb +11 -0
- data/lib/graphql/schema/argument.rb +55 -26
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +56 -32
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +15 -3
- data/lib/graphql/schema/enum.rb +35 -24
- data/lib/graphql/schema/enum_value.rb +2 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +147 -107
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +158 -0
- data/lib/graphql/schema/input_object.rb +47 -11
- data/lib/graphql/schema/interface.rb +15 -21
- data/lib/graphql/schema/introspection_system.rb +7 -17
- data/lib/graphql/schema/late_bound_type.rb +10 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +170 -130
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +100 -38
- data/lib/graphql/schema/member/has_interfaces.rb +65 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +16 -5
- data/lib/graphql/schema/printer.rb +11 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +47 -32
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +11 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +4 -2
- data/lib/graphql/schema/warden.rb +238 -93
- data/lib/graphql/schema.rb +498 -103
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +11 -10
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +20 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +17 -3
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -40
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +27 -20
- data/readme.md +13 -3
- metadata +96 -47
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/language/parser.y +0 -554
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
- data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
module HasSingleInputArgument
|
6
|
+
def resolve_with_support(**inputs)
|
7
|
+
if inputs[:input].is_a?(InputObject)
|
8
|
+
input = inputs[:input].to_kwargs
|
9
|
+
else
|
10
|
+
input = inputs[:input]
|
11
|
+
end
|
12
|
+
|
13
|
+
new_extras = field ? field.extras : []
|
14
|
+
all_extras = self.class.extras + new_extras
|
15
|
+
|
16
|
+
# Transfer these from the top-level hash to the
|
17
|
+
# shortcutted `input:` object
|
18
|
+
all_extras.each do |ext|
|
19
|
+
# It's possible that the `extra` was not passed along by this point,
|
20
|
+
# don't re-add it if it wasn't given here.
|
21
|
+
if inputs.key?(ext)
|
22
|
+
input[ext] = inputs[ext]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if input
|
27
|
+
# This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
|
28
|
+
input_kwargs = input.to_h
|
29
|
+
else
|
30
|
+
# Relay Classic Mutations with no `argument`s
|
31
|
+
# don't require `input:`
|
32
|
+
input_kwargs = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
if input_kwargs.any?
|
36
|
+
super(**input_kwargs)
|
37
|
+
else
|
38
|
+
super()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
base.extend(ClassMethods)
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def dummy
|
48
|
+
@dummy ||= begin
|
49
|
+
d = Class.new(GraphQL::Schema::Resolver)
|
50
|
+
d.graphql_name "#{self.graphql_name}DummyResolver"
|
51
|
+
d.argument_class(self.argument_class)
|
52
|
+
# TODO make this lazier?
|
53
|
+
d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
|
54
|
+
d
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
59
|
+
dummy.arguments(context)
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
63
|
+
dummy.get_argument(name, context)
|
64
|
+
end
|
65
|
+
|
66
|
+
def own_field_arguments
|
67
|
+
dummy.own_arguments
|
68
|
+
end
|
69
|
+
|
70
|
+
def any_field_arguments?
|
71
|
+
dummy.any_arguments?
|
72
|
+
end
|
73
|
+
|
74
|
+
def all_field_argument_definitions
|
75
|
+
dummy.all_argument_definitions
|
76
|
+
end
|
77
|
+
|
78
|
+
# Also apply this argument to the input type:
|
79
|
+
def argument(*args, own_argument: false, **kwargs, &block)
|
80
|
+
it = input_type # make sure any inherited arguments are already added to it
|
81
|
+
arg = super(*args, **kwargs, &block)
|
82
|
+
|
83
|
+
# This definition might be overriding something inherited;
|
84
|
+
# if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
|
85
|
+
prev_args = it.own_arguments[arg.graphql_name]
|
86
|
+
case prev_args
|
87
|
+
when GraphQL::Schema::Argument
|
88
|
+
if prev_args.owner != self
|
89
|
+
it.own_arguments.delete(arg.graphql_name)
|
90
|
+
end
|
91
|
+
when Array
|
92
|
+
prev_args.reject! { |a| a.owner != self }
|
93
|
+
if prev_args.empty?
|
94
|
+
it.own_arguments.delete(arg.graphql_name)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it.add_argument(arg)
|
99
|
+
arg
|
100
|
+
end
|
101
|
+
|
102
|
+
# The base class for generated input object types
|
103
|
+
# @param new_class [Class] The base class to use for generating input object definitions
|
104
|
+
# @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
|
105
|
+
def input_object_class(new_class = nil)
|
106
|
+
if new_class
|
107
|
+
@input_object_class = new_class
|
108
|
+
end
|
109
|
+
@input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
|
113
|
+
# @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
|
114
|
+
def input_type(new_input_type = nil)
|
115
|
+
if new_input_type
|
116
|
+
@input_type = new_input_type
|
117
|
+
end
|
118
|
+
@input_type ||= generate_input_type
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Generate the input type for the `input:` argument
|
124
|
+
# To customize how input objects are generated, override this method
|
125
|
+
# @return [Class] a subclass of {.input_object_class}
|
126
|
+
def generate_input_type
|
127
|
+
mutation_args = all_argument_definitions
|
128
|
+
mutation_class = self
|
129
|
+
Class.new(input_object_class) do
|
130
|
+
class << self
|
131
|
+
def default_graphql_name
|
132
|
+
"#{self.mutation.graphql_name}Input"
|
133
|
+
end
|
134
|
+
|
135
|
+
def description(new_desc = nil)
|
136
|
+
super || "Autogenerated input type of #{self.mutation.graphql_name}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
mutation(mutation_class)
|
140
|
+
# these might be inherited:
|
141
|
+
mutation_args.each do |arg|
|
142
|
+
add_argument(arg)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def authorize_arguments(args, values)
|
151
|
+
# remove the `input` wrapper to match values
|
152
|
+
input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
|
153
|
+
input_args = context.types.arguments(input_type)
|
154
|
+
super(input_args, values)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -23,7 +23,8 @@ module GraphQL
|
|
23
23
|
@ruby_style_hash = ruby_kwargs
|
24
24
|
@arguments = arguments
|
25
25
|
# Apply prepares, not great to have it duplicated here.
|
26
|
-
self.class.arguments(context).each_value
|
26
|
+
arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
|
27
|
+
arg_defns.each do |arg_defn|
|
27
28
|
ruby_kwargs_key = arg_defn.keyword
|
28
29
|
if @ruby_style_hash.key?(ruby_kwargs_key)
|
29
30
|
# Weirdly, procs are applied during coercion, but not methods.
|
@@ -58,7 +59,7 @@ module GraphQL
|
|
58
59
|
def self.authorized?(obj, value, ctx)
|
59
60
|
# Authorize each argument (but this doesn't apply if `prepare` is implemented):
|
60
61
|
if value.respond_to?(:key?)
|
61
|
-
arguments(
|
62
|
+
ctx.types.arguments(self).each do |input_obj_arg|
|
62
63
|
if value.key?(input_obj_arg.keyword) &&
|
63
64
|
!input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
|
64
65
|
return false
|
@@ -69,6 +70,19 @@ module GraphQL
|
|
69
70
|
true
|
70
71
|
end
|
71
72
|
|
73
|
+
def self.one_of
|
74
|
+
if !one_of?
|
75
|
+
if all_argument_definitions.any? { |arg| arg.type.non_null? }
|
76
|
+
raise ArgumentError, "`one_of` may not be used with required arguments -- add `required: false` to argument definitions to use `one_of`"
|
77
|
+
end
|
78
|
+
directive(GraphQL::Schema::Directive::OneOf)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.one_of?
|
83
|
+
false # Re-defined when `OneOf` is added
|
84
|
+
end
|
85
|
+
|
72
86
|
def unwrap_value(value)
|
73
87
|
case value
|
74
88
|
when Array
|
@@ -109,12 +123,21 @@ module GraphQL
|
|
109
123
|
class << self
|
110
124
|
def argument(*args, **kwargs, &block)
|
111
125
|
argument_defn = super(*args, **kwargs, &block)
|
126
|
+
if one_of?
|
127
|
+
if argument_defn.type.non_null?
|
128
|
+
raise ArgumentError, "Argument '#{argument_defn.path}' must be nullable because it is part of a OneOf type, add `required: false`."
|
129
|
+
end
|
130
|
+
if argument_defn.default_value?
|
131
|
+
raise ArgumentError, "Argument '#{argument_defn.path}' cannot have a default value because it is part of a OneOf type, remove `default_value: ...`."
|
132
|
+
end
|
133
|
+
end
|
112
134
|
# Add a method access
|
113
135
|
method_name = argument_defn.keyword
|
114
136
|
class_eval <<-RUBY, __FILE__, __LINE__
|
115
137
|
def #{method_name}
|
116
138
|
self[#{method_name.inspect}]
|
117
139
|
end
|
140
|
+
alias_method :#{method_name}, :#{method_name}
|
118
141
|
RUBY
|
119
142
|
argument_defn
|
120
143
|
end
|
@@ -124,10 +147,10 @@ module GraphQL
|
|
124
147
|
end
|
125
148
|
|
126
149
|
# @api private
|
127
|
-
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object
|
150
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
128
151
|
|
129
152
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
130
|
-
|
153
|
+
types = ctx.types
|
131
154
|
|
132
155
|
if input.is_a?(Array)
|
133
156
|
return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
@@ -139,9 +162,9 @@ module GraphQL
|
|
139
162
|
end
|
140
163
|
|
141
164
|
# Inject missing required arguments
|
142
|
-
missing_required_inputs =
|
143
|
-
if !input.key?(
|
144
|
-
m[
|
165
|
+
missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
|
166
|
+
if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
|
167
|
+
m[argument.graphql_name] = nil
|
145
168
|
end
|
146
169
|
|
147
170
|
m
|
@@ -150,7 +173,7 @@ module GraphQL
|
|
150
173
|
result = nil
|
151
174
|
[input, missing_required_inputs].each do |args_to_validate|
|
152
175
|
args_to_validate.each do |argument_name, value|
|
153
|
-
argument =
|
176
|
+
argument = types.argument(self, argument_name)
|
154
177
|
# Items in the input that are unexpected
|
155
178
|
if argument.nil?
|
156
179
|
result ||= Query::InputValidationResult.new
|
@@ -166,6 +189,20 @@ module GraphQL
|
|
166
189
|
end
|
167
190
|
end
|
168
191
|
|
192
|
+
if one_of?
|
193
|
+
if input.size == 1
|
194
|
+
input.each do |name, value|
|
195
|
+
if value.nil?
|
196
|
+
result ||= Query::InputValidationResult.new
|
197
|
+
result.add_problem("'#{graphql_name}' requires exactly one argument, but '#{name}' was `null`.")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
else
|
201
|
+
result ||= Query::InputValidationResult.new
|
202
|
+
result.add_problem("'#{graphql_name}' requires exactly one argument, but #{input.size} were provided.")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
169
206
|
result
|
170
207
|
end
|
171
208
|
|
@@ -176,12 +213,11 @@ module GraphQL
|
|
176
213
|
|
177
214
|
arguments = coerce_arguments(nil, value, ctx)
|
178
215
|
|
179
|
-
ctx.
|
216
|
+
ctx.query.after_lazy(arguments) do |resolved_arguments|
|
180
217
|
if resolved_arguments.is_a?(GraphQL::Error)
|
181
218
|
raise resolved_arguments
|
182
219
|
else
|
183
|
-
|
184
|
-
input_obj_instance.prepare
|
220
|
+
self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
|
185
221
|
end
|
186
222
|
end
|
187
223
|
end
|
@@ -20,6 +20,15 @@ module GraphQL
|
|
20
20
|
# - Added as class methods to this interface
|
21
21
|
# - Added as class methods to all child interfaces
|
22
22
|
def definition_methods(&block)
|
23
|
+
# Use an instance variable to tell whether it's been included previously or not;
|
24
|
+
# You can't use constant detection because constants are brought into scope
|
25
|
+
# by `include`, which has already happened at this point.
|
26
|
+
if !defined?(@_definition_methods)
|
27
|
+
defn_methods_module = Module.new
|
28
|
+
@_definition_methods = defn_methods_module
|
29
|
+
const_set(:DefinitionMethods, defn_methods_module)
|
30
|
+
extend(self::DefinitionMethods)
|
31
|
+
end
|
23
32
|
self::DefinitionMethods.module_eval(&block)
|
24
33
|
end
|
25
34
|
|
@@ -28,16 +37,6 @@ module GraphQL
|
|
28
37
|
true
|
29
38
|
end
|
30
39
|
|
31
|
-
# The interface is accessible if any of its possible types are accessible
|
32
|
-
def accessible?(context)
|
33
|
-
context.schema.possible_types(self, context).each do |type|
|
34
|
-
if context.schema.accessible?(type, context)
|
35
|
-
return true
|
36
|
-
end
|
37
|
-
end
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
40
|
def type_membership_class(membership_class = nil)
|
42
41
|
if membership_class
|
43
42
|
@type_membership_class = membership_class
|
@@ -57,20 +56,11 @@ module GraphQL
|
|
57
56
|
|
58
57
|
child_class.type_membership_class(self.type_membership_class)
|
59
58
|
child_class.ancestors.reverse_each do |ancestor|
|
60
|
-
if ancestor.const_defined?(:DefinitionMethods)
|
59
|
+
if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
|
61
60
|
child_class.extend(ancestor::DefinitionMethods)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
|
-
# Use an instance variable to tell whether it's been included previously or not;
|
66
|
-
# You can't use constant detection because constants are brought into scope
|
67
|
-
# by `include`, which has already happened at this point.
|
68
|
-
if !child_class.instance_variable_defined?(:@_definition_methods)
|
69
|
-
defn_methods_module = Module.new
|
70
|
-
child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
|
71
|
-
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
72
|
-
child_class.extend(child_class::DefinitionMethods)
|
73
|
-
end
|
74
64
|
child_class.introspection(introspection)
|
75
65
|
child_class.description(description)
|
76
66
|
# If interfaces are mixed into each other, only define this class once
|
@@ -79,7 +69,11 @@ module GraphQL
|
|
79
69
|
end
|
80
70
|
elsif child_class < GraphQL::Schema::Object
|
81
71
|
# This is being included into an object type, make sure it's using `implements(...)`
|
82
|
-
backtrace_line =
|
72
|
+
backtrace_line = caller_locations(0, 10).find do |location|
|
73
|
+
location.base_label == "implements" &&
|
74
|
+
location.path.end_with?("schema/member/has_interfaces.rb")
|
75
|
+
end
|
76
|
+
|
83
77
|
if !backtrace_line
|
84
78
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
85
79
|
end
|
@@ -25,10 +25,10 @@ module GraphQL
|
|
25
25
|
load_constant(:DirectiveLocationEnum)
|
26
26
|
]
|
27
27
|
@types = {}
|
28
|
-
@possible_types = {}
|
28
|
+
@possible_types = {}.tap(&:compare_by_identity)
|
29
29
|
type_defns.each do |t|
|
30
30
|
@types[t.graphql_name] = t
|
31
|
-
@possible_types[t
|
31
|
+
@possible_types[t] = [t]
|
32
32
|
end
|
33
33
|
@entry_point_fields =
|
34
34
|
if schema.disable_introspection_entry_points?
|
@@ -39,7 +39,9 @@ module GraphQL
|
|
39
39
|
entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
|
40
40
|
entry_point_fields
|
41
41
|
end
|
42
|
+
@entry_point_fields.each { |k, v| v.dynamic_introspection = true }
|
42
43
|
@dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
|
44
|
+
@dynamic_fields.each { |k, v| v.dynamic_introspection = true }
|
43
45
|
end
|
44
46
|
|
45
47
|
def entry_points
|
@@ -67,7 +69,7 @@ module GraphQL
|
|
67
69
|
def resolve_late_bindings
|
68
70
|
@types.each do |name, t|
|
69
71
|
if t.kind.fields?
|
70
|
-
t.
|
72
|
+
t.all_field_definitions.each do |field_defn|
|
71
73
|
field_defn.type = resolve_late_binding(field_defn.type)
|
72
74
|
end
|
73
75
|
end
|
@@ -111,19 +113,7 @@ module GraphQL
|
|
111
113
|
|
112
114
|
def get_fields_from_class(class_sym:)
|
113
115
|
object_type_defn = load_constant(class_sym)
|
114
|
-
|
115
|
-
if object_type_defn.is_a?(Module)
|
116
|
-
object_type_defn.fields
|
117
|
-
else
|
118
|
-
extracted_field_defns = {}
|
119
|
-
object_class = object_type_defn.metadata[:type_class]
|
120
|
-
object_type_defn.all_fields.each do |field_defn|
|
121
|
-
inner_resolve = field_defn.resolve_proc
|
122
|
-
resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
|
123
|
-
extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
|
124
|
-
end
|
125
|
-
extracted_field_defns
|
126
|
-
end
|
116
|
+
object_type_defn.fields
|
127
117
|
end
|
128
118
|
|
129
119
|
# This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
|
@@ -155,7 +145,7 @@ module GraphQL
|
|
155
145
|
if obj.is_a?(GraphQL::Schema::Object)
|
156
146
|
obj = obj.object
|
157
147
|
end
|
158
|
-
wrapped_object = @object_class.
|
148
|
+
wrapped_object = @object_class.wrap(obj, query_ctx)
|
159
149
|
@inner_resolve.call(wrapped_object, args, ctx)
|
160
150
|
end
|
161
151
|
end
|
@@ -9,6 +9,8 @@ module GraphQL
|
|
9
9
|
alias :graphql_name :name
|
10
10
|
def initialize(local_name)
|
11
11
|
@name = local_name
|
12
|
+
@to_non_null_type = nil
|
13
|
+
@to_list_type = nil
|
12
14
|
end
|
13
15
|
|
14
16
|
def unwrap
|
@@ -23,10 +25,18 @@ module GraphQL
|
|
23
25
|
@to_list_type ||= GraphQL::Schema::List.new(self)
|
24
26
|
end
|
25
27
|
|
28
|
+
def to_type_signature
|
29
|
+
name
|
30
|
+
end
|
31
|
+
|
26
32
|
def inspect
|
27
33
|
"#<LateBoundType @name=#{name}>"
|
28
34
|
end
|
29
35
|
|
36
|
+
def non_null?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
30
40
|
alias :to_s :inspect
|
31
41
|
end
|
32
42
|
end
|
data/lib/graphql/schema/list.rb
CHANGED
@@ -52,7 +52,7 @@ module GraphQL
|
|
52
52
|
unless item_result.valid?
|
53
53
|
if max_errors
|
54
54
|
if max_errors == 0
|
55
|
-
|
55
|
+
add_max_errors_reached_message(result)
|
56
56
|
break
|
57
57
|
end
|
58
58
|
|
@@ -76,7 +76,7 @@ module GraphQL
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
def
|
79
|
+
def add_max_errors_reached_message(result)
|
80
80
|
message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
|
81
81
|
item_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
82
82
|
result.merge_result!(nil, item_result)
|
@@ -32,7 +32,8 @@ module GraphQL
|
|
32
32
|
end
|
33
33
|
|
34
34
|
Class.new(GraphQL::Schema) do
|
35
|
-
|
35
|
+
add_type_and_traverse(types.values, root: false)
|
36
|
+
orphan_types(types.values.select { |t| t.kind.object? })
|
36
37
|
directives(directives)
|
37
38
|
description(schema["description"])
|
38
39
|
|
@@ -176,7 +177,6 @@ module GraphQL
|
|
176
177
|
while (of_type = unwrapped_field_hash["ofType"])
|
177
178
|
unwrapped_field_hash = of_type
|
178
179
|
end
|
179
|
-
type_name = unwrapped_field_hash["name"]
|
180
180
|
|
181
181
|
type_defn.field(
|
182
182
|
field_hash["name"],
|
@@ -186,7 +186,6 @@ module GraphQL
|
|
186
186
|
null: true,
|
187
187
|
camelize: false,
|
188
188
|
connection_extension: nil,
|
189
|
-
connection: type_name.end_with?("Connection"),
|
190
189
|
) do
|
191
190
|
if field_hash["args"].any?
|
192
191
|
loader.build_arguments(self, field_hash["args"], type_resolver)
|
@@ -22,14 +22,10 @@ module GraphQL
|
|
22
22
|
GraphQL::NameValidator.validate!(new_name)
|
23
23
|
@graphql_name = new_name
|
24
24
|
else
|
25
|
-
|
25
|
+
@graphql_name ||= default_graphql_name
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def overridden_graphql_name
|
30
|
-
defined?(@graphql_name) ? @graphql_name : nil
|
31
|
-
end
|
32
|
-
|
33
29
|
# Just a convenience method to point out that people should use graphql_name instead
|
34
30
|
def name(new_name = nil)
|
35
31
|
return super() if new_name.nil?
|
@@ -50,7 +46,7 @@ module GraphQL
|
|
50
46
|
elsif defined?(@description)
|
51
47
|
@description
|
52
48
|
else
|
53
|
-
nil
|
49
|
+
@description = nil
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
@@ -60,8 +56,12 @@ module GraphQL
|
|
60
56
|
def inherited(child_class)
|
61
57
|
child_class.introspection(introspection)
|
62
58
|
child_class.description(description)
|
63
|
-
|
64
|
-
|
59
|
+
child_class.default_graphql_name = nil
|
60
|
+
|
61
|
+
if defined?(@graphql_name) && @graphql_name && (self.name.nil? || graphql_name != default_graphql_name)
|
62
|
+
child_class.graphql_name(graphql_name)
|
63
|
+
else
|
64
|
+
child_class.graphql_name = nil
|
65
65
|
end
|
66
66
|
super
|
67
67
|
end
|
@@ -79,7 +79,7 @@ module GraphQL
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def introspection?
|
82
|
-
introspection
|
82
|
+
!!@introspection
|
83
83
|
end
|
84
84
|
|
85
85
|
# The mutation this type was derived from, if it was derived from a mutation
|
@@ -102,8 +102,8 @@ module GraphQL
|
|
102
102
|
def default_graphql_name
|
103
103
|
@default_graphql_name ||= begin
|
104
104
|
raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
|
105
|
-
|
106
|
-
|
105
|
+
g_name = -name.split("::").last
|
106
|
+
g_name.end_with?("Type") ? g_name.sub(/Type\Z/, "") : g_name
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -111,13 +111,17 @@ module GraphQL
|
|
111
111
|
true
|
112
112
|
end
|
113
113
|
|
114
|
-
def
|
114
|
+
def authorized?(object, context)
|
115
115
|
true
|
116
116
|
end
|
117
117
|
|
118
|
-
def
|
119
|
-
|
118
|
+
def default_relay
|
119
|
+
false
|
120
120
|
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
attr_writer :default_graphql_name, :graphql_name
|
121
125
|
end
|
122
126
|
end
|
123
127
|
end
|
@@ -109,7 +109,14 @@ module GraphQL
|
|
109
109
|
to_type_name(something.name)
|
110
110
|
end
|
111
111
|
when String
|
112
|
-
something.
|
112
|
+
if something.include?("]") ||
|
113
|
+
something.include?("[") ||
|
114
|
+
something.include?("!") ||
|
115
|
+
something.include?("::")
|
116
|
+
something.gsub(/\]\[\!/, "").split("::").last
|
117
|
+
else
|
118
|
+
something
|
119
|
+
end
|
113
120
|
when GraphQL::Schema::NonNull, GraphQL::Schema::List
|
114
121
|
to_type_name(something.unwrap)
|
115
122
|
else
|
@@ -120,9 +127,10 @@ module GraphQL
|
|
120
127
|
def camelize(string)
|
121
128
|
return string if string == '_'
|
122
129
|
return string unless string.include?("_")
|
123
|
-
camelized = string.split('_').
|
130
|
+
camelized = string.split('_').each(&:capitalize!).join
|
124
131
|
camelized[0] = camelized[0].downcase
|
125
|
-
if
|
132
|
+
if string.start_with?("_")
|
133
|
+
match_data = string.match(/\A(_+)/)
|
126
134
|
camelized = "#{match_data[0]}#{camelized}"
|
127
135
|
end
|
128
136
|
camelized
|