graphql 2.3.7 → 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/field_usage.rb +1 -1
- data/lib/graphql/analysis/query_complexity.rb +3 -3
- data/lib/graphql/analysis/visitor.rb +7 -6
- 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 +29 -25
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/execution/lookahead.rb +10 -10
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- 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 +55 -28
- data/lib/graphql/language/lexer.rb +15 -15
- 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/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +6 -6
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/null_context.rb +2 -2
- data/lib/graphql/query.rb +60 -8
- 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 -2
- 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 +54 -20
- 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 +92 -37
- data/lib/graphql/schema/has_single_input_argument.rb +2 -1
- data/lib/graphql/schema/input_object.rb +27 -13
- data/lib/graphql/schema/interface.rb +21 -4
- data/lib/graphql/schema/introspection_system.rb +5 -16
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +14 -9
- data/lib/graphql/schema/member/has_fields.rb +8 -6
- 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 +7 -9
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/validator.rb +2 -0
- 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 +156 -10
- data/lib/graphql/schema.rb +283 -85
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- 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 +3 -2
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -7
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- 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/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- 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 +11 -2
- data/lib/graphql/static_validation/validation_context.rb +17 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +5 -3
- data/lib/graphql/testing/helpers.rb +9 -5
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +29 -8
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
|
@@ -19,6 +19,10 @@ module GraphQL
|
|
|
19
19
|
PassThruWarden
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
def self.use(schema)
|
|
23
|
+
# no-op
|
|
24
|
+
end
|
|
25
|
+
|
|
22
26
|
# @param visibility_method [Symbol] a Warden method to call for this entry
|
|
23
27
|
# @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
|
|
24
28
|
# @param context [GraphQL::Query::Context]
|
|
@@ -61,21 +65,37 @@ module GraphQL
|
|
|
61
65
|
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
|
62
66
|
def arguments(owner, ctx); owner.arguments(ctx); end
|
|
63
67
|
def loadable?(type, ctx); type.visible?(ctx); end
|
|
68
|
+
def visibility_profile
|
|
69
|
+
@visibility_profile ||= Warden::VisibilityProfile.new(self)
|
|
70
|
+
end
|
|
64
71
|
end
|
|
65
72
|
end
|
|
66
73
|
|
|
67
74
|
class NullWarden
|
|
68
75
|
def initialize(_filter = nil, context:, schema:)
|
|
69
76
|
@schema = schema
|
|
77
|
+
@visibility_profile = Warden::VisibilityProfile.new(self)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# No-op, but for compatibility:
|
|
81
|
+
attr_writer :skip_warning
|
|
82
|
+
|
|
83
|
+
# @api private
|
|
84
|
+
module NullVisibilityProfile
|
|
85
|
+
def self.new(context:, schema:)
|
|
86
|
+
NullWarden.new(context: context, schema: schema).visibility_profile
|
|
87
|
+
end
|
|
70
88
|
end
|
|
71
89
|
|
|
90
|
+
attr_reader :visibility_profile
|
|
91
|
+
|
|
72
92
|
def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
|
|
73
93
|
def visible_argument?(arg_defn, _ctx = nil); true; end
|
|
74
94
|
def visible_type?(type_defn, _ctx = nil); true; end
|
|
75
95
|
def visible_enum_value?(enum_value, _ctx = nil); true; end
|
|
76
96
|
def visible_type_membership?(type_membership, _ctx = nil); true; end
|
|
77
97
|
def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
|
|
78
|
-
def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
|
|
98
|
+
def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
|
|
79
99
|
def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
|
|
80
100
|
def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
|
|
81
101
|
def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
|
|
@@ -87,10 +107,84 @@ module GraphQL
|
|
|
87
107
|
def reachable_type?(type_name); true; end
|
|
88
108
|
def loadable?(type, _ctx); true; end
|
|
89
109
|
def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
|
|
90
|
-
def possible_types(type_defn); @schema.possible_types(type_defn); end
|
|
110
|
+
def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
|
|
91
111
|
def interfaces(obj_type); obj_type.interfaces; end
|
|
92
112
|
end
|
|
93
113
|
|
|
114
|
+
def visibility_profile
|
|
115
|
+
@visibility_profile ||= VisibilityProfile.new(self)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class VisibilityProfile
|
|
119
|
+
def initialize(warden)
|
|
120
|
+
@warden = warden
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def directives
|
|
124
|
+
@warden.directives
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def directive_exists?(dir_name)
|
|
128
|
+
@warden.directives.any? { |d| d.graphql_name == dir_name }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def type(name)
|
|
132
|
+
@warden.get_type(name)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def field(owner, field_name)
|
|
136
|
+
@warden.get_field(owner, field_name)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def argument(owner, arg_name)
|
|
140
|
+
@warden.get_argument(owner, arg_name)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def query_root
|
|
144
|
+
@warden.root_type_for_operation("query")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def mutation_root
|
|
148
|
+
@warden.root_type_for_operation("mutation")
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def subscription_root
|
|
152
|
+
@warden.root_type_for_operation("subscription")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def arguments(owner)
|
|
156
|
+
@warden.arguments(owner)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def fields(owner)
|
|
160
|
+
@warden.fields(owner)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def possible_types(type)
|
|
164
|
+
@warden.possible_types(type)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def enum_values(enum_type)
|
|
168
|
+
@warden.enum_values(enum_type)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def all_types
|
|
172
|
+
@warden.reachable_types
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def interfaces(obj_type)
|
|
176
|
+
@warden.interfaces(obj_type)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def loadable?(t, ctx) # TODO remove ctx here?
|
|
180
|
+
@warden.loadable?(t, ctx)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def reachable_type?(type_name)
|
|
184
|
+
!!@warden.reachable_type?(type_name)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
94
188
|
# @param context [GraphQL::Query::Context]
|
|
95
189
|
# @param schema [GraphQL::Schema]
|
|
96
190
|
def initialize(context:, schema:)
|
|
@@ -100,17 +194,19 @@ module GraphQL
|
|
|
100
194
|
@mutation = @schema.mutation
|
|
101
195
|
@subscription = @schema.subscription
|
|
102
196
|
@context = context
|
|
103
|
-
@visibility_cache = read_through { |m| schema
|
|
104
|
-
@visibility_cache.compare_by_identity
|
|
197
|
+
@visibility_cache = read_through { |m| check_visible(schema, m) }
|
|
105
198
|
# Initialize all ivars to improve object shape consistency:
|
|
106
199
|
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
|
107
200
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
|
108
201
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
|
109
202
|
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
|
110
|
-
@reachable_type_set =
|
|
203
|
+
@reachable_type_set = @visibility_profile =
|
|
111
204
|
nil
|
|
205
|
+
@skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
|
|
112
206
|
end
|
|
113
207
|
|
|
208
|
+
attr_writer :skip_warning
|
|
209
|
+
|
|
114
210
|
# @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
|
|
115
211
|
def types
|
|
116
212
|
@types ||= begin
|
|
@@ -132,7 +228,7 @@ module GraphQL
|
|
|
132
228
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
|
133
229
|
def get_type(type_name)
|
|
134
230
|
@visible_types ||= read_through do |name|
|
|
135
|
-
type_defn = @schema.get_type(name, @context)
|
|
231
|
+
type_defn = @schema.get_type(name, @context, false)
|
|
136
232
|
if type_defn && visible_and_reachable_type?(type_defn)
|
|
137
233
|
type_defn
|
|
138
234
|
else
|
|
@@ -179,7 +275,7 @@ module GraphQL
|
|
|
179
275
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
|
180
276
|
def possible_types(type_defn)
|
|
181
277
|
@visible_possible_types ||= read_through { |type_defn|
|
|
182
|
-
pt = @schema.possible_types(type_defn, @context)
|
|
278
|
+
pt = @schema.possible_types(type_defn, @context, false)
|
|
183
279
|
pt.select { |t| visible_and_reachable_type?(t) }
|
|
184
280
|
}
|
|
185
281
|
@visible_possible_types[type_defn]
|
|
@@ -376,11 +472,61 @@ module GraphQL
|
|
|
376
472
|
end
|
|
377
473
|
|
|
378
474
|
def read_through
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
475
|
+
Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def check_visible(schema, member)
|
|
479
|
+
if schema.visible?(member, @context)
|
|
480
|
+
true
|
|
481
|
+
elsif @skip_warning
|
|
482
|
+
false
|
|
483
|
+
else
|
|
484
|
+
member_s = member.respond_to?(:path) ? member.path : member.inspect
|
|
485
|
+
member_type = case member
|
|
486
|
+
when Module
|
|
487
|
+
if member.respond_to?(:kind)
|
|
488
|
+
member.kind.name.downcase
|
|
489
|
+
else
|
|
490
|
+
""
|
|
491
|
+
end
|
|
492
|
+
when GraphQL::Schema::Field
|
|
493
|
+
"field"
|
|
494
|
+
when GraphQL::Schema::EnumValue
|
|
495
|
+
"enum value"
|
|
496
|
+
when GraphQL::Schema::Argument
|
|
497
|
+
"argument"
|
|
498
|
+
else
|
|
499
|
+
""
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
schema_s = schema.name ? "#{schema.name}'s" : ""
|
|
503
|
+
schema_name = schema.name ? "#{schema.name}" : "your schema"
|
|
504
|
+
warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
|
|
505
|
+
@skip_warning = true # only warn once per query
|
|
506
|
+
# If there's no schema name, add the backtrace for additional context:
|
|
507
|
+
if schema_s == ""
|
|
508
|
+
puts caller.map { |l| " #{l}"}
|
|
509
|
+
end
|
|
510
|
+
false
|
|
511
|
+
end
|
|
382
512
|
end
|
|
383
513
|
|
|
514
|
+
ADD_WARDEN_WARNING = <<~WARNING
|
|
515
|
+
DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
|
|
516
|
+
|
|
517
|
+
Address this warning by adding:
|
|
518
|
+
|
|
519
|
+
use GraphQL::Schema::Visibility
|
|
520
|
+
|
|
521
|
+
to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
|
|
522
|
+
|
|
523
|
+
Alternatively, for legacy behavior, add:
|
|
524
|
+
|
|
525
|
+
use GraphQL::Schema::Warden # legacy visibility behavior
|
|
526
|
+
|
|
527
|
+
For more information see: https://graphql-ruby.org/authorization/visibility.html
|
|
528
|
+
WARNING
|
|
529
|
+
|
|
384
530
|
def reachable_type_set
|
|
385
531
|
return @reachable_type_set if @reachable_type_set
|
|
386
532
|
|