graphql 1.6.8 → 1.7.0

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 (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