graphql 2.3.18 → 2.3.20
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/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +1 -1
- data/lib/graphql/dataloader.rb +31 -10
- data/lib/graphql/query/null_context.rb +1 -1
- data/lib/graphql/query.rb +49 -16
- data/lib/graphql/schema/always_visible.rb +6 -3
- data/lib/graphql/schema/argument.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +1 -0
- data/lib/graphql/schema/enum.rb +2 -0
- data/lib/graphql/schema/input_object.rb +20 -7
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/visibility/migration.rb +31 -34
- data/lib/graphql/schema/visibility/{subset.rb → profile.rb} +31 -17
- data/lib/graphql/schema/visibility.rb +57 -12
- data/lib/graphql/schema/warden.rb +14 -14
- data/lib/graphql/schema.rb +163 -41
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
- data/lib/graphql/testing/helpers.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
@@ -11,26 +11,28 @@ module GraphQL
|
|
11
11
|
# - It doesn't use {Schema}'s top-level caches (eg {Schema.references_to}, {Schema.possible_types}, {Schema.types})
|
12
12
|
# - It doesn't hide Interface or Union types when all their possible types are hidden. (Instead, those types should implement `.visible?` to hide in that case.)
|
13
13
|
# - It checks `.visible?` on root introspection types
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
# @return [Schema::Visibility::Subset]
|
14
|
+
# - It can be used to cache profiles by name for re-use across queries
|
15
|
+
class Profile
|
16
|
+
# @return [Schema::Visibility::Profile]
|
18
17
|
def self.from_context(ctx, schema)
|
19
18
|
if ctx.respond_to?(:types) && (types = ctx.types).is_a?(self)
|
20
19
|
types
|
21
20
|
else
|
22
|
-
|
23
|
-
self.new(context: ctx, schema: schema)
|
21
|
+
schema.visibility.profile_for(ctx, nil)
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
25
|
def self.pass_thru(context:, schema:)
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
profile = self.new(context: context, schema: schema)
|
27
|
+
profile.instance_variable_set(:@cached_visible, Hash.new { |h,k| h[k] = true })
|
28
|
+
profile
|
31
29
|
end
|
32
30
|
|
33
|
-
|
31
|
+
# @return [Symbol, nil]
|
32
|
+
attr_reader :name
|
33
|
+
|
34
|
+
def initialize(name: nil, context:, schema:)
|
35
|
+
@name = name
|
34
36
|
@context = context
|
35
37
|
@schema = schema
|
36
38
|
@all_types = {}
|
@@ -67,6 +69,7 @@ module GraphQL
|
|
67
69
|
@cached_visible_arguments = Hash.new do |h, arg|
|
68
70
|
h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
|
69
71
|
add_type(arg_type, arg)
|
72
|
+
arg.validate_default_value
|
70
73
|
true
|
71
74
|
else
|
72
75
|
false
|
@@ -403,8 +406,9 @@ module GraphQL
|
|
403
406
|
|
404
407
|
@unfiltered_interface_type_memberships = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
405
408
|
@add_possible_types = Set.new
|
409
|
+
@late_types = []
|
406
410
|
|
407
|
-
while @unvisited_types.any?
|
411
|
+
while @unvisited_types.any? || @late_types.any?
|
408
412
|
while t = @unvisited_types.pop
|
409
413
|
# These have already been checked for `.visible?`
|
410
414
|
visit_type(t)
|
@@ -418,6 +422,12 @@ module GraphQL
|
|
418
422
|
end
|
419
423
|
end
|
420
424
|
@add_possible_types.clear
|
425
|
+
|
426
|
+
while (union_tm = @late_types.shift)
|
427
|
+
late_obj_t = union_tm.object_type
|
428
|
+
obj_t = @all_types[late_obj_t.graphql_name] || raise("Failed to resolve #{late_obj_t.graphql_name.inspect} from #{union_tm.inspect}")
|
429
|
+
union_tm.abstract_type.assign_type_membership_object_type(obj_t)
|
430
|
+
end
|
421
431
|
end
|
422
432
|
|
423
433
|
@all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
|
@@ -470,12 +480,16 @@ module GraphQL
|
|
470
480
|
type.type_memberships.each do |tm|
|
471
481
|
if @cached_visible[tm]
|
472
482
|
obj_t = tm.object_type
|
473
|
-
if obj_t.is_a?(
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
483
|
+
if obj_t.is_a?(GraphQL::Schema::LateBoundType)
|
484
|
+
@late_types << tm
|
485
|
+
else
|
486
|
+
if obj_t.is_a?(String)
|
487
|
+
obj_t = Member::BuildType.constantize(obj_t)
|
488
|
+
tm.object_type = obj_t
|
489
|
+
end
|
490
|
+
if @cached_visible[obj_t]
|
491
|
+
add_type(obj_t, tm)
|
492
|
+
end
|
479
493
|
end
|
480
494
|
end
|
481
495
|
end
|
@@ -1,28 +1,73 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "graphql/schema/visibility/
|
2
|
+
require "graphql/schema/visibility/profile"
|
3
3
|
require "graphql/schema/visibility/migration"
|
4
4
|
|
5
5
|
module GraphQL
|
6
6
|
class Schema
|
7
|
+
# Use this plugin to make some parts of your schema hidden from some viewers.
|
8
|
+
#
|
7
9
|
class Visibility
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
# @param schema [Class<GraphQL::Schema>]
|
11
|
+
# @param profiles [Hash<Symbol => Hash>] A hash of `name => context` pairs for preloading visibility profiles
|
12
|
+
# @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?`)
|
13
|
+
# @param migration_errors [Boolean] if `true`, raise an error when `Visibility` and `Warden` return different results
|
14
|
+
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails) ? Rails.env.production? : nil), migration_errors: false)
|
15
|
+
schema.visibility = self.new(schema, dynamic: dynamic, preload: preload, profiles: profiles, migration_errors: migration_errors)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(schema, dynamic:, preload:, profiles:, migration_errors:)
|
19
|
+
@schema = schema
|
20
|
+
schema.use_visibility_profile = true
|
11
21
|
if migration_errors
|
12
|
-
schema.
|
22
|
+
schema.visibility_profile_class = Migration
|
23
|
+
end
|
24
|
+
@profiles = profiles
|
25
|
+
@cached_profiles = {}
|
26
|
+
@dynamic = dynamic
|
27
|
+
@migration_errors = migration_errors
|
28
|
+
if preload
|
29
|
+
profiles.each do |profile_name, example_ctx|
|
30
|
+
example_ctx[:visibility_profile] = profile_name
|
31
|
+
prof = profile_for(example_ctx, profile_name)
|
32
|
+
prof.all_types # force loading
|
33
|
+
end
|
13
34
|
end
|
14
35
|
end
|
15
36
|
|
16
|
-
|
17
|
-
|
18
|
-
|
37
|
+
# Make another Visibility for `schema` based on this one
|
38
|
+
# @return [Visibility]
|
39
|
+
# @api private
|
40
|
+
def dup_for(other_schema)
|
41
|
+
self.class.new(
|
42
|
+
other_schema,
|
43
|
+
dynamic: @dynamic,
|
44
|
+
preload: @preload,
|
45
|
+
profiles: @profiles,
|
46
|
+
migration_errors: @migration_errors
|
47
|
+
)
|
48
|
+
end
|
19
49
|
|
20
|
-
|
21
|
-
|
22
|
-
|
50
|
+
def migration_errors?
|
51
|
+
@migration_errors
|
52
|
+
end
|
23
53
|
|
24
|
-
|
54
|
+
attr_reader :cached_profiles
|
25
55
|
|
56
|
+
def profile_for(context, visibility_profile)
|
57
|
+
if @profiles.any?
|
58
|
+
if visibility_profile.nil?
|
59
|
+
if @dynamic
|
60
|
+
@schema.visibility_profile_class.new(context: context, schema: @schema)
|
61
|
+
elsif @profiles.any?
|
62
|
+
raise ArgumentError, "#{@schema} expects a visibility profile, but `visibility_profile:` wasn't passed. Provide a `visibility_profile:` value or add `dynamic: true` to your visibility configuration."
|
63
|
+
end
|
64
|
+
elsif !@profiles.include?(visibility_profile)
|
65
|
+
raise ArgumentError, "`#{visibility_profile.inspect}` isn't allowed for `visibility_profile:` (must be one of #{@profiles.keys.map(&:inspect).join(", ")}). Or, add `#{visibility_profile.inspect}` to the list of profiles in the schema definition."
|
66
|
+
else
|
67
|
+
@cached_profiles[visibility_profile] ||= @schema.visibility_profile_class.new(name: visibility_profile, context: context, schema: @schema)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
@schema.visibility_profile_class.new(context: context, schema: @schema)
|
26
71
|
end
|
27
72
|
end
|
28
73
|
end
|
@@ -61,8 +61,8 @@ module GraphQL
|
|
61
61
|
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
62
62
|
def arguments(owner, ctx); owner.arguments(ctx); end
|
63
63
|
def loadable?(type, ctx); type.visible?(ctx); end
|
64
|
-
def
|
65
|
-
@
|
64
|
+
def visibility_profile
|
65
|
+
@visibility_profile ||= Warden::VisibilityProfile.new(self)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
@@ -70,17 +70,17 @@ module GraphQL
|
|
70
70
|
class NullWarden
|
71
71
|
def initialize(_filter = nil, context:, schema:)
|
72
72
|
@schema = schema
|
73
|
-
@
|
73
|
+
@visibility_profile = Warden::VisibilityProfile.new(self)
|
74
74
|
end
|
75
75
|
|
76
76
|
# @api private
|
77
|
-
module
|
77
|
+
module NullVisibilityProfile
|
78
78
|
def self.new(context:, schema:)
|
79
|
-
NullWarden.new(context: context, schema: schema).
|
79
|
+
NullWarden.new(context: context, schema: schema).visibility_profile
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
-
attr_reader :
|
83
|
+
attr_reader :visibility_profile
|
84
84
|
|
85
85
|
def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
|
86
86
|
def visible_argument?(arg_defn, _ctx = nil); true; end
|
@@ -88,7 +88,7 @@ module GraphQL
|
|
88
88
|
def visible_enum_value?(enum_value, _ctx = nil); true; end
|
89
89
|
def visible_type_membership?(type_membership, _ctx = nil); true; end
|
90
90
|
def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
|
91
|
-
def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
|
91
|
+
def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
|
92
92
|
def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
|
93
93
|
def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
|
94
94
|
def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
|
@@ -100,15 +100,15 @@ module GraphQL
|
|
100
100
|
def reachable_type?(type_name); true; end
|
101
101
|
def loadable?(type, _ctx); true; end
|
102
102
|
def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
|
103
|
-
def possible_types(type_defn); @schema.possible_types(type_defn); end
|
103
|
+
def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
|
104
104
|
def interfaces(obj_type); obj_type.interfaces; end
|
105
105
|
end
|
106
106
|
|
107
|
-
def
|
108
|
-
@
|
107
|
+
def visibility_profile
|
108
|
+
@visibility_profile ||= VisibilityProfile.new(self)
|
109
109
|
end
|
110
110
|
|
111
|
-
class
|
111
|
+
class VisibilityProfile
|
112
112
|
def initialize(warden)
|
113
113
|
@warden = warden
|
114
114
|
end
|
@@ -193,7 +193,7 @@ module GraphQL
|
|
193
193
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
194
194
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
195
195
|
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
196
|
-
@reachable_type_set = @
|
196
|
+
@reachable_type_set = @visibility_profile =
|
197
197
|
nil
|
198
198
|
end
|
199
199
|
|
@@ -218,7 +218,7 @@ module GraphQL
|
|
218
218
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
219
219
|
def get_type(type_name)
|
220
220
|
@visible_types ||= read_through do |name|
|
221
|
-
type_defn = @schema.get_type(name, @context)
|
221
|
+
type_defn = @schema.get_type(name, @context, false)
|
222
222
|
if type_defn && visible_and_reachable_type?(type_defn)
|
223
223
|
type_defn
|
224
224
|
else
|
@@ -265,7 +265,7 @@ module GraphQL
|
|
265
265
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
266
266
|
def possible_types(type_defn)
|
267
267
|
@visible_possible_types ||= read_through { |type_defn|
|
268
|
-
pt = @schema.possible_types(type_defn, @context)
|
268
|
+
pt = @schema.possible_types(type_defn, @context, false)
|
269
269
|
pt.select { |t| visible_and_reachable_type?(t) }
|
270
270
|
}
|
271
271
|
@visible_possible_types[type_defn]
|