graphql 2.0.30 → 2.3.6
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.
- 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/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 +5 -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 +282 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/trace.rb +12 -15
- 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 +11 -3
- data/lib/graphql/dataloader.rb +112 -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/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +163 -365
- data/lib/graphql/execution/interpreter.rb +92 -158
- data/lib/graphql/execution/lookahead.rb +88 -21
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/schema_type.rb +3 -1
- 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 +38 -38
- data/lib/graphql/language/lexer.rb +305 -193
- data/lib/graphql/language/nodes.rb +113 -66
- data/lib/graphql/language/parser.rb +787 -1986
- data/lib/graphql/language/printer.rb +303 -146
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +61 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +28 -1
- 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 +66 -131
- data/lib/graphql/query/null_context.rb +4 -11
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +17 -26
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +21 -11
- data/lib/graphql/schema/argument.rb +43 -8
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +9 -12
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +3 -1
- data/lib/graphql/schema/enum.rb +3 -3
- data/lib/graphql/schema/field/connection_extension.rb +1 -15
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +49 -35
- data/lib/graphql/schema/has_single_input_argument.rb +157 -0
- data/lib/graphql/schema/input_object.rb +4 -4
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/introspection_system.rb +4 -2
- data/lib/graphql/schema/late_bound_type.rb +4 -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 +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +63 -73
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +8 -5
- data/lib/graphql/schema/member/has_interfaces.rb +23 -9
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/printer.rb +8 -7
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
- data/lib/graphql/schema/resolver.rb +27 -13
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/warden.rb +96 -95
- data/lib/graphql/schema.rb +323 -102
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +2 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +1 -1
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +15 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/prometheus_trace.rb +9 -9
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/type_kinds.rb +1 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +13 -13
- data/readme.md +12 -2
- metadata +33 -26
- 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 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -0,0 +1,157 @@
|
|
|
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_args = args["input"].type.unwrap.arguments(context)
|
|
153
|
+
super(input_args, values)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -79,7 +79,7 @@ module GraphQL
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def self.one_of?
|
|
82
|
-
|
|
82
|
+
false # Re-defined when `OneOf` is added
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def unwrap_value(value)
|
|
@@ -136,6 +136,7 @@ module GraphQL
|
|
|
136
136
|
def #{method_name}
|
|
137
137
|
self[#{method_name.inspect}]
|
|
138
138
|
end
|
|
139
|
+
alias_method :#{method_name}, :#{method_name}
|
|
139
140
|
RUBY
|
|
140
141
|
argument_defn
|
|
141
142
|
end
|
|
@@ -145,7 +146,7 @@ module GraphQL
|
|
|
145
146
|
end
|
|
146
147
|
|
|
147
148
|
# @api private
|
|
148
|
-
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object
|
|
149
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
|
149
150
|
|
|
150
151
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
|
151
152
|
warden = ctx.warden
|
|
@@ -215,8 +216,7 @@ module GraphQL
|
|
|
215
216
|
if resolved_arguments.is_a?(GraphQL::Error)
|
|
216
217
|
raise resolved_arguments
|
|
217
218
|
else
|
|
218
|
-
|
|
219
|
-
input_obj_instance.prepare
|
|
219
|
+
self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
|
|
220
220
|
end
|
|
221
221
|
end
|
|
222
222
|
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
|
|
|
@@ -47,20 +56,11 @@ module GraphQL
|
|
|
47
56
|
|
|
48
57
|
child_class.type_membership_class(self.type_membership_class)
|
|
49
58
|
child_class.ancestors.reverse_each do |ancestor|
|
|
50
|
-
if ancestor.const_defined?(:DefinitionMethods)
|
|
59
|
+
if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
|
|
51
60
|
child_class.extend(ancestor::DefinitionMethods)
|
|
52
61
|
end
|
|
53
62
|
end
|
|
54
63
|
|
|
55
|
-
# Use an instance variable to tell whether it's been included previously or not;
|
|
56
|
-
# You can't use constant detection because constants are brought into scope
|
|
57
|
-
# by `include`, which has already happened at this point.
|
|
58
|
-
if !child_class.instance_variable_defined?(:@_definition_methods)
|
|
59
|
-
defn_methods_module = Module.new
|
|
60
|
-
child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
|
|
61
|
-
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
|
62
|
-
child_class.extend(child_class::DefinitionMethods)
|
|
63
|
-
end
|
|
64
64
|
child_class.introspection(introspection)
|
|
65
65
|
child_class.description(description)
|
|
66
66
|
# If interfaces are mixed into each other, only define this class once
|
|
@@ -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
|
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)
|
|
@@ -102,7 +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
|
-
-name.split("::").last
|
|
105
|
+
g_name = -name.split("::").last
|
|
106
|
+
g_name.end_with?("Type") ? g_name.sub(/Type\Z/, "") : g_name
|
|
106
107
|
end
|
|
107
108
|
end
|
|
108
109
|
|
|
@@ -38,39 +38,6 @@ module GraphQL
|
|
|
38
38
|
end
|
|
39
39
|
arg_defn = self.argument_class.new(*args, **kwargs, &block)
|
|
40
40
|
add_argument(arg_defn)
|
|
41
|
-
|
|
42
|
-
if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
|
|
43
|
-
method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
|
|
44
|
-
"self."
|
|
45
|
-
elsif self < GraphQL::Schema::Resolver
|
|
46
|
-
""
|
|
47
|
-
else
|
|
48
|
-
raise "Unexpected argument owner: #{self}"
|
|
49
|
-
end
|
|
50
|
-
if loads && arg_defn.type.list?
|
|
51
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
52
|
-
def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
|
|
53
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
54
|
-
(context || self.context).query.after_lazy(values) do |values2|
|
|
55
|
-
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
RUBY
|
|
59
|
-
elsif loads
|
|
60
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
61
|
-
def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
|
|
62
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
63
|
-
load_application_object(argument, value, context || self.context)
|
|
64
|
-
end
|
|
65
|
-
RUBY
|
|
66
|
-
else
|
|
67
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
68
|
-
def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
|
|
69
|
-
value
|
|
70
|
-
end
|
|
71
|
-
RUBY
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
41
|
arg_defn
|
|
75
42
|
end
|
|
76
43
|
|
|
@@ -109,7 +76,7 @@ module GraphQL
|
|
|
109
76
|
end
|
|
110
77
|
|
|
111
78
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
|
112
|
-
def arguments(context = GraphQL::Query::NullContext)
|
|
79
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
|
113
80
|
if own_arguments.any?
|
|
114
81
|
own_arguments_that_apply = {}
|
|
115
82
|
own_arguments.each do |name, args_entry|
|
|
@@ -122,6 +89,10 @@ module GraphQL
|
|
|
122
89
|
own_arguments_that_apply || own_arguments
|
|
123
90
|
end
|
|
124
91
|
|
|
92
|
+
def any_arguments?
|
|
93
|
+
own_arguments.any?
|
|
94
|
+
end
|
|
95
|
+
|
|
125
96
|
module ClassConfigured
|
|
126
97
|
def inherited(child_class)
|
|
127
98
|
super
|
|
@@ -129,7 +100,7 @@ module GraphQL
|
|
|
129
100
|
end
|
|
130
101
|
|
|
131
102
|
module InheritedArguments
|
|
132
|
-
def arguments(context = GraphQL::Query::NullContext)
|
|
103
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
|
133
104
|
own_arguments = super
|
|
134
105
|
inherited_arguments = superclass.arguments(context)
|
|
135
106
|
|
|
@@ -145,6 +116,10 @@ module GraphQL
|
|
|
145
116
|
end
|
|
146
117
|
end
|
|
147
118
|
|
|
119
|
+
def any_arguments?
|
|
120
|
+
super || superclass.any_arguments?
|
|
121
|
+
end
|
|
122
|
+
|
|
148
123
|
def all_argument_definitions
|
|
149
124
|
all_defns = {}
|
|
150
125
|
ancestors.reverse_each do |ancestor|
|
|
@@ -158,7 +133,7 @@ module GraphQL
|
|
|
158
133
|
end
|
|
159
134
|
|
|
160
135
|
|
|
161
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
|
136
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
|
162
137
|
warden = Warden.from_context(context)
|
|
163
138
|
for ancestor in ancestors
|
|
164
139
|
if ancestor.respond_to?(:own_arguments) &&
|
|
@@ -173,9 +148,9 @@ module GraphQL
|
|
|
173
148
|
end
|
|
174
149
|
|
|
175
150
|
module FieldConfigured
|
|
176
|
-
def arguments(context = GraphQL::Query::NullContext)
|
|
151
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
|
177
152
|
own_arguments = super
|
|
178
|
-
if
|
|
153
|
+
if @resolver_class
|
|
179
154
|
inherited_arguments = @resolver_class.field_arguments(context)
|
|
180
155
|
if own_arguments.any?
|
|
181
156
|
if inherited_arguments.any?
|
|
@@ -191,8 +166,12 @@ module GraphQL
|
|
|
191
166
|
end
|
|
192
167
|
end
|
|
193
168
|
|
|
169
|
+
def any_arguments?
|
|
170
|
+
super || (@resolver_class && @resolver_class.any_field_arguments?)
|
|
171
|
+
end
|
|
172
|
+
|
|
194
173
|
def all_argument_definitions
|
|
195
|
-
if
|
|
174
|
+
if @resolver_class
|
|
196
175
|
all_defns = {}
|
|
197
176
|
@resolver_class.all_field_argument_definitions.each do |arg_defn|
|
|
198
177
|
key = arg_defn.graphql_name
|
|
@@ -224,7 +203,7 @@ module GraphQL
|
|
|
224
203
|
end
|
|
225
204
|
|
|
226
205
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
|
227
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
|
206
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
|
228
207
|
warden = Warden.from_context(context)
|
|
229
208
|
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
|
230
209
|
visible_arg
|
|
@@ -247,8 +226,8 @@ module GraphQL
|
|
|
247
226
|
#
|
|
248
227
|
# @param values [Hash<String, Object>]
|
|
249
228
|
# @param context [GraphQL::Query::Context]
|
|
250
|
-
# @yield [Interpreter::Arguments, Execution::Lazy<
|
|
251
|
-
# @return [Interpreter::Arguments, Execution::Lazy<
|
|
229
|
+
# @yield [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
|
|
230
|
+
# @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
|
|
252
231
|
def coerce_arguments(parent_object, values, context, &block)
|
|
253
232
|
# Cache this hash to avoid re-merging it
|
|
254
233
|
arg_defns = context.warden.arguments(self)
|
|
@@ -367,41 +346,52 @@ module GraphQL
|
|
|
367
346
|
def authorize_application_object(argument, id, context, loaded_application_object)
|
|
368
347
|
context.query.after_lazy(loaded_application_object) do |application_object|
|
|
369
348
|
if application_object.nil?
|
|
370
|
-
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
|
371
|
-
load_application_object_failed(err)
|
|
349
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
|
350
|
+
application_object = load_application_object_failed(err)
|
|
372
351
|
end
|
|
373
352
|
# Double-check that the located object is actually of this type
|
|
374
353
|
# (Don't want to allow arbitrary access to objects this way)
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
354
|
+
if application_object.nil?
|
|
355
|
+
nil
|
|
356
|
+
else
|
|
357
|
+
maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
|
|
358
|
+
context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
|
|
359
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
|
360
|
+
application_object_type, application_object = resolve_type_result
|
|
361
|
+
else
|
|
362
|
+
application_object_type = resolve_type_result
|
|
363
|
+
# application_object is already assigned
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
if !(
|
|
367
|
+
context.warden.possible_types(argument.loads).include?(application_object_type) ||
|
|
368
|
+
context.warden.loadable?(argument.loads, context)
|
|
369
|
+
)
|
|
370
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
|
371
|
+
application_object = load_application_object_failed(err)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
if application_object.nil?
|
|
375
|
+
nil
|
|
376
|
+
else
|
|
377
|
+
# This object was loaded successfully
|
|
378
|
+
# and resolved to the right type,
|
|
379
|
+
# now apply the `.authorized?` class method if there is one
|
|
380
|
+
context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
|
|
381
|
+
if authed
|
|
382
|
+
application_object
|
|
403
383
|
else
|
|
404
|
-
|
|
384
|
+
err = GraphQL::UnauthorizedError.new(
|
|
385
|
+
object: application_object,
|
|
386
|
+
type: application_object_type,
|
|
387
|
+
context: context,
|
|
388
|
+
)
|
|
389
|
+
if self.respond_to?(:unauthorized_object)
|
|
390
|
+
err.set_backtrace(caller)
|
|
391
|
+
unauthorized_object(err)
|
|
392
|
+
else
|
|
393
|
+
raise err
|
|
394
|
+
end
|
|
405
395
|
end
|
|
406
396
|
end
|
|
407
397
|
end
|
|
@@ -91,7 +91,7 @@ module GraphQL
|
|
|
91
91
|
private
|
|
92
92
|
|
|
93
93
|
# Modify `target` by adding items from `dirs` such that:
|
|
94
|
-
# - Any name conflict is
|
|
94
|
+
# - Any name conflict is overridden by the incoming member of `dirs`
|
|
95
95
|
# - Any other member of `dirs` is appended
|
|
96
96
|
# @param target [Array<GraphQL::Schema::Directive>]
|
|
97
97
|
# @param dirs [Array<GraphQL::Schema::Directive>]
|
|
@@ -97,7 +97,7 @@ module GraphQL
|
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
module InterfaceMethods
|
|
100
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
|
100
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
|
101
101
|
warden = Warden.from_context(context)
|
|
102
102
|
for ancestor in ancestors
|
|
103
103
|
if ancestor.respond_to?(:own_fields) &&
|
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
|
113
|
-
def fields(context = GraphQL::Query::NullContext)
|
|
113
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
|
114
114
|
warden = Warden.from_context(context)
|
|
115
115
|
# Local overrides take precedence over inherited fields
|
|
116
116
|
visible_fields = {}
|
|
@@ -130,22 +130,25 @@ module GraphQL
|
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
module ObjectMethods
|
|
133
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
|
133
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
|
134
134
|
# Objects need to check that the interface implementation is visible, too
|
|
135
135
|
warden = Warden.from_context(context)
|
|
136
|
-
|
|
136
|
+
ancs = ancestors
|
|
137
|
+
i = 0
|
|
138
|
+
while (ancestor = ancs[i])
|
|
137
139
|
if ancestor.respond_to?(:own_fields) &&
|
|
138
140
|
visible_interface_implementation?(ancestor, context, warden) &&
|
|
139
141
|
(f_entry = ancestor.own_fields[field_name]) &&
|
|
140
142
|
(f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
|
|
141
143
|
return f
|
|
142
144
|
end
|
|
145
|
+
i += 1
|
|
143
146
|
end
|
|
144
147
|
nil
|
|
145
148
|
end
|
|
146
149
|
|
|
147
150
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
|
148
|
-
def fields(context = GraphQL::Query::NullContext)
|
|
151
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
|
149
152
|
# Objects need to check that the interface implementation is visible, too
|
|
150
153
|
warden = Warden.from_context(context)
|
|
151
154
|
# Local overrides take precedence over inherited fields
|
|
@@ -70,11 +70,20 @@ module GraphQL
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
module InheritedInterfaces
|
|
73
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
|
73
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
|
74
74
|
visible_interfaces = super
|
|
75
|
-
|
|
76
|
-
visible_interfaces.
|
|
77
|
-
|
|
75
|
+
inherited_interfaces = superclass.interfaces(context)
|
|
76
|
+
if visible_interfaces.any?
|
|
77
|
+
if inherited_interfaces.any?
|
|
78
|
+
visible_interfaces.concat(inherited_interfaces)
|
|
79
|
+
visible_interfaces.uniq!
|
|
80
|
+
end
|
|
81
|
+
visible_interfaces
|
|
82
|
+
elsif inherited_interfaces.any?
|
|
83
|
+
inherited_interfaces
|
|
84
|
+
else
|
|
85
|
+
EmptyObjects::EMPTY_ARRAY
|
|
86
|
+
end
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
def interface_type_memberships
|
|
@@ -90,25 +99,30 @@ module GraphQL
|
|
|
90
99
|
end
|
|
91
100
|
|
|
92
101
|
# param context [Query::Context] If omitted, skip filtering.
|
|
93
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
|
102
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
|
94
103
|
warden = Warden.from_context(context)
|
|
95
|
-
visible_interfaces =
|
|
104
|
+
visible_interfaces = nil
|
|
96
105
|
own_interface_type_memberships.each do |type_membership|
|
|
97
106
|
case type_membership
|
|
98
107
|
when Schema::TypeMembership
|
|
99
108
|
if warden.visible_type_membership?(type_membership, context)
|
|
109
|
+
visible_interfaces ||= []
|
|
100
110
|
visible_interfaces << type_membership.abstract_type
|
|
101
111
|
end
|
|
102
112
|
when String, Schema::LateBoundType
|
|
103
113
|
# During initialization, `type_memberships` can hold late-bound types
|
|
114
|
+
visible_interfaces ||= []
|
|
104
115
|
visible_interfaces << type_membership
|
|
105
116
|
else
|
|
106
117
|
raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
|
|
107
118
|
end
|
|
108
119
|
end
|
|
109
|
-
visible_interfaces
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
if visible_interfaces
|
|
121
|
+
visible_interfaces.uniq!
|
|
122
|
+
visible_interfaces
|
|
123
|
+
else
|
|
124
|
+
EmptyObjects::EMPTY_ARRAY
|
|
125
|
+
end
|
|
112
126
|
end
|
|
113
127
|
|
|
114
128
|
private
|
|
@@ -76,7 +76,7 @@ module GraphQL
|
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
|
-
# If one of
|
|
79
|
+
# If one of these values is accessed, initialize all the instance variables to retain
|
|
80
80
|
# a consistent object shape.
|
|
81
81
|
def initialize_relay_metadata
|
|
82
82
|
if !defined?(@connection_type)
|