graphql 2.1.1 → 2.1.5

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.

Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/query_depth.rb +7 -2
  3. data/lib/graphql/dataloader.rb +29 -10
  4. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +1 -1
  5. data/lib/graphql/execution/interpreter/runtime.rb +7 -26
  6. data/lib/graphql/execution/lookahead.rb +87 -20
  7. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  8. data/lib/graphql/pagination/connection.rb +15 -10
  9. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  10. data/lib/graphql/query/context.rb +4 -0
  11. data/lib/graphql/query/null_context.rb +2 -10
  12. data/lib/graphql/query.rb +10 -0
  13. data/lib/graphql/schema/build_from_definition.rb +0 -11
  14. data/lib/graphql/schema/directive/one_of.rb +12 -0
  15. data/lib/graphql/schema/directive.rb +1 -1
  16. data/lib/graphql/schema/enum.rb +2 -2
  17. data/lib/graphql/schema/field/scope_extension.rb +4 -3
  18. data/lib/graphql/schema/field.rb +2 -2
  19. data/lib/graphql/schema/has_single_input_argument.rb +2 -2
  20. data/lib/graphql/schema/input_object.rb +1 -1
  21. data/lib/graphql/schema/interface.rb +10 -10
  22. data/lib/graphql/schema/loader.rb +0 -2
  23. data/lib/graphql/schema/member/has_arguments.rb +47 -36
  24. data/lib/graphql/schema/member/has_fields.rb +4 -4
  25. data/lib/graphql/schema/member/has_interfaces.rb +2 -2
  26. data/lib/graphql/schema/member/validates_input.rb +3 -3
  27. data/lib/graphql/schema/resolver.rb +3 -3
  28. data/lib/graphql/schema/union.rb +1 -1
  29. data/lib/graphql/schema/warden.rb +73 -57
  30. data/lib/graphql/schema.rb +154 -43
  31. data/lib/graphql/subscriptions/event.rb +1 -1
  32. data/lib/graphql/subscriptions.rb +2 -2
  33. data/lib/graphql/version.rb +1 -1
  34. metadata +17 -17
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "logger"
2
3
  require "graphql/schema/addition"
3
4
  require "graphql/schema/always_visible"
4
5
  require "graphql/schema/base_64_encoder"
@@ -146,6 +147,19 @@ module GraphQL
146
147
  @subscriptions = new_implementation
147
148
  end
148
149
 
150
+ # @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
151
+ def default_trace_mode(new_mode = nil)
152
+ if new_mode
153
+ @default_trace_mode = new_mode
154
+ elsif defined?(@default_trace_mode)
155
+ @default_trace_mode
156
+ elsif superclass.respond_to?(:default_trace_mode)
157
+ superclass.default_trace_mode
158
+ else
159
+ :default
160
+ end
161
+ end
162
+
149
163
  def trace_class(new_class = nil)
150
164
  if new_class
151
165
  trace_mode(:default, new_class)
@@ -158,41 +172,65 @@ module GraphQL
158
172
 
159
173
  # @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
160
174
  def trace_class_for(mode)
161
- @trace_modes ||= {}
162
- @trace_modes[mode] ||= begin
163
- case mode
164
- when :default
165
- superclass_base_class = if superclass.respond_to?(:trace_class_for)
166
- superclass.trace_class_for(mode)
167
- else
168
- GraphQL::Tracing::Trace
169
- end
170
- Class.new(superclass_base_class)
171
- when :default_backtrace
172
- schema_base_class = trace_class_for(:default)
173
- Class.new(schema_base_class) do
174
- include(GraphQL::Backtrace::Trace)
175
- end
176
- else
177
- mods = trace_modules_for(mode)
178
- Class.new(trace_class_for(:default)) do
179
- mods.any? && include(*mods)
180
- end
181
- end
182
- end
175
+ own_trace_modes[mode] ||
176
+ (superclass.respond_to?(:trace_class_for) ? superclass.trace_class_for(mode) : (own_trace_modes[mode] = build_trace_mode(mode)))
183
177
  end
184
178
 
185
179
  # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
186
- # `:default` is used when no `trace_mode: ...` is requested.
180
+ # {default_trace_mode} is used when no `trace_mode: ...` is requested.
181
+ #
182
+ # When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
183
+ # unless `trace_mode` is explicitly given. (This class will not recieve any default trace modules.)
184
+ #
185
+ # Subclasses of the schema will use `trace_class` as a base class for this mode and those
186
+ # subclass also will _not_ receive default tracing modules.
187
+ #
187
188
  # @param mode_name [Symbol]
188
189
  # @param trace_class [Class] subclass of GraphQL::Tracing::Trace
189
190
  # @return void
190
191
  def trace_mode(mode_name, trace_class)
191
- @trace_modes ||= {}
192
- @trace_modes[mode_name] = trace_class
192
+ own_trace_modes[mode_name] = trace_class
193
193
  nil
194
194
  end
195
195
 
196
+ def own_trace_modes
197
+ @own_trace_modes ||= {}
198
+ end
199
+
200
+ module DefaultTraceClass
201
+ end
202
+
203
+ private_constant :DefaultTraceClass
204
+
205
+ def build_trace_mode(mode)
206
+ case mode
207
+ when :default
208
+ # Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
209
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || GraphQL::Tracing::Trace
210
+ Class.new(base_class) do
211
+ include DefaultTraceClass
212
+ end
213
+ when :default_backtrace
214
+ schema_base_class = trace_class_for(:default)
215
+ Class.new(schema_base_class) do
216
+ include(GraphQL::Backtrace::Trace)
217
+ end
218
+ else
219
+ # First, see if the superclass has a custom-defined class for this.
220
+ # Then, if it doesn't, use this class's default trace
221
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default)
222
+ # Prepare the default trace class if it hasn't been initialized yet
223
+ base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
224
+ mods = trace_modules_for(mode)
225
+ if base_class < DefaultTraceClass
226
+ mods = trace_modules_for(:default) + mods
227
+ end
228
+ Class.new(base_class) do
229
+ mods.any? && include(*mods)
230
+ end
231
+ end
232
+ end
233
+
196
234
  def own_trace_modules
197
235
  @own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
198
236
  end
@@ -288,7 +326,7 @@ module GraphQL
288
326
  # Build a map of `{ name => type }` and return it
289
327
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
290
328
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
291
- def types(context = GraphQL::Query::NullContext)
329
+ def types(context = GraphQL::Query::NullContext.instance)
292
330
  all_types = non_introspection_types.merge(introspection_system.types)
293
331
  visible_types = {}
294
332
  all_types.each do |k, v|
@@ -315,7 +353,7 @@ module GraphQL
315
353
 
316
354
  # @param type_name [String]
317
355
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
318
- def get_type(type_name, context = GraphQL::Query::NullContext)
356
+ def get_type(type_name, context = GraphQL::Query::NullContext.instance)
319
357
  local_entry = own_types[type_name]
320
358
  type_defn = case local_entry
321
359
  when nil
@@ -446,7 +484,7 @@ module GraphQL
446
484
  # @param type [Module] The type definition whose possible types you want to see
447
485
  # @return [Hash<String, Module>] All possible types, if no `type` is given.
448
486
  # @return [Array<Module>] Possible types for `type`, if it's given.
449
- def possible_types(type = nil, context = GraphQL::Query::NullContext)
487
+ def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
450
488
  if type
451
489
  # TODO duck-typing `.possible_types` would probably be nicer here
452
490
  if type.kind.union?
@@ -499,18 +537,17 @@ module GraphQL
499
537
  attr_writer :dataloader_class
500
538
 
501
539
  def references_to(to_type = nil, from: nil)
502
- @own_references_to ||= Hash.new { |h, k| h[k] = [] }
540
+ @own_references_to ||= {}
503
541
  if to_type
504
542
  if !to_type.is_a?(String)
505
543
  to_type = to_type.graphql_name
506
544
  end
507
545
 
508
546
  if from
509
- @own_references_to[to_type] << from
547
+ refs = @own_references_to[to_type] ||= []
548
+ refs << from
510
549
  else
511
- own_refs = @own_references_to[to_type]
512
- inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
513
- own_refs + inherited_refs
550
+ get_references_to(to_type) || EMPTY_ARRAY
514
551
  end
515
552
  else
516
553
  # `@own_references_to` can be quite large for big schemas,
@@ -530,7 +567,7 @@ module GraphQL
530
567
  GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
531
568
  end
532
569
 
533
- def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
570
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
534
571
  parent_type = case type_or_name
535
572
  when LateBoundType
536
573
  get_type(type_or_name.name, context)
@@ -553,7 +590,7 @@ module GraphQL
553
590
  end
554
591
  end
555
592
 
556
- def get_fields(type, context = GraphQL::Query::NullContext)
593
+ def get_fields(type, context = GraphQL::Query::NullContext.instance)
557
594
  type.fields(context)
558
595
  end
559
596
 
@@ -703,9 +740,10 @@ module GraphQL
703
740
 
704
741
  attr_writer :max_depth
705
742
 
706
- def max_depth(new_max_depth = nil)
743
+ def max_depth(new_max_depth = nil, count_introspection_fields: true)
707
744
  if new_max_depth
708
745
  @max_depth = new_max_depth
746
+ @count_introspection_fields = count_introspection_fields
709
747
  elsif defined?(@max_depth)
710
748
  @max_depth
711
749
  else
@@ -713,6 +751,14 @@ module GraphQL
713
751
  end
714
752
  end
715
753
 
754
+ def count_introspection_fields
755
+ if defined?(@count_introspection_fields)
756
+ @count_introspection_fields
757
+ else
758
+ find_inherited_value(:count_introspection_fields, true)
759
+ end
760
+ end
761
+
716
762
  def disable_introspection_entry_points
717
763
  @disable_introspection_entry_points = true
718
764
  # TODO: this clears the cache made in `def types`. But this is not a great solution.
@@ -790,6 +836,26 @@ module GraphQL
790
836
  end
791
837
  end
792
838
 
839
+ def default_logger(new_default_logger = NOT_CONFIGURED)
840
+ if NOT_CONFIGURED.equal?(new_default_logger)
841
+ if defined?(@default_logger)
842
+ @default_logger
843
+ elsif superclass.respond_to?(:default_logger)
844
+ superclass.default_logger
845
+ elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
846
+ rails_logger
847
+ else
848
+ def_logger = Logger.new($stdout)
849
+ def_logger.info! # It doesn't output debug info by default
850
+ def_logger
851
+ end
852
+ elsif new_default_logger == nil
853
+ @default_logger = Logger.new(IO::NULL)
854
+ else
855
+ @default_logger = new_default_logger
856
+ end
857
+ end
858
+
793
859
  def context_class(new_context_class = nil)
794
860
  if new_context_class
795
861
  @context_class = new_context_class
@@ -876,6 +942,12 @@ module GraphQL
876
942
  def inherited(child_class)
877
943
  if self == GraphQL::Schema
878
944
  child_class.directives(default_directives.values)
945
+ child_class.extend(SubclassGetReferencesTo)
946
+ end
947
+ # Make sure the child class has these built out, so that
948
+ # subclasses can be modified by later calls to `trace_with`
949
+ own_trace_modes.each do |name, _class|
950
+ child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
879
951
  end
880
952
  child_class.singleton_class.prepend(ResolveTypeWithType)
881
953
  super
@@ -999,7 +1071,8 @@ module GraphQL
999
1071
  end
1000
1072
 
1001
1073
  def tracer(new_tracer)
1002
- if !(trace_class_for(:default) < GraphQL::Tracing::CallLegacyTracers)
1074
+ default_trace = trace_class_for(:default)
1075
+ if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
1003
1076
  trace_with(GraphQL::Tracing::CallLegacyTracers)
1004
1077
  end
1005
1078
 
@@ -1021,10 +1094,20 @@ module GraphQL
1021
1094
  if mode.is_a?(Array)
1022
1095
  mode.each { |m| trace_with(trace_mod, mode: m, **options) }
1023
1096
  else
1024
- tc = trace_class_for(mode)
1097
+ tc = own_trace_modes[mode] ||= build_trace_mode(mode)
1025
1098
  tc.include(trace_mod)
1026
- if mode != :default
1027
- own_trace_modules[mode] << trace_mod
1099
+ own_trace_modules[mode] << trace_mod
1100
+
1101
+ if mode == :default
1102
+ # This module is being added as a default tracer. If any other mode classes
1103
+ # have already been created, but get their default behavior from a superclass,
1104
+ # Then mix this into this schema's subclass.
1105
+ # (But don't mix it into mode classes that aren't default-based.)
1106
+ own_trace_modes.each do |other_mode_name, other_mode_class|
1107
+ if other_mode_class < DefaultTraceClass && !(other_mode_class < trace_mod)
1108
+ other_mode_class.include(trace_mod)
1109
+ end
1110
+ end
1028
1111
  end
1029
1112
  t_opts = trace_options_for(mode)
1030
1113
  t_opts.merge!(options)
@@ -1047,6 +1130,8 @@ module GraphQL
1047
1130
 
1048
1131
  # Create a trace instance which will include the trace modules specified for the optional mode.
1049
1132
  #
1133
+ # If no `mode:` is given, then {default_trace_mode} will be used.
1134
+ #
1050
1135
  # @param mode [Symbol] Trace modules for this trade mode will be included
1051
1136
  # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1052
1137
  # @return [Tracing::Trace]
@@ -1057,14 +1142,19 @@ module GraphQL
1057
1142
  trace_mode = if mode
1058
1143
  mode
1059
1144
  elsif target && target.context[:backtrace]
1060
- :default_backtrace
1145
+ if default_trace_mode != :default
1146
+ raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
1147
+ else
1148
+ own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
1149
+ :default_backtrace
1150
+ end
1061
1151
  else
1062
- :default
1152
+ default_trace_mode
1063
1153
  end
1064
1154
 
1065
1155
  base_trace_options = trace_options_for(trace_mode)
1066
1156
  trace_options = base_trace_options.merge(options)
1067
- trace_class_for_mode = trace_class_for(trace_mode)
1157
+ trace_class_for_mode = trace_class_for(trace_mode) || raise(ArgumentError, "#{self} has no trace class for mode: #{trace_mode.inspect}")
1068
1158
  trace_class_for_mode.new(**trace_options)
1069
1159
  end
1070
1160
 
@@ -1328,6 +1418,27 @@ module GraphQL
1328
1418
  def own_multiplex_analyzers
1329
1419
  @own_multiplex_analyzers ||= []
1330
1420
  end
1421
+
1422
+ # This is overridden in subclasses to check the inheritance chain
1423
+ def get_references_to(type_name)
1424
+ @own_references_to[type_name]
1425
+ end
1426
+ end
1427
+
1428
+ module SubclassGetReferencesTo
1429
+ def get_references_to(type_name)
1430
+ own_refs = @own_references_to[type_name]
1431
+ inherited_refs = superclass.references_to(type_name)
1432
+ if inherited_refs&.any?
1433
+ if own_refs&.any?
1434
+ own_refs + inherited_refs
1435
+ else
1436
+ inherited_refs
1437
+ end
1438
+ else
1439
+ own_refs
1440
+ end
1441
+ end
1331
1442
  end
1332
1443
 
1333
1444
  # Install these here so that subclasses will also install it.
@@ -37,7 +37,7 @@ module GraphQL
37
37
  end
38
38
 
39
39
  # @return [String] an identifier for this unit of subscription
40
- def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
40
+ def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext.instance)
41
41
  subscription = field.resolver || GraphQL::Schema::Subscription
42
42
  normalized_args = stringify_args(field, arguments.to_h, context)
43
43
  subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
@@ -62,7 +62,7 @@ module GraphQL
62
62
  # @return [void]
63
63
  def trigger(event_name, args, object, scope: nil, context: {})
64
64
  # Make something as context-like as possible, even though there isn't a current query:
65
- dummy_query = GraphQL::Query.new(@schema, "", validate: false, context: context)
65
+ dummy_query = GraphQL::Query.new(@schema, "{ __typename }", validate: false, context: context)
66
66
  context = dummy_query.context
67
67
  event_name = event_name.to_s
68
68
 
@@ -83,7 +83,7 @@ module GraphQL
83
83
 
84
84
  # Normalize symbol-keyed args to strings, try camelizing them
85
85
  # Should this accept a real context somehow?
86
- normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
86
+ normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext.instance)
87
87
 
88
88
  event = Subscriptions::Event.new(
89
89
  name: normalized_event_name,
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.1.1"
3
+ VERSION = "2.1.5"
4
4
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-02 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: racc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.4'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: benchmark-ips
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +108,6 @@ dependencies:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '1.0'
97
- - !ruby/object:Gem::Dependency
98
- name: racc
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '1.4'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '1.4'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -619,7 +619,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
619
619
  requirements:
620
620
  - - ">="
621
621
  - !ruby/object:Gem::Version
622
- version: 2.4.0
622
+ version: 2.7.0
623
623
  required_rubygems_version: !ruby/object:Gem::Requirement
624
624
  requirements:
625
625
  - - ">="