graphql 2.4.1 → 2.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12a25d94ae9348527390bad889be7c918390c0a1b133735612ac5a80ca0c6633
4
- data.tar.gz: de4bb61a31dc643d359157dff498410f70a5a7bd18d6c254463a2a5294706949
3
+ metadata.gz: 0dcc846071132cf2d084ff65347dab7c97d0b25b60c1cdb6dfcbe37c55f278e9
4
+ data.tar.gz: afc95cb5ba89e33974b8b38616bc36c14dcbfd3c9f121b8e65437e7cfc390770
5
5
  SHA512:
6
- metadata.gz: f85c5a5e4ab0083862c990fe6cd3f0ed99d36a414721d4c3d0a7a3e5c59042cdc5611a6b74d10d0e18525d9e51a32dc6aa1a2349c789b04dae75a835f4bb322a
7
- data.tar.gz: e0304dded75753771417672c704054a1daec13ab428ed92f97dbdcee2771f21874bfb6aedf9bd0054806ed97b4483b98376f03526b129d96628735c1933f0d35
6
+ metadata.gz: d1b6ad8fba792ca671246b2d6531f981a2c184adde3e4efc7522a7f38ea659c563dadd50ee208ab406f0ce4c37fc6625c2d59e020b0334cdefd8ea7f5d5eed8a
7
+ data.tar.gz: 74c1156b7b407b2d687cc74886198d9f2705d7d82e3672e5d5b9b61f2811fa53dfe7b2bdb61ac0dae8e5e83242415ff7d7d1f6e2721f77b90dcda61dff88c815
@@ -56,7 +56,14 @@ module GraphQL
56
56
  else
57
57
  @arguments = if @field
58
58
  @query.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
59
- args.is_a?(Execution::Interpreter::Arguments) ? args.keyword_arguments : args
59
+ case args
60
+ when Execution::Interpreter::Arguments
61
+ args.keyword_arguments
62
+ when GraphQL::ExecutionError
63
+ EmptyObjects::EMPTY_HASH
64
+ else
65
+ args
66
+ end
60
67
  end
61
68
  else
62
69
  nil
@@ -404,7 +404,7 @@ module GraphQL
404
404
  end
405
405
  end
406
406
 
407
- entry_point_types.compact! # TODO why is this necessary?!
407
+ entry_point_types.compact! # Root types might be nil
408
408
  entry_point_types.flatten! # handle multiple defns
409
409
  entry_point_types.each { |t| add_type(t, true) }
410
410
 
@@ -21,11 +21,27 @@ module GraphQL
21
21
  if migration_errors
22
22
  schema.visibility_profile_class = Migration
23
23
  end
24
+ @preload = preload
24
25
  @profiles = profiles
25
26
  @cached_profiles = {}
26
27
  @dynamic = dynamic
27
28
  @migration_errors = migration_errors
28
29
  if preload
30
+ # Traverse the schema now (and in the *_configured hooks below)
31
+ # To make sure things are loaded during boot
32
+ @preloaded_types = Set.new
33
+ types_to_visit = [
34
+ @schema.query,
35
+ @schema.mutation,
36
+ @schema.subscription,
37
+ *@schema.introspection_system.types.values,
38
+ *@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
39
+ *@schema.orphan_types,
40
+ ]
41
+ # Root types may have been nil:
42
+ types_to_visit.compact!
43
+ ensure_all_loaded(types_to_visit)
44
+
29
45
  profiles.each do |profile_name, example_ctx|
30
46
  example_ctx[:visibility_profile] = profile_name
31
47
  prof = profile_for(example_ctx, profile_name)
@@ -34,6 +50,45 @@ module GraphQL
34
50
  end
35
51
  end
36
52
 
53
+ # @api private
54
+ def query_configured(query_type)
55
+ if @preload
56
+ ensure_all_loaded([query_type])
57
+ end
58
+ end
59
+
60
+ # @api private
61
+ def mutation_configured(mutation_type)
62
+ if @preload
63
+ ensure_all_loaded([mutation_type])
64
+ end
65
+ end
66
+
67
+ # @api private
68
+ def subscription_configured(subscription_type)
69
+ if @preload
70
+ ensure_all_loaded([subscription_type])
71
+ end
72
+ end
73
+
74
+ # @api private
75
+ def orphan_types_configured(orphan_types)
76
+ if @preload
77
+ ensure_all_loaded(orphan_types)
78
+ end
79
+ end
80
+
81
+ # @api private
82
+ def introspection_system_configured(introspection_system)
83
+ if @preload
84
+ introspection_types = [
85
+ *@schema.introspection_system.types.values,
86
+ *@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
87
+ ]
88
+ ensure_all_loaded(introspection_types)
89
+ end
90
+ end
91
+
37
92
  # Make another Visibility for `schema` based on this one
38
93
  # @return [Visibility]
39
94
  # @api private
@@ -57,7 +112,11 @@ module GraphQL
57
112
  if @profiles.any?
58
113
  if visibility_profile.nil?
59
114
  if @dynamic
60
- @schema.visibility_profile_class.new(context: context, schema: @schema)
115
+ if context.is_a?(Query::NullContext)
116
+ top_level_profile
117
+ else
118
+ @schema.visibility_profile_class.new(context: context, schema: @schema)
119
+ end
61
120
  elsif @profiles.any?
62
121
  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
122
  end
@@ -66,10 +125,34 @@ module GraphQL
66
125
  else
67
126
  @cached_profiles[visibility_profile] ||= @schema.visibility_profile_class.new(name: visibility_profile, context: context, schema: @schema)
68
127
  end
128
+ elsif context.is_a?(Query::NullContext)
129
+ top_level_profile
69
130
  else
70
131
  @schema.visibility_profile_class.new(context: context, schema: @schema)
71
132
  end
72
133
  end
134
+
135
+ private
136
+
137
+ def top_level_profile(refresh: false)
138
+ if refresh
139
+ @top_level_profile = nil
140
+ end
141
+ @top_level_profile ||= @schema.visibility_profile_class.new(context: Query::NullContext.instance, schema: @schema)
142
+ end
143
+
144
+ def ensure_all_loaded(types_to_visit)
145
+ while (type = types_to_visit.shift)
146
+ if type.kind.fields? && @preloaded_types.add?(type)
147
+ type.all_field_definitions.each do |field_defn|
148
+ field_defn.ensure_loaded
149
+ types_to_visit << field_defn.type.unwrap
150
+ end
151
+ end
152
+ end
153
+ top_level_profile(refresh: true)
154
+ nil
155
+ end
73
156
  end
74
157
  end
75
158
  end
@@ -445,7 +445,12 @@ module GraphQL
445
445
  dup_defn = new_query_object || yield
446
446
  raise GraphQL::Error, "Second definition of `query(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@query_object.inspect}"
447
447
  elsif use_visibility_profile?
448
- @query_object = block_given? ? lazy_load_block : new_query_object
448
+ if block_given?
449
+ @query_object = lazy_load_block
450
+ else
451
+ @query_object = new_query_object
452
+ self.visibility.query_configured(@query_object)
453
+ end
449
454
  else
450
455
  @query_object = new_query_object || lazy_load_block.call
451
456
  add_type_and_traverse(@query_object, root: true)
@@ -453,6 +458,8 @@ module GraphQL
453
458
  nil
454
459
  elsif @query_object.is_a?(Proc)
455
460
  @query_object = @query_object.call
461
+ self.visibility&.query_configured(@query_object)
462
+ @query_object
456
463
  else
457
464
  @query_object || find_inherited_value(:query)
458
465
  end
@@ -472,7 +479,12 @@ module GraphQL
472
479
  dup_defn = new_mutation_object || yield
473
480
  raise GraphQL::Error, "Second definition of `mutation(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
474
481
  elsif use_visibility_profile?
475
- @mutation_object = block_given? ? lazy_load_block : new_mutation_object
482
+ if block_given?
483
+ @mutation_object = lazy_load_block
484
+ else
485
+ @mutation_object = new_mutation_object
486
+ self.visibility.mutation_configured(@mutation_object)
487
+ end
476
488
  else
477
489
  @mutation_object = new_mutation_object || lazy_load_block.call
478
490
  add_type_and_traverse(@mutation_object, root: true)
@@ -480,6 +492,8 @@ module GraphQL
480
492
  nil
481
493
  elsif @mutation_object.is_a?(Proc)
482
494
  @mutation_object = @mutation_object.call
495
+ self.visibility&.mutation_configured(@mutation_object)
496
+ @mutation_object
483
497
  else
484
498
  @mutation_object || find_inherited_value(:mutation)
485
499
  end
@@ -499,7 +513,12 @@ module GraphQL
499
513
  dup_defn = new_subscription_object || yield
500
514
  raise GraphQL::Error, "Second definition of `subscription(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
501
515
  elsif use_visibility_profile?
502
- @subscription_object = block_given? ? lazy_load_block : new_subscription_object
516
+ if block_given?
517
+ @subscription_object = lazy_load_block
518
+ else
519
+ @subscription_object = new_subscription_object
520
+ self.visibility.subscription_configured(@subscription_object)
521
+ end
503
522
  add_subscription_extension_if_necessary
504
523
  else
505
524
  @subscription_object = new_subscription_object || lazy_load_block.call
@@ -510,6 +529,7 @@ module GraphQL
510
529
  elsif @subscription_object.is_a?(Proc)
511
530
  @subscription_object = @subscription_object.call
512
531
  add_subscription_extension_if_necessary
532
+ self.visibility.subscription_configured(@subscription_object)
513
533
  @subscription_object
514
534
  else
515
535
  @subscription_object || find_inherited_value(:subscription)
@@ -695,20 +715,27 @@ module GraphQL
695
715
  type.fields(context)
696
716
  end
697
717
 
718
+ # Pass a custom introspection module here to use it for this schema.
719
+ # @param new_introspection_namespace [Module] If given, use this module for custom introspection on the schema
720
+ # @return [Module, nil] The configured namespace, if there is one
698
721
  def introspection(new_introspection_namespace = nil)
699
722
  if new_introspection_namespace
700
723
  @introspection = new_introspection_namespace
701
724
  # reset this cached value:
702
725
  @introspection_system = nil
726
+ introspection_system
727
+ @introspection
703
728
  else
704
729
  @introspection || find_inherited_value(:introspection)
705
730
  end
706
731
  end
707
732
 
733
+ # @return [Schema::IntrospectionSystem] Based on {introspection}
708
734
  def introspection_system
709
735
  if !@introspection_system
710
736
  @introspection_system = Schema::IntrospectionSystem.new(self)
711
737
  @introspection_system.resolve_late_bindings
738
+ self.visibility&.introspection_system_configured(@introspection_system)
712
739
  end
713
740
  @introspection_system
714
741
  end
@@ -952,6 +979,13 @@ module GraphQL
952
979
  end
953
980
  end
954
981
 
982
+ # Tell the schema about these types so that they can be registered as implementations of interfaces in the schema.
983
+ #
984
+ # This method must be used when an object type is connected to the schema as an interface implementor but
985
+ # not as a return type of a field. In that case, if the object type isn't registered here, GraphQL-Ruby won't be able to find it.
986
+ #
987
+ # @param new_orphan_types [Array<Class<GraphQL::Schema::Object>>] Object types to register as implementations of interfaces in the schema.
988
+ # @return [Array<Class<GraphQL::Schema::Object>>] All previously-registered orphan types for this schema
955
989
  def orphan_types(*new_orphan_types)
956
990
  if new_orphan_types.any?
957
991
  new_orphan_types = new_orphan_types.flatten
@@ -968,6 +1002,7 @@ module GraphQL
968
1002
  end
969
1003
  add_type_and_traverse(new_orphan_types, root: false) unless use_visibility_profile?
970
1004
  own_orphan_types.concat(new_orphan_types.flatten)
1005
+ self.visibility&.orphan_types_configured(new_orphan_types)
971
1006
  end
972
1007
 
973
1008
  inherited_ot = find_inherited_value(:orphan_types, nil)
@@ -14,7 +14,9 @@ module GraphQL
14
14
  node_name: parent_type.graphql_name
15
15
  ))
16
16
  else
17
- message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{context.did_you_mean_suggestion(node.name, context.types.fields(parent_type).map(&:graphql_name))}"
17
+ possible_fields = possible_fields(context, parent_type)
18
+ suggestion = context.did_you_mean_suggestion(node.name, possible_fields)
19
+ message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{suggestion}"
18
20
  add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
19
21
  message,
20
22
  nodes: node,
@@ -26,6 +28,13 @@ module GraphQL
26
28
  super
27
29
  end
28
30
  end
31
+
32
+ private
33
+
34
+ def possible_fields(context, parent_type)
35
+ return EmptyObjects::EMPTY_ARRAY if parent_type.kind.leaf?
36
+ context.types.fields(parent_type).map(&:graphql_name)
37
+ end
29
38
  end
30
39
  end
31
40
  end
@@ -25,7 +25,7 @@ module GraphQL
25
25
  def validate_field_selections(ast_node, resolved_type)
26
26
  msg = if resolved_type.nil?
27
27
  nil
28
- elsif resolved_type.kind.scalar? && ast_node.selections.any?
28
+ elsif ast_node.selections.any? && resolved_type.kind.leaf?
29
29
  selection_strs = ast_node.selections.map do |n|
30
30
  case n
31
31
  when GraphQL::Language::Nodes::InlineFragment
@@ -38,7 +38,7 @@ module GraphQL
38
38
  raise "Invariant: unexpected selection node: #{n}"
39
39
  end
40
40
  end
41
- "Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{selection_strs.join(", ")}])"
41
+ "Selections can't be made on #{resolved_type.kind.name.sub("_", " ").downcase}s (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{selection_strs.join(", ")}])"
42
42
  elsif resolved_type.kind.fields? && ast_node.selections.empty?
43
43
  "Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
44
44
  else
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.4.1"
3
+ VERSION = "2.4.3"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-04 00:00:00.000000000 Z
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64