graphql 1.6.8 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +5 -0
  3. data/lib/graphql/analysis/analyze_query.rb +21 -17
  4. data/lib/graphql/argument.rb +6 -2
  5. data/lib/graphql/backtrace.rb +50 -0
  6. data/lib/graphql/backtrace/inspect_result.rb +51 -0
  7. data/lib/graphql/backtrace/table.rb +120 -0
  8. data/lib/graphql/backtrace/traced_error.rb +55 -0
  9. data/lib/graphql/backtrace/tracer.rb +50 -0
  10. data/lib/graphql/enum_type.rb +1 -10
  11. data/lib/graphql/execution.rb +1 -2
  12. data/lib/graphql/execution/execute.rb +98 -89
  13. data/lib/graphql/execution/flatten.rb +40 -0
  14. data/lib/graphql/execution/lazy/resolve.rb +7 -7
  15. data/lib/graphql/execution/multiplex.rb +29 -29
  16. data/lib/graphql/field.rb +5 -1
  17. data/lib/graphql/internal_representation/node.rb +16 -0
  18. data/lib/graphql/invalid_name_error.rb +11 -0
  19. data/lib/graphql/language/parser.rb +11 -5
  20. data/lib/graphql/language/parser.y +11 -5
  21. data/lib/graphql/name_validator.rb +16 -0
  22. data/lib/graphql/object_type.rb +5 -0
  23. data/lib/graphql/query.rb +28 -7
  24. data/lib/graphql/query/context.rb +155 -52
  25. data/lib/graphql/query/literal_input.rb +36 -9
  26. data/lib/graphql/query/null_context.rb +7 -1
  27. data/lib/graphql/query/result.rb +63 -0
  28. data/lib/graphql/query/serial_execution/field_resolution.rb +3 -4
  29. data/lib/graphql/query/serial_execution/value_resolution.rb +3 -4
  30. data/lib/graphql/query/variables.rb +1 -1
  31. data/lib/graphql/schema.rb +31 -0
  32. data/lib/graphql/schema/traversal.rb +16 -1
  33. data/lib/graphql/schema/warden.rb +40 -4
  34. data/lib/graphql/static_validation/validator.rb +20 -18
  35. data/lib/graphql/subscriptions.rb +129 -0
  36. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +122 -0
  37. data/lib/graphql/subscriptions/event.rb +52 -0
  38. data/lib/graphql/subscriptions/instrumentation.rb +68 -0
  39. data/lib/graphql/tracing.rb +80 -0
  40. data/lib/graphql/tracing/active_support_notifications_tracing.rb +31 -0
  41. data/lib/graphql/version.rb +1 -1
  42. data/readme.md +1 -1
  43. data/spec/graphql/analysis/analyze_query_spec.rb +19 -0
  44. data/spec/graphql/argument_spec.rb +28 -0
  45. data/spec/graphql/backtrace_spec.rb +144 -0
  46. data/spec/graphql/define/assign_argument_spec.rb +12 -0
  47. data/spec/graphql/enum_type_spec.rb +1 -1
  48. data/spec/graphql/execution/execute_spec.rb +66 -0
  49. data/spec/graphql/execution/lazy_spec.rb +4 -3
  50. data/spec/graphql/language/parser_spec.rb +16 -0
  51. data/spec/graphql/object_type_spec.rb +14 -0
  52. data/spec/graphql/query/context_spec.rb +134 -27
  53. data/spec/graphql/query/result_spec.rb +29 -0
  54. data/spec/graphql/query/variables_spec.rb +13 -0
  55. data/spec/graphql/query_spec.rb +22 -0
  56. data/spec/graphql/schema/build_from_definition_spec.rb +2 -0
  57. data/spec/graphql/schema/traversal_spec.rb +70 -12
  58. data/spec/graphql/schema/warden_spec.rb +67 -1
  59. data/spec/graphql/schema_spec.rb +29 -0
  60. data/spec/graphql/static_validation/validator_spec.rb +16 -0
  61. data/spec/graphql/subscriptions_spec.rb +331 -0
  62. data/spec/graphql/tracing/active_support_notifications_tracing_spec.rb +57 -0
  63. data/spec/graphql/tracing_spec.rb +47 -0
  64. data/spec/spec_helper.rb +32 -0
  65. data/spec/support/star_wars/schema.rb +39 -0
  66. metadata +27 -4
  67. data/lib/graphql/execution/field_result.rb +0 -54
  68. data/lib/graphql/execution/selection_result.rb +0 -90
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Tracing::ActiveSupportNotificationsTracing do
5
+ before do
6
+ GraphQL::Tracing.install(GraphQL::Tracing::ActiveSupportNotificationsTracing)
7
+ end
8
+
9
+ after do
10
+ GraphQL::Tracing.uninstall(GraphQL::Tracing::ActiveSupportNotificationsTracing)
11
+ end
12
+
13
+ it "pushes through AS::N" do
14
+ traces = []
15
+
16
+ callback = ->(name, started, finished, id, data) {
17
+ traces << name
18
+ }
19
+
20
+ query_string = <<-GRAPHQL
21
+ query Bases($id1: ID!, $id2: ID!){
22
+ b1: batchedBase(id: $id1) { name }
23
+ b2: batchedBase(id: $id2) { name }
24
+ }
25
+ GRAPHQL
26
+ first_id = StarWars::Base.first.id
27
+ last_id = StarWars::Base.last.id
28
+
29
+ ActiveSupport::Notifications.subscribed(callback, /^graphql/) do
30
+ star_wars_query(query_string, {
31
+ "id1" => first_id,
32
+ "id2" => last_id,
33
+ })
34
+ end
35
+
36
+ expected_traces = [
37
+ "graphql.lex",
38
+ "graphql.parse",
39
+ "graphql.validate",
40
+ "graphql.analyze_query",
41
+ "graphql.analyze_multiplex",
42
+ "graphql.execute_field",
43
+ "graphql.execute_field",
44
+ "graphql.execute_query",
45
+ "graphql.lazy_loader",
46
+ "graphql.execute_field",
47
+ "graphql.execute_field_lazy",
48
+ "graphql.execute_field",
49
+ "graphql.execute_field_lazy",
50
+ "graphql.execute_field_lazy",
51
+ "graphql.execute_field_lazy",
52
+ "graphql.execute_query_lazy",
53
+ "graphql.execute_multiplex",
54
+ ]
55
+ assert_equal expected_traces, traces
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe GraphQL::Tracing do
5
+ describe ".trace" do
6
+ it "delivers the metadata to send_trace, with result and key" do
7
+ returned_value = nil
8
+ traces = TestTracing.with_trace do
9
+ returned_value = GraphQL::Tracing.trace("something", { some_stuff: true }) do
10
+ "do stuff"
11
+ end
12
+ end
13
+
14
+ assert_equal 1, traces.length
15
+ trace = traces.first
16
+ assert_equal "something", trace[:key]
17
+ assert_equal true, trace[:some_stuff]
18
+ # Any override of .trace must return the block's return value
19
+ assert_equal "do stuff", returned_value
20
+ end
21
+
22
+ module OtherRandomTracer
23
+ CALLS = []
24
+
25
+ def self.trace(key, metadata)
26
+ CALLS << key.upcase
27
+ yield
28
+ end
29
+ end
30
+
31
+ it "calls multiple tracers" do
32
+ OtherRandomTracer::CALLS.clear
33
+ GraphQL::Tracing.install(OtherRandomTracer)
34
+ # Duplicate install is a no-op
35
+ GraphQL::Tracing.install(OtherRandomTracer)
36
+
37
+ traces = TestTracing.with_trace do
38
+ GraphQL::Tracing.trace("stuff", { }) { :stuff }
39
+ end
40
+
41
+ assert_equal ["stuff"], traces.map { |t| t[:key] }
42
+ assert_equal ["STUFF"], OtherRandomTracer::CALLS
43
+
44
+ GraphQL::Tracing.uninstall(OtherRandomTracer)
45
+ end
46
+ end
47
+ end
data/spec/spec_helper.rb CHANGED
@@ -67,3 +67,35 @@ end
67
67
  def star_wars_query(string, variables={}, context: {})
68
68
  GraphQL::Query.new(StarWars::Schema, string, variables: variables, context: context).result
69
69
  end
70
+
71
+ module TestTracing
72
+ class << self
73
+ def clear
74
+ traces.clear
75
+ end
76
+
77
+ def traces
78
+ @traces ||= []
79
+ end
80
+
81
+ def with_trace
82
+ GraphQL::Tracing.install(self)
83
+ clear
84
+ yield
85
+ GraphQL::Tracing.uninstall(self)
86
+ traces
87
+ end
88
+
89
+ def trace(key, data)
90
+ data[:key] = key
91
+ result = yield
92
+ data[:result] = result
93
+ traces << data
94
+ result
95
+ end
96
+ end
97
+ end
98
+
99
+ if rails_should_be_installed?
100
+ GraphQL::Tracing.uninstall(GraphQL::Tracing::ActiveSupportNotificationsTracing)
101
+ end
@@ -265,6 +265,37 @@ module StarWars
265
265
  function IntroduceShipFunction.new
266
266
  end
267
267
 
268
+ # GraphQL-Batch knockoff
269
+ class LazyLoader
270
+ def self.defer(ctx, model, id)
271
+ ids = ctx.namespace(:loading)[model] ||= []
272
+ ids << id
273
+ self.new(model: model, id: id, context: ctx)
274
+ end
275
+
276
+ def initialize(model:, id:, context:)
277
+ @model = model
278
+ @id = id
279
+ @context = context
280
+ end
281
+
282
+ def value
283
+ loaded = @context.namespace(:loaded)[@model] ||= {}
284
+ if loaded.empty?
285
+ ids = @context.namespace(:loading)[@model]
286
+ # Example custom tracing
287
+ GraphQL::Tracing.trace("lazy_loader", { ids: ids, model: @model}) do
288
+ records = @model.where(id: ids)
289
+ records.each do |record|
290
+ loaded[record.id.to_s] = record
291
+ end
292
+ end
293
+ end
294
+
295
+ loaded[@id]
296
+ end
297
+ end
298
+
268
299
  class LazyWrapper
269
300
  def initialize(value = nil, &block)
270
301
  if block_given?
@@ -332,6 +363,13 @@ module StarWars
332
363
  field :nodesWithCustomResolver, GraphQL::Relay::Node.plural_field(
333
364
  resolve: ->(_, _, _) { [StarWars::DATA["Faction"]["1"], StarWars::DATA["Faction"]["2"]] }
334
365
  )
366
+
367
+ field :batchedBase, BaseType do
368
+ argument :id, !types.ID
369
+ resolve ->(o, a, c) {
370
+ LazyLoader.defer(c, Base, a["id"])
371
+ }
372
+ end
335
373
  end
336
374
 
337
375
  MutationType = GraphQL::ObjectType.define do
@@ -390,6 +428,7 @@ module StarWars
390
428
  end
391
429
 
392
430
  lazy_resolve(LazyWrapper, :value)
431
+ lazy_resolve(LazyLoader, :value)
393
432
 
394
433
  instrument(:field, ClassNameRecorder.new(:before_built_ins))
395
434
  instrument(:field, ClassNameRecorder.new(:after_built_ins), after_built_ins: true)
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: 1.6.8
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-08 00:00:00.000000000 Z
11
+ date: 2017-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -317,6 +317,11 @@ files:
317
317
  - lib/graphql/analysis/reducer_state.rb
318
318
  - lib/graphql/analysis_error.rb
319
319
  - lib/graphql/argument.rb
320
+ - lib/graphql/backtrace.rb
321
+ - lib/graphql/backtrace/inspect_result.rb
322
+ - lib/graphql/backtrace/table.rb
323
+ - lib/graphql/backtrace/traced_error.rb
324
+ - lib/graphql/backtrace/tracer.rb
320
325
  - lib/graphql/backwards_compatibility.rb
321
326
  - lib/graphql/base_type.rb
322
327
  - lib/graphql/boolean_type.rb
@@ -350,12 +355,11 @@ files:
350
355
  - lib/graphql/execution.rb
351
356
  - lib/graphql/execution/directive_checks.rb
352
357
  - lib/graphql/execution/execute.rb
353
- - lib/graphql/execution/field_result.rb
358
+ - lib/graphql/execution/flatten.rb
354
359
  - lib/graphql/execution/lazy.rb
355
360
  - lib/graphql/execution/lazy/lazy_method_map.rb
356
361
  - lib/graphql/execution/lazy/resolve.rb
357
362
  - lib/graphql/execution/multiplex.rb
358
- - lib/graphql/execution/selection_result.rb
359
363
  - lib/graphql/execution/typecast.rb
360
364
  - lib/graphql/execution_error.rb
361
365
  - lib/graphql/field.rb
@@ -394,6 +398,7 @@ files:
394
398
  - lib/graphql/introspection/type_kind_enum.rb
395
399
  - lib/graphql/introspection/type_type.rb
396
400
  - lib/graphql/introspection/typename_field.rb
401
+ - lib/graphql/invalid_name_error.rb
397
402
  - lib/graphql/invalid_null_error.rb
398
403
  - lib/graphql/language.rb
399
404
  - lib/graphql/language/comments.rb
@@ -407,6 +412,7 @@ files:
407
412
  - lib/graphql/language/token.rb
408
413
  - lib/graphql/language/visitor.rb
409
414
  - lib/graphql/list_type.rb
415
+ - lib/graphql/name_validator.rb
410
416
  - lib/graphql/non_null_type.rb
411
417
  - lib/graphql/object_type.rb
412
418
  - lib/graphql/parse_error.rb
@@ -418,6 +424,7 @@ files:
418
424
  - lib/graphql/query/input_validation_result.rb
419
425
  - lib/graphql/query/literal_input.rb
420
426
  - lib/graphql/query/null_context.rb
427
+ - lib/graphql/query/result.rb
421
428
  - lib/graphql/query/serial_execution.rb
422
429
  - lib/graphql/query/serial_execution/field_resolution.rb
423
430
  - lib/graphql/query/serial_execution/operation_resolution.rb
@@ -504,6 +511,12 @@ files:
504
511
  - lib/graphql/static_validation/validator.rb
505
512
  - lib/graphql/string_encoding_error.rb
506
513
  - lib/graphql/string_type.rb
514
+ - lib/graphql/subscriptions.rb
515
+ - lib/graphql/subscriptions/action_cable_subscriptions.rb
516
+ - lib/graphql/subscriptions/event.rb
517
+ - lib/graphql/subscriptions/instrumentation.rb
518
+ - lib/graphql/tracing.rb
519
+ - lib/graphql/tracing/active_support_notifications_tracing.rb
507
520
  - lib/graphql/type_kinds.rb
508
521
  - lib/graphql/union_type.rb
509
522
  - lib/graphql/unresolved_type_error.rb
@@ -524,6 +537,7 @@ files:
524
537
  - spec/graphql/analysis/query_complexity_spec.rb
525
538
  - spec/graphql/analysis/query_depth_spec.rb
526
539
  - spec/graphql/argument_spec.rb
540
+ - spec/graphql/backtrace_spec.rb
527
541
  - spec/graphql/base_type_spec.rb
528
542
  - spec/graphql/boolean_type_spec.rb
529
543
  - spec/graphql/compatibility/execution_specification_spec.rb
@@ -569,6 +583,7 @@ files:
569
583
  - spec/graphql/query/context_spec.rb
570
584
  - spec/graphql/query/executor_spec.rb
571
585
  - spec/graphql/query/literal_input_spec.rb
586
+ - spec/graphql/query/result_spec.rb
572
587
  - spec/graphql/query/serial_execution/value_resolution_spec.rb
573
588
  - spec/graphql/query/variables_spec.rb
574
589
  - spec/graphql/query_spec.rb
@@ -624,6 +639,9 @@ files:
624
639
  - spec/graphql/static_validation/type_stack_spec.rb
625
640
  - spec/graphql/static_validation/validator_spec.rb
626
641
  - spec/graphql/string_type_spec.rb
642
+ - spec/graphql/subscriptions_spec.rb
643
+ - spec/graphql/tracing/active_support_notifications_tracing_spec.rb
644
+ - spec/graphql/tracing_spec.rb
627
645
  - spec/graphql/union_type_spec.rb
628
646
  - spec/rails_dependency_sanity_spec.rb
629
647
  - spec/spec_helper.rb
@@ -679,6 +697,7 @@ test_files:
679
697
  - spec/graphql/analysis/query_complexity_spec.rb
680
698
  - spec/graphql/analysis/query_depth_spec.rb
681
699
  - spec/graphql/argument_spec.rb
700
+ - spec/graphql/backtrace_spec.rb
682
701
  - spec/graphql/base_type_spec.rb
683
702
  - spec/graphql/boolean_type_spec.rb
684
703
  - spec/graphql/compatibility/execution_specification_spec.rb
@@ -724,6 +743,7 @@ test_files:
724
743
  - spec/graphql/query/context_spec.rb
725
744
  - spec/graphql/query/executor_spec.rb
726
745
  - spec/graphql/query/literal_input_spec.rb
746
+ - spec/graphql/query/result_spec.rb
727
747
  - spec/graphql/query/serial_execution/value_resolution_spec.rb
728
748
  - spec/graphql/query/variables_spec.rb
729
749
  - spec/graphql/query_spec.rb
@@ -779,6 +799,9 @@ test_files:
779
799
  - spec/graphql/static_validation/type_stack_spec.rb
780
800
  - spec/graphql/static_validation/validator_spec.rb
781
801
  - spec/graphql/string_type_spec.rb
802
+ - spec/graphql/subscriptions_spec.rb
803
+ - spec/graphql/tracing/active_support_notifications_tracing_spec.rb
804
+ - spec/graphql/tracing_spec.rb
782
805
  - spec/graphql/union_type_spec.rb
783
806
  - spec/rails_dependency_sanity_spec.rb
784
807
  - spec/spec_helper.rb
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Execution
4
- # This is one key-value pair in a GraphQL response.
5
- # @api private
6
- class FieldResult
7
- # @return [Any, Lazy] the GraphQL-ready response value, or a {Lazy} instance
8
- attr_reader :value
9
-
10
- # @return [SelectionResult] The result object that this field belongs to
11
- attr_reader :owner
12
-
13
- def initialize(type:, value:, owner:)
14
- @type = type
15
- @owner = owner
16
- self.value = value
17
- end
18
-
19
- # Set a new value for this field in the response.
20
- # It may be updated after resolving a {Lazy}.
21
- # If it is {Execute::PROPAGATE_NULL}, tell the owner to propagate null.
22
- # If the value is a {SelectionResult}, make a link with it, and if it's already null,
23
- # propagate the null as needed.
24
- # If it's {Execute::Execution::SKIP}, remove this field result from its parent
25
- # @param new_value [Any] The GraphQL-ready value
26
- def value=(new_value)
27
- if new_value.is_a?(SelectionResult)
28
- if new_value.invalid_null?
29
- new_value = GraphQL::Execution::Execute::PROPAGATE_NULL
30
- else
31
- new_value.owner = self
32
- end
33
- end
34
-
35
- case new_value
36
- when GraphQL::Execution::Execute::PROPAGATE_NULL
37
- if @type.kind.non_null?
38
- @owner.propagate_null
39
- else
40
- @value = nil
41
- end
42
- when GraphQL::Execution::Execute::SKIP
43
- @owner.delete(self)
44
- else
45
- @value = new_value
46
- end
47
- end
48
-
49
- def inspect
50
- "#<FieldResult #{value.inspect} (#{@type})>"
51
- end
52
- end
53
- end
54
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Execution
4
- # A set of key-value pairs suitable for a GraphQL response.
5
- # @api private
6
- class SelectionResult
7
- def initialize
8
- @storage = {}
9
- @owner = nil
10
- @invalid_null = false
11
- end
12
-
13
- # @param key [String] The name for this value in the result
14
- # @param field_result [FieldResult] The result for this field
15
- def set(key, field_result)
16
- @storage[key] = field_result
17
- end
18
-
19
- # @param key [String] The name of an already-defined result
20
- # @return [FieldResult] The result for this field
21
- def fetch(key)
22
- @storage.fetch(key)
23
- end
24
-
25
- # Visit each key-result pair in this result
26
- def each
27
- @storage.each do |key, field_res|
28
- yield(key, field_res)
29
- end
30
- end
31
-
32
- # @return [Hash] A plain Hash representation of this result
33
- def to_h
34
- if @invalid_null
35
- nil
36
- else
37
- flatten(self)
38
- end
39
- end
40
-
41
- # TODO this should delete by key, ya dummy
42
- def delete(field_result)
43
- @storage.delete_if { |k, v| v == field_result }
44
- end
45
-
46
- # A field has been unexpectedly nullified.
47
- # Tell the owner {FieldResult} if it is present.
48
- # Record {#invalid_null} in case an owner is added later.
49
- def propagate_null
50
- if @owner
51
- @owner.value = GraphQL::Execution::Execute::PROPAGATE_NULL
52
- end
53
- @invalid_null = true
54
- end
55
-
56
- # @return [Boolean] True if this selection has been nullified by a null child
57
- def invalid_null?
58
- @invalid_null
59
- end
60
-
61
- # @param field_result [FieldResult] The field that this selection belongs to (used for propagating nulls)
62
- def owner=(field_result)
63
- if @owner
64
- raise("Can't change owners of SelectionResult")
65
- else
66
- @owner = field_result
67
- end
68
- end
69
-
70
- private
71
-
72
- def flatten(obj)
73
- case obj
74
- when SelectionResult
75
- flattened = {}
76
- obj.each do |key, val|
77
- flattened[key] = flatten(val)
78
- end
79
- flattened
80
- when Array
81
- obj.map { |v| flatten(v) }
82
- when FieldResult
83
- flatten(obj.value)
84
- else
85
- obj
86
- end
87
- end
88
- end
89
- end
90
- end