graphql 2.3.8 → 2.4.0
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_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis.rb +1 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +6 -3
- data/lib/graphql/dataloader.rb +35 -11
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +10 -6
- data/lib/graphql/execution/interpreter/runtime.rb +23 -19
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +4 -19
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +38 -4
- data/lib/graphql/language/lexer.rb +15 -12
- data/lib/graphql/language/nodes.rb +24 -16
- data/lib/graphql/language/parser.rb +14 -1
- data/lib/graphql/language/printer.rb +23 -7
- data/lib/graphql/language.rb +6 -5
- data/lib/graphql/query/context.rb +4 -2
- data/lib/graphql/query/null_context.rb +1 -5
- data/lib/graphql/query.rb +49 -20
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +1 -0
- data/lib/graphql/schema/always_visible.rb +6 -3
- data/lib/graphql/schema/argument.rb +14 -1
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/enum.rb +49 -15
- data/lib/graphql/schema/enum_value.rb +9 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +91 -36
- data/lib/graphql/schema/input_object.rb +20 -7
- data/lib/graphql/schema/interface.rb +21 -4
- data/lib/graphql/schema/introspection_system.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +9 -5
- data/lib/graphql/schema/member/has_fields.rb +5 -5
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/resolver.rb +3 -4
- data/lib/graphql/schema/validator/all_validator.rb +2 -0
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/visibility/migration.rb +186 -0
- data/lib/graphql/schema/visibility/profile.rb +523 -0
- data/lib/graphql/schema/visibility.rb +75 -0
- data/lib/graphql/schema/warden.rb +80 -21
- data/lib/graphql/schema.rb +254 -85
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
- data/lib/graphql/static_validation/validation_context.rb +15 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions.rb +3 -1
- data/lib/graphql/testing/helpers.rb +7 -3
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +28 -7
- data/lib/graphql/schema/subset.rb +0 -397
|
@@ -50,12 +50,27 @@ module GraphQL
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# Call this method to provide a new comment; OR
|
|
54
|
+
# call it without an argument to get the comment
|
|
55
|
+
# @param new_comment [String]
|
|
56
|
+
# @return [String, nil]
|
|
57
|
+
def comment(new_comment = NOT_CONFIGURED)
|
|
58
|
+
if !NOT_CONFIGURED.equal?(new_comment)
|
|
59
|
+
@comment = new_comment
|
|
60
|
+
elsif defined?(@comment)
|
|
61
|
+
@comment
|
|
62
|
+
else
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
53
67
|
# This pushes some configurations _down_ the inheritance tree,
|
|
54
68
|
# in order to prevent repetitive lookups at runtime.
|
|
55
69
|
module ConfigurationExtension
|
|
56
70
|
def inherited(child_class)
|
|
57
71
|
child_class.introspection(introspection)
|
|
58
72
|
child_class.description(description)
|
|
73
|
+
child_class.comment(nil)
|
|
59
74
|
child_class.default_graphql_name = nil
|
|
60
75
|
|
|
61
76
|
if defined?(@graphql_name) && @graphql_name && (self.name.nil? || graphql_name != default_graphql_name)
|
|
@@ -135,7 +135,7 @@ module GraphQL
|
|
|
135
135
|
|
|
136
136
|
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
|
137
137
|
warden = Warden.from_context(context)
|
|
138
|
-
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::
|
|
138
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
|
|
139
139
|
for ancestor in ancestors
|
|
140
140
|
if ancestor.respond_to?(:own_arguments) &&
|
|
141
141
|
(a = ancestor.own_arguments[argument_name]) &&
|
|
@@ -198,15 +198,19 @@ module GraphQL
|
|
|
198
198
|
end
|
|
199
199
|
|
|
200
200
|
def all_argument_definitions
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
if own_arguments.any?
|
|
202
|
+
all_defns = own_arguments.values
|
|
203
|
+
all_defns.flatten!
|
|
204
|
+
all_defns
|
|
205
|
+
else
|
|
206
|
+
EmptyObjects::EMPTY_ARRAY
|
|
207
|
+
end
|
|
204
208
|
end
|
|
205
209
|
|
|
206
210
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
|
207
211
|
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
|
208
212
|
warden = Warden.from_context(context)
|
|
209
|
-
if (arg_config = own_arguments[argument_name]) && ((context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::
|
|
213
|
+
if (arg_config = own_arguments[argument_name]) && ((context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)) || (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden)))
|
|
210
214
|
visible_arg || arg_config
|
|
211
215
|
elsif defined?(@resolver_class) && @resolver_class
|
|
212
216
|
@resolver_class.get_field_argument(argument_name, context)
|
|
@@ -99,7 +99,7 @@ module GraphQL
|
|
|
99
99
|
module InterfaceMethods
|
|
100
100
|
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
|
101
101
|
warden = Warden.from_context(context)
|
|
102
|
-
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::
|
|
102
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
|
|
103
103
|
for ancestor in ancestors
|
|
104
104
|
if ancestor.respond_to?(:own_fields) &&
|
|
105
105
|
(f_entry = ancestor.own_fields[field_name]) &&
|
|
@@ -121,7 +121,7 @@ module GraphQL
|
|
|
121
121
|
# Choose the most local definition that passes `.visible?` --
|
|
122
122
|
# stop checking for fields by name once one has been found.
|
|
123
123
|
if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
|
|
124
|
-
visible_fields[field_name] = f
|
|
124
|
+
visible_fields[field_name] = f.ensure_loaded
|
|
125
125
|
end
|
|
126
126
|
end
|
|
127
127
|
end
|
|
@@ -135,14 +135,14 @@ module GraphQL
|
|
|
135
135
|
# Objects need to check that the interface implementation is visible, too
|
|
136
136
|
warden = Warden.from_context(context)
|
|
137
137
|
ancs = ancestors
|
|
138
|
-
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::
|
|
138
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
|
|
139
139
|
i = 0
|
|
140
140
|
while (ancestor = ancs[i])
|
|
141
141
|
if ancestor.respond_to?(:own_fields) &&
|
|
142
142
|
visible_interface_implementation?(ancestor, context, warden) &&
|
|
143
143
|
(f_entry = ancestor.own_fields[field_name]) &&
|
|
144
144
|
(skip_visible || (f_entry = Warden.visible_entry?(:visible_field?, f_entry, context, warden)))
|
|
145
|
-
return f_entry
|
|
145
|
+
return (skip_visible ? f_entry : f_entry.ensure_loaded)
|
|
146
146
|
end
|
|
147
147
|
i += 1
|
|
148
148
|
end
|
|
@@ -161,7 +161,7 @@ module GraphQL
|
|
|
161
161
|
# Choose the most local definition that passes `.visible?` --
|
|
162
162
|
# stop checking for fields by name once one has been found.
|
|
163
163
|
if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
|
|
164
|
-
visible_fields[field_name] = f
|
|
164
|
+
visible_fields[field_name] = f.ensure_loaded
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
end
|
|
@@ -7,7 +7,11 @@ module GraphQL
|
|
|
7
7
|
module HasUnresolvedTypeError
|
|
8
8
|
private
|
|
9
9
|
def add_unresolved_type_error(child_class)
|
|
10
|
-
child_class.
|
|
10
|
+
if child_class.name # Don't set this for anonymous classes
|
|
11
|
+
child_class.const_set(:UnresolvedTypeError, Class.new(GraphQL::UnresolvedTypeError))
|
|
12
|
+
else
|
|
13
|
+
child_class.const_set(:UnresolvedTypeError, UnresolvedTypeError)
|
|
14
|
+
end
|
|
11
15
|
end
|
|
12
16
|
end
|
|
13
17
|
end
|
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
|
8
8
|
# - Arguments, via `.argument(...)` helper, which will be applied to the field.
|
|
9
9
|
# - Return type, via `.type(..., null: ...)`, which will be applied to the field.
|
|
10
10
|
# - Description, via `.description(...)`, which will be applied to the field
|
|
11
|
+
# - Comment, via `.comment(...)`, which will be applied to the field
|
|
11
12
|
# - Resolution, via `#resolve(**args)` method, which will be called to resolve the field.
|
|
12
13
|
# - `#object` and `#context` accessors for use during `#resolve`.
|
|
13
14
|
#
|
|
@@ -19,7 +20,7 @@ module GraphQL
|
|
|
19
20
|
# @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
|
|
20
21
|
class Resolver
|
|
21
22
|
include Schema::Member::GraphQLTypeNames
|
|
22
|
-
# Really we only need description from here, but:
|
|
23
|
+
# Really we only need description & comment from here, but:
|
|
23
24
|
extend Schema::Member::BaseDSLMethods
|
|
24
25
|
extend GraphQL::Schema::Member::HasArguments
|
|
25
26
|
extend GraphQL::Schema::Member::HasValidators
|
|
@@ -408,9 +409,7 @@ module GraphQL
|
|
|
408
409
|
|
|
409
410
|
private
|
|
410
411
|
|
|
411
|
-
|
|
412
|
-
@own_extensions
|
|
413
|
-
end
|
|
412
|
+
attr_reader :own_extensions
|
|
414
413
|
end
|
|
415
414
|
end
|
|
416
415
|
end
|
|
@@ -35,9 +35,10 @@ module GraphQL
|
|
|
35
35
|
# end
|
|
36
36
|
#
|
|
37
37
|
class RequiredValidator < Validator
|
|
38
|
-
# @param one_of [
|
|
38
|
+
# @param one_of [Array<Symbol>] A list of arguments, exactly one of which is required for this field
|
|
39
|
+
# @param argument [Symbol] An argument that is required for this field
|
|
39
40
|
# @param message [String]
|
|
40
|
-
def initialize(one_of: nil, argument: nil, message:
|
|
41
|
+
def initialize(one_of: nil, argument: nil, message: nil, **default_options)
|
|
41
42
|
@one_of = if one_of
|
|
42
43
|
one_of
|
|
43
44
|
elsif argument
|
|
@@ -49,7 +50,7 @@ module GraphQL
|
|
|
49
50
|
super(**default_options)
|
|
50
51
|
end
|
|
51
52
|
|
|
52
|
-
def validate(_object,
|
|
53
|
+
def validate(_object, context, value)
|
|
53
54
|
matched_conditions = 0
|
|
54
55
|
|
|
55
56
|
if !value.nil?
|
|
@@ -73,9 +74,32 @@ module GraphQL
|
|
|
73
74
|
if matched_conditions == 1
|
|
74
75
|
nil # OK
|
|
75
76
|
else
|
|
76
|
-
@message
|
|
77
|
+
@message || build_message(context)
|
|
77
78
|
end
|
|
78
79
|
end
|
|
80
|
+
|
|
81
|
+
def build_message(context)
|
|
82
|
+
argument_definitions = @validated.arguments(context).values
|
|
83
|
+
required_names = @one_of.map do |arg_keyword|
|
|
84
|
+
if arg_keyword.is_a?(Array)
|
|
85
|
+
names = arg_keyword.map { |arg| arg_keyword_to_grapqhl_name(argument_definitions, arg) }
|
|
86
|
+
"(" + names.join(" and ") + ")"
|
|
87
|
+
else
|
|
88
|
+
arg_keyword_to_grapqhl_name(argument_definitions, arg_keyword)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if required_names.size == 1
|
|
93
|
+
"%{validated} must include the following argument: #{required_names.first}."
|
|
94
|
+
else
|
|
95
|
+
"%{validated} must include exactly one of the following arguments: #{required_names.join(", ")}."
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def arg_keyword_to_grapqhl_name(argument_definitions, arg_keyword)
|
|
100
|
+
argument_definition = argument_definitions.find { |defn| defn.keyword == arg_keyword }
|
|
101
|
+
argument_definition.graphql_name
|
|
102
|
+
end
|
|
79
103
|
end
|
|
80
104
|
end
|
|
81
105
|
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
class Schema
|
|
4
|
+
class Visibility
|
|
5
|
+
# You can use this to see how {GraphQL::Schema::Warden} and {GraphQL::Schema::Visibility::Profile}
|
|
6
|
+
# handle `.visible?` differently in your schema.
|
|
7
|
+
#
|
|
8
|
+
# It runs the same method on both implementations and raises an error when the results diverge.
|
|
9
|
+
#
|
|
10
|
+
# To fix the error, modify your schema so that both implementations return the same thing.
|
|
11
|
+
# Or, open an issue on GitHub to discuss the difference.
|
|
12
|
+
#
|
|
13
|
+
# This plugin adds overhead to runtime and may cause unexpected crashes -- **don't** use it in production!
|
|
14
|
+
#
|
|
15
|
+
# This plugin adds two keys to `context` when running:
|
|
16
|
+
#
|
|
17
|
+
# - `visibility_migration_running: true`
|
|
18
|
+
# - For the {Schema::Warden} which it instantiates, it adds `visibility_migration_warden_running: true`.
|
|
19
|
+
#
|
|
20
|
+
# Use those keys to modify your `visible?` behavior as needed.
|
|
21
|
+
#
|
|
22
|
+
# Also, in a pinch, you can set `skip_visibility_migration_error: true` in context to turn off this behavior per-query.
|
|
23
|
+
# (In that case, it uses {Profile} directly.)
|
|
24
|
+
#
|
|
25
|
+
# @example Adding this plugin
|
|
26
|
+
#
|
|
27
|
+
# use GraphQL::Schema::Visibility, migration_errors: true
|
|
28
|
+
#
|
|
29
|
+
class Migration < GraphQL::Schema::Visibility::Profile
|
|
30
|
+
class RuntimeTypesMismatchError < GraphQL::Error
|
|
31
|
+
def initialize(method_called, warden_result, profile_result, method_args)
|
|
32
|
+
super(<<~ERR)
|
|
33
|
+
Mismatch in types for `##{method_called}(#{method_args.map(&:inspect).join(", ")})`:
|
|
34
|
+
|
|
35
|
+
#{compare_results(warden_result, profile_result)}
|
|
36
|
+
|
|
37
|
+
Update your `.visible?` implementation to make these implementations return the same value.
|
|
38
|
+
|
|
39
|
+
See: https://graphql-ruby.org/authorization/visibility_migration.html
|
|
40
|
+
ERR
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
def compare_results(warden_result, profile_result)
|
|
45
|
+
if warden_result.is_a?(Array) && profile_result.is_a?(Array)
|
|
46
|
+
all_results = warden_result | profile_result
|
|
47
|
+
all_results.sort_by!(&:graphql_name)
|
|
48
|
+
|
|
49
|
+
entries_text = all_results.map { |entry| "#{entry.graphql_name} (#{entry})"}
|
|
50
|
+
width = entries_text.map(&:size).max
|
|
51
|
+
yes = " ✔ "
|
|
52
|
+
no = " "
|
|
53
|
+
res = "".dup
|
|
54
|
+
res << "#{"Result".center(width)} Warden Profile \n"
|
|
55
|
+
all_results.each_with_index do |entry, idx|
|
|
56
|
+
res << "#{entries_text[idx].ljust(width)}#{warden_result.include?(entry) ? yes : no}#{profile_result.include?(entry) ? yes : no}\n"
|
|
57
|
+
end
|
|
58
|
+
res << "\n"
|
|
59
|
+
else
|
|
60
|
+
"- Warden returned: #{humanize(warden_result)}\n\n- Visibility::Profile returned: #{humanize(profile_result)}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
def humanize(val)
|
|
64
|
+
case val
|
|
65
|
+
when Array
|
|
66
|
+
"#{val.size}: #{val.map { |v| humanize(v) }.sort.inspect}"
|
|
67
|
+
when Module
|
|
68
|
+
if val.respond_to?(:graphql_name)
|
|
69
|
+
"#{val.graphql_name} (#{val.inspect})"
|
|
70
|
+
else
|
|
71
|
+
val.inspect
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
val.inspect
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def initialize(context:, schema:, name: nil)
|
|
80
|
+
@name = name
|
|
81
|
+
@skip_error = context[:skip_visibility_migration_error] || context.is_a?(Query::NullContext) || context.is_a?(Hash)
|
|
82
|
+
@profile_types = GraphQL::Schema::Visibility::Profile.new(context: context, schema: schema)
|
|
83
|
+
if !@skip_error
|
|
84
|
+
context[:visibility_migration_running] = true
|
|
85
|
+
warden_ctx_vals = context.to_h.dup
|
|
86
|
+
warden_ctx_vals[:visibility_migration_warden_running] = true
|
|
87
|
+
if schema.const_defined?(:WardenCompatSchema, false) # don't use a defn from a superclass
|
|
88
|
+
warden_schema = schema.const_get(:WardenCompatSchema, false)
|
|
89
|
+
else
|
|
90
|
+
warden_schema = Class.new(schema)
|
|
91
|
+
warden_schema.use_visibility_profile = false
|
|
92
|
+
# TODO public API
|
|
93
|
+
warden_schema.send(:add_type_and_traverse, [warden_schema.query, warden_schema.mutation, warden_schema.subscription].compact, root: true)
|
|
94
|
+
warden_schema.send(:add_type_and_traverse, warden_schema.directives.values + warden_schema.orphan_types, root: false)
|
|
95
|
+
schema.const_set(:WardenCompatSchema, warden_schema)
|
|
96
|
+
end
|
|
97
|
+
warden_ctx = GraphQL::Query::Context.new(query: context.query, values: warden_ctx_vals)
|
|
98
|
+
warden_ctx.warden = GraphQL::Schema::Warden.new(schema: warden_schema, context: warden_ctx)
|
|
99
|
+
warden_ctx.warden.skip_warning = true
|
|
100
|
+
warden_ctx.types = @warden_types = warden_ctx.warden.visibility_profile
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def loaded_types
|
|
105
|
+
@profile_types.loaded_types
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
PUBLIC_PROFILE_METHODS = [
|
|
109
|
+
:enum_values,
|
|
110
|
+
:interfaces,
|
|
111
|
+
:all_types,
|
|
112
|
+
:all_types_h,
|
|
113
|
+
:fields,
|
|
114
|
+
:loadable?,
|
|
115
|
+
:type,
|
|
116
|
+
:arguments,
|
|
117
|
+
:argument,
|
|
118
|
+
:directive_exists?,
|
|
119
|
+
:directives,
|
|
120
|
+
:field,
|
|
121
|
+
:query_root,
|
|
122
|
+
:mutation_root,
|
|
123
|
+
:possible_types,
|
|
124
|
+
:subscription_root,
|
|
125
|
+
:reachable_type?
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
PUBLIC_PROFILE_METHODS.each do |profile_method|
|
|
129
|
+
define_method(profile_method) do |*args|
|
|
130
|
+
call_method_and_compare(profile_method, args)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def call_method_and_compare(method, args)
|
|
135
|
+
res_1 = @profile_types.public_send(method, *args)
|
|
136
|
+
if @skip_error
|
|
137
|
+
return res_1
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
res_2 = @warden_types.public_send(method, *args)
|
|
141
|
+
normalized_res_1 = res_1.is_a?(Array) ? Set.new(res_1) : res_1
|
|
142
|
+
normalized_res_2 = res_2.is_a?(Array) ? Set.new(res_2) : res_2
|
|
143
|
+
if !equivalent_schema_members?(normalized_res_1, normalized_res_2)
|
|
144
|
+
# Raise the errors with the orignally returned values:
|
|
145
|
+
err = RuntimeTypesMismatchError.new(method, res_2, res_1, args)
|
|
146
|
+
raise err
|
|
147
|
+
else
|
|
148
|
+
res_1
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def equivalent_schema_members?(member1, member2)
|
|
153
|
+
if member1.class != member2.class
|
|
154
|
+
return false
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
case member1
|
|
158
|
+
when Set
|
|
159
|
+
member1_array = member1.to_a.sort_by(&:graphql_name)
|
|
160
|
+
member2_array = member2.to_a.sort_by(&:graphql_name)
|
|
161
|
+
member1_array.each_with_index do |inner_member1, idx|
|
|
162
|
+
inner_member2 = member2_array[idx]
|
|
163
|
+
equivalent_schema_members?(inner_member1, inner_member2)
|
|
164
|
+
end
|
|
165
|
+
when GraphQL::Schema::Field
|
|
166
|
+
member1.ensure_loaded
|
|
167
|
+
member2.ensure_loaded
|
|
168
|
+
if member1.introspection? && member2.introspection?
|
|
169
|
+
member1.inspect == member2.inspect
|
|
170
|
+
else
|
|
171
|
+
member1 == member2
|
|
172
|
+
end
|
|
173
|
+
when Module
|
|
174
|
+
if member1.introspection? && member2.introspection?
|
|
175
|
+
member1.graphql_name == member2.graphql_name
|
|
176
|
+
else
|
|
177
|
+
member1 == member2
|
|
178
|
+
end
|
|
179
|
+
else
|
|
180
|
+
member1 == member2
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|