graphql 1.5.15 → 1.6.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +4 -19
  3. data/lib/graphql/analysis/analyze_query.rb +27 -2
  4. data/lib/graphql/analysis/query_complexity.rb +10 -11
  5. data/lib/graphql/argument.rb +7 -6
  6. data/lib/graphql/backwards_compatibility.rb +47 -0
  7. data/lib/graphql/compatibility/execution_specification.rb +14 -0
  8. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +6 -1
  9. data/lib/graphql/compatibility/lazy_execution_specification.rb +19 -0
  10. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +15 -6
  11. data/lib/graphql/directive.rb +1 -6
  12. data/lib/graphql/execution.rb +1 -0
  13. data/lib/graphql/execution/execute.rb +174 -160
  14. data/lib/graphql/execution/field_result.rb +5 -1
  15. data/lib/graphql/execution/lazy.rb +2 -2
  16. data/lib/graphql/execution/lazy/resolve.rb +8 -11
  17. data/lib/graphql/execution/multiplex.rb +134 -0
  18. data/lib/graphql/execution/selection_result.rb +5 -0
  19. data/lib/graphql/field.rb +1 -8
  20. data/lib/graphql/filter.rb +53 -0
  21. data/lib/graphql/internal_representation/node.rb +11 -6
  22. data/lib/graphql/internal_representation/rewrite.rb +3 -3
  23. data/lib/graphql/query.rb +160 -78
  24. data/lib/graphql/query/arguments.rb +14 -25
  25. data/lib/graphql/query/arguments_cache.rb +6 -13
  26. data/lib/graphql/query/context.rb +28 -10
  27. data/lib/graphql/query/executor.rb +1 -0
  28. data/lib/graphql/query/literal_input.rb +10 -4
  29. data/lib/graphql/query/null_context.rb +1 -1
  30. data/lib/graphql/query/serial_execution/field_resolution.rb +5 -1
  31. data/lib/graphql/query/validation_pipeline.rb +12 -7
  32. data/lib/graphql/query/variables.rb +1 -1
  33. data/lib/graphql/rake_task.rb +140 -0
  34. data/lib/graphql/relay/array_connection.rb +29 -48
  35. data/lib/graphql/relay/base_connection.rb +9 -7
  36. data/lib/graphql/relay/mutation.rb +0 -11
  37. data/lib/graphql/relay/mutation/instrumentation.rb +2 -2
  38. data/lib/graphql/relay/mutation/resolve.rb +7 -10
  39. data/lib/graphql/relay/relation_connection.rb +98 -61
  40. data/lib/graphql/scalar_type.rb +1 -15
  41. data/lib/graphql/schema.rb +90 -25
  42. data/lib/graphql/schema/build_from_definition.rb +22 -23
  43. data/lib/graphql/schema/build_from_definition/resolve_map.rb +70 -0
  44. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
  45. data/lib/graphql/schema/middleware_chain.rb +1 -1
  46. data/lib/graphql/schema/printer.rb +2 -1
  47. data/lib/graphql/schema/timeout_middleware.rb +6 -6
  48. data/lib/graphql/schema/type_map.rb +1 -1
  49. data/lib/graphql/schema/warden.rb +5 -9
  50. data/lib/graphql/static_validation/definition_dependencies.rb +1 -1
  51. data/lib/graphql/version.rb +1 -1
  52. data/spec/graphql/analysis/analyze_query_spec.rb +2 -2
  53. data/spec/graphql/analysis/max_query_complexity_spec.rb +28 -0
  54. data/spec/graphql/argument_spec.rb +3 -3
  55. data/spec/graphql/execution/lazy_spec.rb +8 -114
  56. data/spec/graphql/execution/multiplex_spec.rb +131 -0
  57. data/spec/graphql/internal_representation/rewrite_spec.rb +10 -0
  58. data/spec/graphql/query/arguments_spec.rb +14 -16
  59. data/spec/graphql/query/context_spec.rb +14 -1
  60. data/spec/graphql/query/literal_input_spec.rb +19 -13
  61. data/spec/graphql/query/variables_spec.rb +1 -1
  62. data/spec/graphql/query_spec.rb +12 -1
  63. data/spec/graphql/rake_task_spec.rb +57 -0
  64. data/spec/graphql/relay/array_connection_spec.rb +24 -3
  65. data/spec/graphql/relay/connection_instrumentation_spec.rb +23 -0
  66. data/spec/graphql/relay/mutation_spec.rb +2 -10
  67. data/spec/graphql/relay/page_info_spec.rb +2 -2
  68. data/spec/graphql/relay/relation_connection_spec.rb +167 -3
  69. data/spec/graphql/schema/build_from_definition_spec.rb +93 -19
  70. data/spec/graphql/schema/warden_spec.rb +80 -0
  71. data/spec/graphql/schema_spec.rb +26 -2
  72. data/spec/spec_helper.rb +4 -2
  73. data/spec/support/lazy_helpers.rb +152 -0
  74. data/spec/support/star_wars/schema.rb +23 -0
  75. metadata +28 -3
  76. data/lib/graphql/schema/mask.rb +0 -55
@@ -228,6 +228,21 @@ type Query {
228
228
  end
229
229
  end
230
230
 
231
+ # Use this to assert instrumenters are called as a stack
232
+ class StackCheckInstrumenter
233
+ def initialize(counter)
234
+ @counter = counter
235
+ end
236
+
237
+ def before_query(query)
238
+ @counter.counts << :in
239
+ end
240
+
241
+ def after_query(query)
242
+ @counter.counts << :out
243
+ end
244
+ end
245
+
231
246
  let(:variable_counter) {
232
247
  VariableCountInstrumenter.new
233
248
  }
@@ -246,6 +261,7 @@ type Query {
246
261
  GraphQL::Schema.define do
247
262
  query(spec.query_type)
248
263
  instrument(:field, MultiplyInstrumenter.new(3))
264
+ instrument(:query, StackCheckInstrumenter.new(spec.variable_counter))
249
265
  instrument(:query, spec.variable_counter)
250
266
  end
251
267
  }
@@ -258,7 +274,7 @@ type Query {
258
274
  it "can wrap query execution" do
259
275
  schema.execute("query getInt($val: Int = 5){ int(value: $val) } ")
260
276
  schema.execute("query getInt($val: Int = 5, $val2: Int = 3){ int(value: $val) int2: int(value: $val2) } ")
261
- assert_equal [1, :end, 2, :end], variable_counter.counts
277
+ assert_equal [:in, 1, :end, :out, :in, 2, :end, :out], variable_counter.counts
262
278
  end
263
279
 
264
280
  it "runs even when a runtime error occurs" do
@@ -266,7 +282,7 @@ type Query {
266
282
  assert_raises(RuntimeError) {
267
283
  schema.execute("query getInt($val: Int = 13){ int(value: $val) } ")
268
284
  }
269
- assert_equal [1, :end, 1, :end], variable_counter.counts
285
+ assert_equal [:in, 1, :end, :out, :in, 1, :end, :out], variable_counter.counts
270
286
  end
271
287
 
272
288
  it "can be applied after the fact" do
@@ -336,4 +352,12 @@ type Query {
336
352
  assert_equal([], errors)
337
353
  end
338
354
  end
355
+
356
+ describe "#as_json / #to_json" do
357
+ it "returns the instrospection result" do
358
+ result = schema.execute(GraphQL::Introspection::INTROSPECTION_QUERY)
359
+ assert_equal result, schema.as_json
360
+ assert_equal result, JSON.parse(schema.to_json)
361
+ end
362
+ end
339
363
  end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
  require "codeclimate-test-reporter"
3
3
  CodeClimate::TestReporter.start
4
+ require "rake"
4
5
  require "rails/all"
5
6
  require "rails/generators"
6
7
  require "jdbc/sqlite3" if RUBY_ENGINE == 'jruby'
7
8
  require "sqlite3" if RUBY_ENGINE == 'ruby'
8
9
  require "sequel"
9
10
  require "graphql"
11
+ require "graphql/rake_task"
10
12
  require "benchmark"
11
13
  require "minitest/autorun"
12
14
  require "minitest/focus"
@@ -37,6 +39,6 @@ end
37
39
  # Load support files
38
40
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
39
41
 
40
- def star_wars_query(string, variables={})
41
- GraphQL::Query.new(StarWars::Schema, string, variables: variables).result
42
+ def star_wars_query(string, variables={}, context: {})
43
+ GraphQL::Query.new(StarWars::Schema, string, variables: variables, context: context).result
42
44
  end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+ module LazyHelpers
3
+ class Wrapper
4
+ def initialize(item = nil, &block)
5
+ if block
6
+ @block = block
7
+ else
8
+ @item = item
9
+ end
10
+ end
11
+
12
+ def item
13
+ if @block
14
+ @item = @block.call()
15
+ @block = nil
16
+ end
17
+ @item
18
+ end
19
+ end
20
+
21
+ class SumAll
22
+ attr_reader :own_value
23
+ attr_accessor :value
24
+
25
+ def initialize(ctx, own_value)
26
+ @own_value = own_value
27
+ all << self
28
+ end
29
+
30
+ def value
31
+ @value ||= begin
32
+ total_value = all.map(&:own_value).reduce(&:+)
33
+ all.each { |v| v.value = total_value}
34
+ all.clear
35
+ total_value
36
+ end
37
+ @value
38
+ end
39
+
40
+ def all
41
+ self.class.all
42
+ end
43
+
44
+ def self.all
45
+ @all ||= []
46
+ end
47
+ end
48
+
49
+ LazySum = GraphQL::ObjectType.define do
50
+ name "LazySum"
51
+ field :value, types.Int do
52
+ resolve ->(o, a, c) { o == 13 ? nil : o }
53
+ end
54
+ field :nestedSum, !LazySum do
55
+ argument :value, !types.Int
56
+ resolve ->(o, args, c) {
57
+ if args[:value] == 13
58
+ Wrapper.new(nil)
59
+ else
60
+ SumAll.new(c, o + args[:value])
61
+ end
62
+ }
63
+ end
64
+
65
+ field :nullableNestedSum, LazySum do
66
+ argument :value, types.Int
67
+ resolve ->(o, args, c) {
68
+ if args[:value] == 13
69
+ Wrapper.new(nil)
70
+ else
71
+ SumAll.new(c, o + args[:value])
72
+ end
73
+ }
74
+ end
75
+ end
76
+
77
+ LazyQuery = GraphQL::ObjectType.define do
78
+ name "Query"
79
+ field :int, !types.Int do
80
+ argument :value, !types.Int
81
+ argument :plus, types.Int, default_value: 0
82
+ resolve ->(o, a, c) { Wrapper.new(a[:value] + a[:plus])}
83
+ end
84
+
85
+ field :nestedSum, !LazySum do
86
+ argument :value, !types.Int
87
+ resolve ->(o, args, c) { SumAll.new(c, args[:value]) }
88
+ end
89
+
90
+ field :nullableNestedSum, LazySum do
91
+ argument :value, types.Int
92
+ resolve ->(o, args, c) {
93
+ if args[:value] == 13
94
+ Wrapper.new { raise GraphQL::ExecutionError.new("13 is unlucky") }
95
+ else
96
+ SumAll.new(c, args[:value])
97
+ end
98
+ }
99
+ end
100
+
101
+ field :listSum, types[LazySum] do
102
+ argument :values, types[types.Int]
103
+ resolve ->(o, args, c) { args[:values] }
104
+ end
105
+ end
106
+
107
+ class SumAllInstrumentation
108
+ def initialize(counter:)
109
+ @counter = counter
110
+ end
111
+
112
+ def before_query(q)
113
+ add_check(q, "before #{q.selected_operation.name}")
114
+ # TODO not threadsafe
115
+ # This should use multiplex-level context
116
+ SumAll.all.clear
117
+ end
118
+
119
+ def after_query(q)
120
+ add_check(q, "after #{q.selected_operation.name}")
121
+ end
122
+
123
+ def before_multiplex(multiplex)
124
+ add_check(multiplex, "before multiplex #@counter")
125
+ end
126
+
127
+ def after_multiplex(multiplex)
128
+ add_check(multiplex, "after multiplex #@counter")
129
+ end
130
+
131
+ def add_check(obj, text)
132
+ checks = obj.context[:instrumentation_checks]
133
+ if checks
134
+ checks << text
135
+ end
136
+ end
137
+ end
138
+
139
+ LazySchema = GraphQL::Schema.define do
140
+ query(LazyQuery)
141
+ mutation(LazyQuery)
142
+ lazy_resolve(Wrapper, :item)
143
+ lazy_resolve(SumAll, :value)
144
+ instrument(:query, SumAllInstrumentation.new(counter: nil))
145
+ instrument(:multiplex, SumAllInstrumentation.new(counter: 1))
146
+ instrument(:multiplex, SumAllInstrumentation.new(counter: 2))
147
+ end
148
+
149
+ def run_query(query_str)
150
+ LazySchema.execute(query_str)
151
+ end
152
+ end
@@ -309,6 +309,26 @@ module StarWars
309
309
  field :introduceShipFunction, IntroduceShipFunctionMutation.field
310
310
  end
311
311
 
312
+ class ClassNameRecorder
313
+ def initialize(context_key)
314
+ @context_key = context_key
315
+ end
316
+
317
+ def instrument(type, field)
318
+ inner_resolve = field.resolve_proc
319
+ key = @context_key
320
+ field.redefine {
321
+ resolve ->(o, a, c) {
322
+ res = inner_resolve.call(o, a, c)
323
+ if c[key]
324
+ c[key] << res.class.name
325
+ end
326
+ res
327
+ }
328
+ }
329
+ end
330
+ end
331
+
312
332
  Schema = GraphQL::Schema.define do
313
333
  query(QueryType)
314
334
  mutation(MutationType)
@@ -337,5 +357,8 @@ module StarWars
337
357
  end
338
358
 
339
359
  lazy_resolve(LazyWrapper, :value)
360
+
361
+ instrument(:field, ClassNameRecorder.new(:before_built_ins))
362
+ instrument(:field, ClassNameRecorder.new(:after_built_ins), after_built_ins: true)
340
363
  end
341
364
  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: 1.5.15
4
+ version: 1.6.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-06-09 00:00:00.000000000 Z
11
+ date: 2017-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -276,6 +276,20 @@ dependencies:
276
276
  - - ">="
277
277
  - !ruby/object:Gem::Version
278
278
  version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: yard
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
279
293
  description: A plain-Ruby implementation of GraphQL.
280
294
  email:
281
295
  - rdmosolgo@gmail.com
@@ -315,6 +329,7 @@ files:
315
329
  - lib/graphql/analysis/reducer_state.rb
316
330
  - lib/graphql/analysis_error.rb
317
331
  - lib/graphql/argument.rb
332
+ - lib/graphql/backwards_compatibility.rb
318
333
  - lib/graphql/base_type.rb
319
334
  - lib/graphql/boolean_type.rb
320
335
  - lib/graphql/compatibility.rb
@@ -350,11 +365,13 @@ files:
350
365
  - lib/graphql/execution/lazy.rb
351
366
  - lib/graphql/execution/lazy/lazy_method_map.rb
352
367
  - lib/graphql/execution/lazy/resolve.rb
368
+ - lib/graphql/execution/multiplex.rb
353
369
  - lib/graphql/execution/selection_result.rb
354
370
  - lib/graphql/execution/typecast.rb
355
371
  - lib/graphql/execution_error.rb
356
372
  - lib/graphql/field.rb
357
373
  - lib/graphql/field/resolve.rb
374
+ - lib/graphql/filter.rb
358
375
  - lib/graphql/float_type.rb
359
376
  - lib/graphql/function.rb
360
377
  - lib/graphql/id_type.rb
@@ -419,6 +436,7 @@ files:
419
436
  - lib/graphql/query/validation_pipeline.rb
420
437
  - lib/graphql/query/variable_validation_error.rb
421
438
  - lib/graphql/query/variables.rb
439
+ - lib/graphql/rake_task.rb
422
440
  - lib/graphql/relay.rb
423
441
  - lib/graphql/relay/array_connection.rb
424
442
  - lib/graphql/relay/base_connection.rb
@@ -441,13 +459,14 @@ files:
441
459
  - lib/graphql/schema.rb
442
460
  - lib/graphql/schema/base_64_encoder.rb
443
461
  - lib/graphql/schema/build_from_definition.rb
462
+ - lib/graphql/schema/build_from_definition/resolve_map.rb
463
+ - lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb
444
464
  - lib/graphql/schema/catchall_middleware.rb
445
465
  - lib/graphql/schema/default_parse_error.rb
446
466
  - lib/graphql/schema/default_type_error.rb
447
467
  - lib/graphql/schema/instrumented_field_map.rb
448
468
  - lib/graphql/schema/invalid_type_error.rb
449
469
  - lib/graphql/schema/loader.rb
450
- - lib/graphql/schema/mask.rb
451
470
  - lib/graphql/schema/middleware_chain.rb
452
471
  - lib/graphql/schema/null_mask.rb
453
472
  - lib/graphql/schema/possible_types.rb
@@ -529,6 +548,7 @@ files:
529
548
  - spec/graphql/execution/execute_spec.rb
530
549
  - spec/graphql/execution/lazy/lazy_method_map_spec.rb
531
550
  - spec/graphql/execution/lazy_spec.rb
551
+ - spec/graphql/execution/multiplex_spec.rb
532
552
  - spec/graphql/execution/typecast_spec.rb
533
553
  - spec/graphql/execution_error_spec.rb
534
554
  - spec/graphql/field_spec.rb
@@ -562,6 +582,7 @@ files:
562
582
  - spec/graphql/query/serial_execution/value_resolution_spec.rb
563
583
  - spec/graphql/query/variables_spec.rb
564
584
  - spec/graphql/query_spec.rb
585
+ - spec/graphql/rake_task_spec.rb
565
586
  - spec/graphql/relay/array_connection_spec.rb
566
587
  - spec/graphql/relay/base_connection_spec.rb
567
588
  - spec/graphql/relay/connection_instrumentation_spec.rb
@@ -618,6 +639,7 @@ files:
618
639
  - spec/support/base_generator_test.rb
619
640
  - spec/support/dummy/data.rb
620
641
  - spec/support/dummy/schema.rb
642
+ - spec/support/lazy_helpers.rb
621
643
  - spec/support/minimum_input_object.rb
622
644
  - spec/support/star_wars/data.rb
623
645
  - spec/support/star_wars/schema.rb
@@ -676,6 +698,7 @@ test_files:
676
698
  - spec/graphql/execution/execute_spec.rb
677
699
  - spec/graphql/execution/lazy/lazy_method_map_spec.rb
678
700
  - spec/graphql/execution/lazy_spec.rb
701
+ - spec/graphql/execution/multiplex_spec.rb
679
702
  - spec/graphql/execution/typecast_spec.rb
680
703
  - spec/graphql/execution_error_spec.rb
681
704
  - spec/graphql/field_spec.rb
@@ -709,6 +732,7 @@ test_files:
709
732
  - spec/graphql/query/serial_execution/value_resolution_spec.rb
710
733
  - spec/graphql/query/variables_spec.rb
711
734
  - spec/graphql/query_spec.rb
735
+ - spec/graphql/rake_task_spec.rb
712
736
  - spec/graphql/relay/array_connection_spec.rb
713
737
  - spec/graphql/relay/base_connection_spec.rb
714
738
  - spec/graphql/relay/connection_instrumentation_spec.rb
@@ -765,6 +789,7 @@ test_files:
765
789
  - spec/support/base_generator_test.rb
766
790
  - spec/support/dummy/data.rb
767
791
  - spec/support/dummy/schema.rb
792
+ - spec/support/lazy_helpers.rb
768
793
  - spec/support/minimum_input_object.rb
769
794
  - spec/support/star_wars/data.rb
770
795
  - spec/support/star_wars/schema.rb
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- # Tools for working with schema masks (`only` / `except`).
5
- #
6
- # In general, these are functions which, when they return `true`,
7
- # the `member` is hidden for the current query.
8
- #
9
- # @api private
10
- module Mask
11
- module_function
12
-
13
- # Combine a schema's default_mask with query-level masks.
14
- def combine(default_mask, except:, only:)
15
- query_mask = if except
16
- except
17
- elsif only
18
- InvertedMask.new(only)
19
- end
20
-
21
- if query_mask && (default_mask != GraphQL::Schema::NullMask)
22
- EitherMask.new(default_mask, query_mask)
23
- else
24
- query_mask || default_mask
25
- end
26
- end
27
-
28
- # @api private
29
- # Returns true when the inner mask returned false
30
- # Returns false when the inner mask returned true
31
- class InvertedMask
32
- def initialize(inner_mask)
33
- @inner_mask = inner_mask
34
- end
35
-
36
- def call(member, ctx)
37
- !@inner_mask.call(member, ctx)
38
- end
39
- end
40
-
41
- # Hides `member` if _either_ mask would hide the member.
42
- # @api private
43
- class EitherMask
44
- def initialize(first_mask, second_mask)
45
- @first_mask = first_mask
46
- @second_mask = second_mask
47
- end
48
-
49
- def call(member, ctx)
50
- @first_mask.call(member, ctx) || @second_mask.call(member, ctx)
51
- end
52
- end
53
- end
54
- end
55
- end