graphql 2.5.14 → 2.5.22

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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  4. data/lib/graphql/dashboard/application_controller.rb +41 -0
  5. data/lib/graphql/dashboard/landings_controller.rb +9 -0
  6. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  7. data/lib/graphql/dashboard/subscriptions.rb +2 -1
  8. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +1 -0
  9. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +2 -2
  10. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +1 -1
  11. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +1 -1
  12. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +1 -1
  13. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +1 -1
  14. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +1 -1
  15. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +7 -7
  16. data/lib/graphql/dashboard.rb +11 -73
  17. data/lib/graphql/dataloader/null_dataloader.rb +7 -3
  18. data/lib/graphql/date_encoding_error.rb +1 -1
  19. data/lib/graphql/execution/interpreter.rb +0 -1
  20. data/lib/graphql/execution/multiplex.rb +1 -1
  21. data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
  22. data/lib/graphql/execution/next/load_argument_step.rb +60 -0
  23. data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
  24. data/lib/graphql/execution/next/runner.rb +389 -0
  25. data/lib/graphql/execution/next/selections_step.rb +37 -0
  26. data/lib/graphql/execution/next.rb +70 -0
  27. data/lib/graphql/execution.rb +1 -0
  28. data/lib/graphql/execution_error.rb +13 -10
  29. data/lib/graphql/introspection/directive_type.rb +7 -3
  30. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  31. data/lib/graphql/introspection/entry_points.rb +11 -3
  32. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  33. data/lib/graphql/introspection/field_type.rb +13 -5
  34. data/lib/graphql/introspection/input_value_type.rb +21 -13
  35. data/lib/graphql/introspection/type_type.rb +64 -28
  36. data/lib/graphql/invalid_null_error.rb +11 -5
  37. data/lib/graphql/language/document_from_schema_definition.rb +2 -1
  38. data/lib/graphql/language.rb +21 -12
  39. data/lib/graphql/pagination/connection.rb +2 -0
  40. data/lib/graphql/pagination/connections.rb +32 -0
  41. data/lib/graphql/query/context.rb +3 -2
  42. data/lib/graphql/query/null_context.rb +9 -3
  43. data/lib/graphql/schema/argument.rb +12 -0
  44. data/lib/graphql/schema/build_from_definition.rb +7 -0
  45. data/lib/graphql/schema/directive.rb +8 -1
  46. data/lib/graphql/schema/field/connection_extension.rb +15 -35
  47. data/lib/graphql/schema/field/scope_extension.rb +22 -13
  48. data/lib/graphql/schema/field.rb +80 -48
  49. data/lib/graphql/schema/field_extension.rb +33 -0
  50. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
  51. data/lib/graphql/schema/member/has_arguments.rb +37 -14
  52. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  53. data/lib/graphql/schema/member/has_dataloader.rb +37 -0
  54. data/lib/graphql/schema/member/has_fields.rb +81 -4
  55. data/lib/graphql/schema/member.rb +5 -0
  56. data/lib/graphql/schema/object.rb +1 -0
  57. data/lib/graphql/schema/resolver.rb +45 -1
  58. data/lib/graphql/schema/validator/required_validator.rb +33 -2
  59. data/lib/graphql/schema/visibility.rb +3 -3
  60. data/lib/graphql/schema.rb +53 -10
  61. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +2 -2
  62. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
  63. data/lib/graphql/subscriptions.rb +1 -1
  64. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  65. data/lib/graphql/testing.rb +1 -0
  66. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  67. data/lib/graphql/tracing/detailed_trace.rb +70 -7
  68. data/lib/graphql/tracing/perfetto_trace.rb +208 -78
  69. data/lib/graphql/types/relay/connection_behaviors.rb +8 -6
  70. data/lib/graphql/types/relay/edge_behaviors.rb +4 -3
  71. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  72. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  73. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  74. data/lib/graphql/unauthorized_error.rb +5 -1
  75. data/lib/graphql/version.rb +1 -1
  76. data/lib/graphql.rb +8 -2
  77. metadata +17 -3
@@ -60,11 +60,52 @@ module GraphQL
60
60
  DA_FETCH_KEYS_IID = 13
61
61
  DA_STR_VAL_NIL_IID = 14
62
62
 
63
+ REVERSE_DEBUG_NAME_LOOKUP = {
64
+ DA_OBJECT_IID => "object",
65
+ DA_RESULT_IID => "result",
66
+ DA_ARGUMENTS_IID => "arguments",
67
+ DA_FETCH_KEYS_IID => "fetch keys",
68
+ }
69
+
70
+ DEBUG_INSPECT_CATEGORY_IIDS = [15]
71
+ DA_DEBUG_INSPECT_CLASS_IID = 16
72
+ DEBUG_INSPECT_EVENT_NAME_IID = 17
73
+ DA_DEBUG_INSPECT_FOR_IID = 18
74
+
63
75
  # @param active_support_notifications_pattern [String, RegExp, false] A filter for `ActiveSupport::Notifications`, if it's present. Or `false` to skip subscribing.
64
76
  def initialize(active_support_notifications_pattern: nil, save_profile: false, **_rest)
65
77
  super
66
78
  @active_support_notifications_pattern = active_support_notifications_pattern
67
79
  @save_profile = save_profile
80
+
81
+ query = if @multiplex
82
+ @multiplex.queries.first
83
+ else
84
+ @query # could still be nil in some initializations
85
+ end
86
+
87
+ @detailed_trace = query&.schema&.detailed_trace || DetailedTrace
88
+ @create_debug_annotations = if (ctx = query&.context).nil? || (ctx_debug = ctx[:detailed_trace_debug]).nil?
89
+ @detailed_trace.debug?
90
+ else
91
+ ctx_debug
92
+ end
93
+
94
+ @arguments_filter = if (ctx = query&.context) && (dtf = ctx[:detailed_trace_filter])
95
+ dtf
96
+ elsif defined?(ActiveSupport::ParameterFilter)
97
+ fp = if defined?(Rails) && Rails.application && (app_config = Rails.application.config.filter_parameters).present? && !app_config.empty?
98
+ app_config
99
+ elsif ActiveSupport.respond_to?(:filter_parameters)
100
+ ActiveSupport.filter_parameters
101
+ else
102
+ EmptyObjects::EMPTY_ARRAY
103
+ end
104
+ ActiveSupport::ParameterFilter.new(fp, mask: ArgumentsFilter::FILTERED)
105
+ else
106
+ ArgumentsFilter.new
107
+ end
108
+
68
109
  Fiber[:graphql_flow_stack] = nil
69
110
  @sequence_id = object_id
70
111
  @pid = Process.pid
@@ -110,6 +151,10 @@ module GraphQL
110
151
  @objects_counter_id = :objects_counter.object_id
111
152
  @fibers_counter_id = :fibers_counter.object_id
112
153
  @fields_counter_id = :fields_counter.object_id
154
+ @counts_objects = [@objects_counter_id]
155
+ @counts_objects_and_fields = [@objects_counter_id, @fields_counter_id]
156
+ @counts_fibers = [@fibers_counter_id]
157
+ @counts_fibers_and_objects = [@fibers_counter_id, @objects_counter_id]
113
158
  @begin_validate = nil
114
159
  @begin_time = nil
115
160
  @packets = []
@@ -132,16 +177,19 @@ module GraphQL
132
177
  EventCategory.new(name: "ActiveSupport::Notifications", iid: ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS.first),
133
178
  EventCategory.new(name: "Authorized", iid: AUTHORIZED_CATEGORY_IIDS.first),
134
179
  EventCategory.new(name: "Resolve Type", iid: RESOLVE_TYPE_CATEGORY_IIDS.first),
180
+ EventCategory.new(name: "Debug Inspect", iid: DEBUG_INSPECT_CATEGORY_IIDS.first),
135
181
  ],
136
182
  debug_annotation_names: [
137
- DebugAnnotationName.new(name: "object", iid: DA_OBJECT_IID),
138
- DebugAnnotationName.new(name: "arguments", iid: DA_ARGUMENTS_IID),
139
- DebugAnnotationName.new(name: "result", iid: DA_RESULT_IID),
140
- DebugAnnotationName.new(name: "fetch keys", iid: DA_FETCH_KEYS_IID),
183
+ *REVERSE_DEBUG_NAME_LOOKUP.map { |(iid, name)| DebugAnnotationName.new(name: name, iid: iid) },
184
+ DebugAnnotationName.new(name: "inspect instance of", iid: DA_DEBUG_INSPECT_CLASS_IID),
185
+ DebugAnnotationName.new(name: "inspecting for", iid: DA_DEBUG_INSPECT_FOR_IID)
141
186
  ],
142
187
  debug_annotation_string_values: [
143
188
  InternedString.new(str: "(nil)", iid: DA_STR_VAL_NIL_IID),
144
189
  ],
190
+ event_names: [
191
+ EventName.new(name: "#{(@detailed_trace.is_a?(Class) ? @detailed_trace : @detailed_trace.class).name}#inspect_object", iid: DEBUG_INSPECT_EVENT_NAME_IID)
192
+ ],
145
193
  ),
146
194
  trusted_packet_sequence_id: @sequence_id,
147
195
  sequence_flags: 2,
@@ -180,11 +228,9 @@ module GraphQL
180
228
  @packets << trace_packet(
181
229
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
182
230
  track_uuid: fid,
183
- name: "Multiplex",
184
- debug_annotations: [
185
- payload_to_debug("query_string", multiplex.queries.map(&:sanitized_query_string).join("\n\n"))
186
- ]
187
- )
231
+ name: "Multiplex"
232
+ ) { [ payload_to_debug("query_string", multiplex.queries.map(&:sanitized_query_string).join("\n\n")) ] }
233
+
188
234
  result = super
189
235
 
190
236
  @packets << trace_packet(
@@ -209,7 +255,7 @@ module GraphQL
209
255
  track_uuid: fid,
210
256
  name: query.context.current_path.join("."),
211
257
  category_iids: FIELD_EXECUTE_CATEGORY_IIDS,
212
- extra_counter_track_uuids: [@objects_counter_id],
258
+ extra_counter_track_uuids: @counts_objects,
213
259
  extra_counter_values: [count_allocations],
214
260
  )
215
261
  @packets << packet
@@ -218,19 +264,23 @@ module GraphQL
218
264
  end
219
265
 
220
266
  def end_execute_field(field, object, arguments, query, app_result)
267
+ end_ts = ts
221
268
  start_field = fiber_flow_stack.pop
222
- start_field.track_event = dup_with(start_field.track_event, {
223
- debug_annotations: [
224
- payload_to_debug(nil, object.object, iid: DA_OBJECT_IID, intern_value: true),
225
- payload_to_debug(nil, arguments, iid: DA_ARGUMENTS_IID),
226
- payload_to_debug(nil, app_result, iid: DA_RESULT_IID, intern_value: true)
227
- ]
228
- })
269
+ if @create_debug_annotations
270
+ start_field.track_event = dup_with(start_field.track_event,{
271
+ debug_annotations: [
272
+ payload_to_debug(nil, object.object, iid: DA_OBJECT_IID, intern_value: true),
273
+ payload_to_debug(nil, arguments, iid: DA_ARGUMENTS_IID),
274
+ payload_to_debug(nil, app_result, iid: DA_RESULT_IID, intern_value: true)
275
+ ]
276
+ })
277
+ end
229
278
 
230
279
  @packets << trace_packet(
280
+ timestamp: end_ts,
231
281
  type: TrackEvent::Type::TYPE_SLICE_END,
232
282
  track_uuid: fid,
233
- extra_counter_track_uuids: [@objects_counter_id, @fields_counter_id],
283
+ extra_counter_track_uuids: @counts_objects_and_fields,
234
284
  extra_counter_values: [count_allocations, count_fields],
235
285
  )
236
286
  super
@@ -240,22 +290,24 @@ module GraphQL
240
290
  @packets << trace_packet(
241
291
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
242
292
  track_uuid: fid,
243
- extra_counter_track_uuids: [@objects_counter_id],
293
+ extra_counter_track_uuids: @counts_objects,
244
294
  extra_counter_values: [count_allocations],
245
- name: "Analysis",
246
- debug_annotations: [
247
- payload_to_debug("analyzers_count", analyzers.size),
248
- payload_to_debug("analyzers", analyzers),
249
- ]
250
- )
295
+ name: "Analysis") {
296
+ [
297
+ payload_to_debug("analyzers_count", analyzers.size),
298
+ payload_to_debug("analyzers", analyzers),
299
+ ]
300
+ }
251
301
  super
252
302
  end
253
303
 
254
304
  def end_analyze_multiplex(m, analyzers)
305
+ end_ts = ts
255
306
  @packets << trace_packet(
307
+ timestamp: end_ts,
256
308
  type: TrackEvent::Type::TYPE_SLICE_END,
257
309
  track_uuid: fid,
258
- extra_counter_track_uuids: [@objects_counter_id],
310
+ extra_counter_track_uuids: @counts_objects,
259
311
  extra_counter_values: [count_allocations],
260
312
  )
261
313
  super
@@ -265,50 +317,57 @@ module GraphQL
265
317
  @packets << trace_packet(
266
318
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
267
319
  track_uuid: fid,
268
- extra_counter_track_uuids: [@objects_counter_id],
320
+ extra_counter_track_uuids: @counts_objects,
269
321
  extra_counter_values: [count_allocations],
270
322
  name: "Parse"
271
323
  )
272
324
  result = super
325
+ end_ts = ts
273
326
  @packets << trace_packet(
327
+ timestamp: end_ts,
274
328
  type: TrackEvent::Type::TYPE_SLICE_END,
275
329
  track_uuid: fid,
276
- extra_counter_track_uuids: [@objects_counter_id],
330
+ extra_counter_track_uuids: @counts_objects,
277
331
  extra_counter_values: [count_allocations],
278
332
  )
279
333
  result
280
334
  end
281
335
 
282
336
  def begin_validate(query, validate)
283
- @packets << @begin_validate = trace_packet(
337
+ @begin_validate = trace_packet(
284
338
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
285
339
  track_uuid: fid,
286
- extra_counter_track_uuids: [@objects_counter_id],
340
+ extra_counter_track_uuids: @counts_objects,
287
341
  extra_counter_values: [count_allocations],
288
- name: "Validate",
289
- debug_annotations: [
290
- payload_to_debug("validate?", validate),
291
- ]
292
- )
342
+ name: "Validate") {
343
+ [payload_to_debug("validate?", validate)]
344
+ }
345
+
346
+ @packets << @begin_validate
293
347
  super
294
348
  end
295
349
 
296
350
  def end_validate(query, validate, validation_errors)
351
+ end_ts = ts
297
352
  @packets << trace_packet(
353
+ timestamp: end_ts,
298
354
  type: TrackEvent::Type::TYPE_SLICE_END,
299
355
  track_uuid: fid,
300
- extra_counter_track_uuids: [@objects_counter_id],
356
+ extra_counter_track_uuids: @counts_objects,
301
357
  extra_counter_values: [count_allocations],
302
358
  )
303
- @begin_validate.track_event = dup_with(
304
- @begin_validate.track_event,
305
- {
306
- debug_annotations: [
307
- @begin_validate.track_event.debug_annotations.first,
308
- payload_to_debug("valid?", validation_errors.empty?)
309
- ]
310
- }
311
- )
359
+
360
+ if @create_debug_annotations
361
+ new_bv_track_event = dup_with(
362
+ @begin_validate.track_event, {
363
+ debug_annotations: [
364
+ @begin_validate.track_event.debug_annotations.first,
365
+ payload_to_debug("valid?", validation_errors.empty?)
366
+ ]
367
+ }
368
+ )
369
+ @begin_validate.track_event = new_bv_track_event
370
+ end
312
371
  super
313
372
  end
314
373
 
@@ -318,7 +377,7 @@ module GraphQL
318
377
  track_uuid: fid,
319
378
  name: "Create Execution Fiber",
320
379
  category_iids: DATALOADER_CATEGORY_IIDS,
321
- extra_counter_track_uuids: [@fibers_counter_id, @objects_counter_id],
380
+ extra_counter_track_uuids: @counts_fibers_and_objects,
322
381
  extra_counter_values: [count_fibers(1), count_allocations]
323
382
  )
324
383
  @packets << track_descriptor_packet(@did, fid, "Exec Fiber ##{fid}")
@@ -331,7 +390,7 @@ module GraphQL
331
390
  track_uuid: fid,
332
391
  name: "Create Source Fiber",
333
392
  category_iids: DATALOADER_CATEGORY_IIDS,
334
- extra_counter_track_uuids: [@fibers_counter_id, @objects_counter_id],
393
+ extra_counter_track_uuids: @counts_fibers_and_objects,
335
394
  extra_counter_values: [count_fibers(1), count_allocations]
336
395
  )
337
396
  @packets << track_descriptor_packet(@did, fid, "Source Fiber ##{fid}")
@@ -385,7 +444,7 @@ module GraphQL
385
444
  track_uuid: fid,
386
445
  name: "Fiber Exit",
387
446
  category_iids: DATALOADER_CATEGORY_IIDS,
388
- extra_counter_track_uuids: [@fibers_counter_id],
447
+ extra_counter_track_uuids: @counts_fibers,
389
448
  extra_counter_values: [count_fibers(-1)],
390
449
  )
391
450
  super
@@ -415,31 +474,34 @@ module GraphQL
415
474
  fds = @flow_ids[source]
416
475
  fds_copy = fds.dup
417
476
  fds.clear
477
+
418
478
  packet = trace_packet(
419
479
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
420
480
  track_uuid: fid,
421
481
  name_iid: @source_name_iids[source.class],
422
482
  category_iids: DATALOADER_CATEGORY_IIDS,
423
483
  flow_ids: fds_copy,
424
- extra_counter_track_uuids: [@objects_counter_id],
425
- extra_counter_values: [count_allocations],
426
- debug_annotations: [
427
- payload_to_debug(nil, source.pending.values, iid: DA_FETCH_KEYS_IID, intern_value: true),
428
- *(source.instance_variables - [:@pending, :@fetching, :@results, :@dataloader]).map { |iv|
429
- payload_to_debug(iv.to_s, source.instance_variable_get(iv), intern_value: true)
430
- }
431
- ]
432
- )
484
+ extra_counter_track_uuids: @counts_objects,
485
+ extra_counter_values: [count_allocations]) {
486
+ [
487
+ payload_to_debug(nil, source.pending.values, iid: DA_FETCH_KEYS_IID, intern_value: true),
488
+ *(source.instance_variables - [:@pending, :@fetching, :@results, :@dataloader]).map { |iv|
489
+ payload_to_debug(iv.to_s, source.instance_variable_get(iv), intern_value: true)
490
+ }
491
+ ]
492
+ }
433
493
  @packets << packet
434
494
  fiber_flow_stack << packet
435
495
  super
436
496
  end
437
497
 
438
498
  def end_dataloader_source(source)
499
+ end_ts = ts
439
500
  @packets << trace_packet(
501
+ timestamp: end_ts,
440
502
  type: TrackEvent::Type::TYPE_SLICE_END,
441
503
  track_uuid: fid,
442
- extra_counter_track_uuids: [@objects_counter_id],
504
+ extra_counter_track_uuids: @counts_objects,
443
505
  extra_counter_values: [count_allocations],
444
506
  )
445
507
  fiber_flow_stack.pop
@@ -451,7 +513,7 @@ module GraphQL
451
513
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
452
514
  track_uuid: fid,
453
515
  category_iids: AUTHORIZED_CATEGORY_IIDS,
454
- extra_counter_track_uuids: [@objects_counter_id],
516
+ extra_counter_track_uuids: @counts_objects,
455
517
  extra_counter_values: [count_allocations],
456
518
  name_iid: @auth_name_iids[type],
457
519
  )
@@ -461,14 +523,18 @@ module GraphQL
461
523
  end
462
524
 
463
525
  def end_authorized(type, obj, ctx, is_authorized)
526
+ end_ts = ts
464
527
  @packets << trace_packet(
528
+ timestamp: end_ts,
465
529
  type: TrackEvent::Type::TYPE_SLICE_END,
466
530
  track_uuid: fid,
467
- extra_counter_track_uuids: [@objects_counter_id],
531
+ extra_counter_track_uuids: @counts_objects,
468
532
  extra_counter_values: [count_allocations],
469
533
  )
470
534
  beg_auth = fiber_flow_stack.pop
471
- beg_auth.track_event = dup_with(beg_auth.track_event, { debug_annotations: [payload_to_debug("authorized?", is_authorized)] })
535
+ if @create_debug_annotations
536
+ beg_auth.track_event = dup_with(beg_auth.track_event, { debug_annotations: [payload_to_debug("authorized?", is_authorized)] })
537
+ end
472
538
  super
473
539
  end
474
540
 
@@ -477,7 +543,7 @@ module GraphQL
477
543
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
478
544
  track_uuid: fid,
479
545
  category_iids: RESOLVE_TYPE_CATEGORY_IIDS,
480
- extra_counter_track_uuids: [@objects_counter_id],
546
+ extra_counter_track_uuids: @counts_objects,
481
547
  extra_counter_values: [count_allocations],
482
548
  name_iid: @resolve_type_name_iids[type],
483
549
  )
@@ -487,14 +553,18 @@ module GraphQL
487
553
  end
488
554
 
489
555
  def end_resolve_type(type, value, context, resolved_type)
556
+ end_ts = ts
490
557
  @packets << trace_packet(
558
+ timestamp: end_ts,
491
559
  type: TrackEvent::Type::TYPE_SLICE_END,
492
560
  track_uuid: fid,
493
- extra_counter_track_uuids: [@objects_counter_id],
561
+ extra_counter_track_uuids: @counts_objects,
494
562
  extra_counter_values: [count_allocations],
495
563
  )
496
564
  rt_begin = fiber_flow_stack.pop
497
- rt_begin.track_event = dup_with(rt_begin.track_event, { debug_annotations: [payload_to_debug("resolved_type", resolved_type, intern_value: true)] })
565
+ if @create_debug_annotations
566
+ rt_begin.track_event = dup_with(rt_begin.track_event, { debug_annotations: [payload_to_debug("resolved_type", resolved_type, intern_value: true)] })
567
+ end
498
568
  super
499
569
  end
500
570
 
@@ -535,6 +605,22 @@ module GraphQL
535
605
  Fiber.current.object_id
536
606
  end
537
607
 
608
+ class ArgumentsFilter
609
+ # From Rails defaults
610
+ # https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt#L6-L8
611
+ SENSITIVE_KEY = /passw|token|crypt|email|_key|salt|certificate|secret|ssn|cvv|cvc|otp/i
612
+ FILTERED = "[FILTERED]"
613
+
614
+ def filter_param(key, value)
615
+ if (key.is_a?(String) && SENSITIVE_KEY.match?(key)) ||
616
+ (key.is_a?(Symbol) && SENSITIVE_KEY.match?(key.name))
617
+ FILTERED
618
+ else
619
+ value
620
+ end
621
+ end
622
+ end
623
+
538
624
  def debug_annotation(iid, value_key, value)
539
625
  if iid
540
626
  DebugAnnotation.new(name_iid: iid, value_key => value)
@@ -546,7 +632,6 @@ module GraphQL
546
632
  def payload_to_debug(k, v, iid: nil, intern_value: false)
547
633
  if iid.nil?
548
634
  iid = @interned_da_name_ids[k]
549
- k = nil
550
635
  end
551
636
  case v
552
637
  when String
@@ -578,15 +663,56 @@ module GraphQL
578
663
  when Symbol
579
664
  debug_annotation(iid, :string_value, v.inspect)
580
665
  when Array
581
- debug_annotation(iid, :array_values, v.map { |v2| payload_to_debug(nil, v2, intern_value: intern_value) }.compact)
666
+ debug_annotation(iid, :array_values, v.each_with_index.map { |v2, idx| payload_to_debug((k ? "#{k}.#{idx}" : String(idx)), v2, intern_value: intern_value) }.compact)
582
667
  when Hash
583
- debug_annotation(iid, :dict_entries, v.map { |k2, v2| payload_to_debug(k2, v2, intern_value: intern_value) }.compact)
668
+ debug_v = v.map { |k2, v2|
669
+ debug_k = case k2
670
+ when String
671
+ k2
672
+ when Symbol
673
+ k2.name
674
+ else
675
+ String(k2)
676
+ end
677
+ filtered_v2 = @arguments_filter.filter_param(debug_k, v2)
678
+ payload_to_debug(debug_k, filtered_v2, intern_value: intern_value)
679
+ }
680
+ debug_v.compact!
681
+ debug_annotation(iid, :dict_entries, debug_v)
682
+ when GraphQL::Schema::InputObject
683
+ payload_to_debug(k, v.to_h, iid: iid, intern_value: intern_value)
584
684
  else
585
- debug_str = if defined?(ActiveRecord::Relation) && v.is_a?(ActiveRecord::Relation)
586
- "#{v.class}, .to_sql=#{v.to_sql.inspect}"
587
- else
588
- v.inspect
685
+ class_name_iid = @interned_da_string_values[(v.class.name || "(anonymous)")]
686
+ da = [
687
+ debug_annotation(DA_DEBUG_INSPECT_CLASS_IID, :string_value_iid, class_name_iid),
688
+ ]
689
+ if k
690
+ k_str_value_iid = @interned_da_string_values[k]
691
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, k_str_value_iid)
692
+ elsif iid
693
+ k = REVERSE_DEBUG_NAME_LOOKUP[iid] || @interned_da_name_ids.key(iid)
694
+ if k.nil?
695
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, DA_STR_VAL_NIL_IID)
696
+ else
697
+ k_str_value_iid = @interned_da_string_values[k]
698
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, k_str_value_iid)
699
+ end
589
700
  end
701
+
702
+ @packets << trace_packet(
703
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
704
+ track_uuid: fid,
705
+ name_iid: DEBUG_INSPECT_EVENT_NAME_IID,
706
+ category_iids: DEBUG_INSPECT_CATEGORY_IIDS,
707
+ extra_counter_track_uuids: @counts_objects,
708
+ extra_counter_values: [count_allocations],
709
+ debug_annotations: da,
710
+ )
711
+ debug_str = @detailed_trace.inspect_object(v)
712
+ @packets << trace_packet(
713
+ type: TrackEvent::Type::TYPE_SLICE_END,
714
+ track_uuid: fid,
715
+ )
590
716
  if intern_value
591
717
  str_iid = @interned_da_string_values[debug_str]
592
718
  debug_annotation(iid, :string_value_iid, str_iid)
@@ -622,10 +748,14 @@ module GraphQL
622
748
  Fiber[:graphql_flow_stack] ||= []
623
749
  end
624
750
 
625
- def trace_packet(event_attrs)
751
+ def trace_packet(timestamp: ts, **event_attrs)
752
+ if @create_debug_annotations && block_given?
753
+ event_attrs[:debug_annotations] = yield
754
+ end
755
+ track_event = TrackEvent.new(event_attrs)
626
756
  TracePacket.new(
627
- timestamp: ts,
628
- track_event: TrackEvent.new(event_attrs),
757
+ timestamp: timestamp,
758
+ track_event: track_event,
629
759
  trusted_packet_sequence_id: @sequence_id,
630
760
  sequence_flags: 2,
631
761
  interned_data: new_interned_data
@@ -690,9 +820,9 @@ module GraphQL
690
820
 
691
821
  def subscribe_to_active_support_notifications(pattern)
692
822
  @as_subscriber = ActiveSupport::Notifications.monotonic_subscribe(pattern) do |name, start, finish, id, payload|
693
- metadata = payload.map { |k, v| payload_to_debug(k, v, intern_value: true) }
694
- metadata.compact!
695
- te = if metadata.empty?
823
+ metadata = @create_debug_annotations ? payload.map { |k, v| payload_to_debug(String(k), v, intern_value: true) } : nil
824
+ metadata&.compact!
825
+ te = if metadata.nil? || metadata.empty?
696
826
  TrackEvent.new(
697
827
  type: TrackEvent::Type::TYPE_SLICE_BEGIN,
698
828
  track_uuid: fid,
@@ -721,7 +851,7 @@ module GraphQL
721
851
  type: TrackEvent::Type::TYPE_SLICE_END,
722
852
  track_uuid: fid,
723
853
  name: name,
724
- extra_counter_track_uuids: [@objects_counter_id],
854
+ extra_counter_track_uuids: @counts_objects,
725
855
  extra_counter_values: [count_allocations]
726
856
  ),
727
857
  trusted_packet_sequence_id: @sequence_id,
@@ -196,18 +196,20 @@ module GraphQL
196
196
  def edges
197
197
  # Assume that whatever authorization needed to happen
198
198
  # already happened at the connection level.
199
- current_runtime_state = Fiber[:__graphql_runtime_info]
200
- query_runtime_state = current_runtime_state[context.query]
201
- query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
199
+ if (current_runtime_state = Fiber[:__graphql_runtime_info])
200
+ query_runtime_state = current_runtime_state[context.query]
201
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
202
+ end
202
203
  @object.edges
203
204
  end
204
205
 
205
206
  def nodes
206
207
  # Assume that whatever authorization needed to happen
207
208
  # already happened at the connection level.
208
- current_runtime_state = Fiber[:__graphql_runtime_info]
209
- query_runtime_state = current_runtime_state[context.query]
210
- query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
209
+ if (current_runtime_state = Fiber[:__graphql_runtime_info])
210
+ query_runtime_state = current_runtime_state[context.query]
211
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
212
+ end
211
213
  @object.nodes
212
214
  end
213
215
  end
@@ -14,9 +14,10 @@ module GraphQL
14
14
  end
15
15
 
16
16
  def node
17
- current_runtime_state = Fiber[:__graphql_runtime_info]
18
- query_runtime_state = current_runtime_state[context.query]
19
- query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
17
+ if (current_runtime_state = Fiber[:__graphql_runtime_info])
18
+ query_runtime_state = current_runtime_state[context.query]
19
+ query_runtime_state.was_authorized_by_scope_items = @object.was_authorized_by_scope_items?
20
+ end
20
21
  @object.node
21
22
  end
22
23
 
@@ -7,6 +7,17 @@ module GraphQL
7
7
  module HasNodeField
8
8
  def self.included(child_class)
9
9
  child_class.field(**field_options, &field_block)
10
+ child_class.extend(ExecutionMethods)
11
+ end
12
+
13
+ module ExecutionMethods
14
+ def get_relay_node(context, id:)
15
+ context.schema.object_from_id(id, context)
16
+ end
17
+ end
18
+
19
+ def get_relay_node(id:)
20
+ self.class.get_relay_node(context, id: id)
10
21
  end
11
22
 
12
23
  class << self
@@ -17,6 +28,8 @@ module GraphQL
17
28
  null: true,
18
29
  description: "Fetches an object given its ID.",
19
30
  relay_node_field: true,
31
+ resolver_method: :get_relay_node,
32
+ resolve_static: :get_relay_node,
20
33
  }
21
34
  end
22
35
 
@@ -24,14 +37,6 @@ module GraphQL
24
37
  Proc.new {
25
38
  argument :id, "ID!",
26
39
  description: "ID of the object."
27
-
28
- def resolve(obj, args, ctx)
29
- ctx.schema.object_from_id(args[:id], ctx)
30
- end
31
-
32
- def resolve_field(obj, args, ctx)
33
- resolve(obj, args, ctx)
34
- end
35
40
  }
36
41
  end
37
42
  end
@@ -7,6 +7,17 @@ module GraphQL
7
7
  module HasNodesField
8
8
  def self.included(child_class)
9
9
  child_class.field(**field_options, &field_block)
10
+ child_class.extend(ExecutionMethods)
11
+ end
12
+
13
+ module ExecutionMethods
14
+ def get_relay_nodes(context, ids:)
15
+ ids.map { |id| context.schema.object_from_id(id, context) }
16
+ end
17
+ end
18
+
19
+ def get_relay_nodes(ids:)
20
+ self.class.get_relay_nodes(context, ids: ids)
10
21
  end
11
22
 
12
23
  class << self
@@ -17,6 +28,8 @@ module GraphQL
17
28
  null: false,
18
29
  description: "Fetches a list of objects given a list of IDs.",
19
30
  relay_nodes_field: true,
31
+ resolver_method: :get_relay_nodes,
32
+ resolve_static: :get_relay_nodes
20
33
  }
21
34
  end
22
35
 
@@ -24,14 +37,6 @@ module GraphQL
24
37
  Proc.new {
25
38
  argument :ids, "[ID!]!",
26
39
  description: "IDs of the objects."
27
-
28
- def resolve(obj, args, ctx)
29
- args[:ids].map { |id| ctx.schema.object_from_id(id, ctx) }
30
- end
31
-
32
- def resolve_field(obj, args, ctx)
33
- resolve(obj, args, ctx)
34
- end
35
40
  }
36
41
  end
37
42
  end
@@ -6,12 +6,13 @@ module GraphQL
6
6
  module NodeBehaviors
7
7
  def self.included(child_module)
8
8
  child_module.extend(ClassMethods)
9
+ child_module.extend(ExecutionMethods)
9
10
  child_module.description("An object with an ID.")
10
- child_module.field(:id, ID, null: false, description: "ID of the object.", resolver_method: :default_global_id)
11
+ child_module.field(:id, ID, null: false, description: "ID of the object.", resolver_method: :default_global_id, resolve_each: :default_global_id)
11
12
  end
12
13
 
13
14
  def default_global_id
14
- context.schema.id_from_object(object, self.class, context)
15
+ self.class.default_global_id(object, context)
15
16
  end
16
17
 
17
18
  module ClassMethods
@@ -19,6 +20,16 @@ module GraphQL
19
20
  true
20
21
  end
21
22
  end
23
+
24
+ module ExecutionMethods
25
+ def default_global_id(object, context)
26
+ context.schema.id_from_object(object, self, context)
27
+ end
28
+
29
+ def included(child_class)
30
+ child_class.extend(ExecutionMethods)
31
+ end
32
+ end
22
33
  end
23
34
  end
24
35
  end