graphql 1.12.8 → 1.12.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  4. data/lib/graphql.rb +10 -10
  5. data/lib/graphql/backtrace/table.rb +14 -2
  6. data/lib/graphql/backtrace/tracer.rb +7 -4
  7. data/lib/graphql/cop/nullability.rb +28 -0
  8. data/lib/graphql/cop/resolve_methods.rb +28 -0
  9. data/lib/graphql/dataloader.rb +59 -15
  10. data/lib/graphql/dataloader/null_dataloader.rb +1 -0
  11. data/lib/graphql/execution/execute.rb +1 -1
  12. data/lib/graphql/execution/interpreter.rb +4 -8
  13. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -2
  14. data/lib/graphql/execution/interpreter/resolve.rb +6 -2
  15. data/lib/graphql/execution/interpreter/runtime.rb +496 -222
  16. data/lib/graphql/execution/lazy.rb +5 -1
  17. data/lib/graphql/introspection/schema_type.rb +1 -1
  18. data/lib/graphql/pagination/connections.rb +1 -1
  19. data/lib/graphql/query.rb +1 -1
  20. data/lib/graphql/query/null_context.rb +7 -1
  21. data/lib/graphql/rake_task.rb +3 -0
  22. data/lib/graphql/schema.rb +52 -218
  23. data/lib/graphql/schema/addition.rb +238 -0
  24. data/lib/graphql/schema/argument.rb +55 -36
  25. data/lib/graphql/schema/build_from_definition.rb +8 -2
  26. data/lib/graphql/schema/directive/transform.rb +13 -1
  27. data/lib/graphql/schema/enum.rb +10 -1
  28. data/lib/graphql/schema/input_object.rb +13 -17
  29. data/lib/graphql/schema/loader.rb +8 -0
  30. data/lib/graphql/schema/member/base_dsl_methods.rb +3 -15
  31. data/lib/graphql/schema/member/build_type.rb +1 -0
  32. data/lib/graphql/schema/object.rb +19 -5
  33. data/lib/graphql/schema/printer.rb +11 -16
  34. data/lib/graphql/schema/resolver.rb +52 -25
  35. data/lib/graphql/schema/scalar.rb +3 -1
  36. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  37. data/lib/graphql/static_validation/rules/fields_will_merge.rb +17 -8
  38. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
  39. data/lib/graphql/static_validation/validator.rb +5 -0
  40. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
  41. data/lib/graphql/subscriptions/serialize.rb +8 -1
  42. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  43. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  44. data/lib/graphql/types/relay/node_field.rb +2 -2
  45. data/lib/graphql/types/relay/nodes_field.rb +2 -2
  46. data/lib/graphql/version.rb +1 -1
  47. data/readme.md +0 -3
  48. metadata +9 -21
  49. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
@@ -44,7 +44,9 @@ module GraphQL
44
44
  def validate_non_null_input(value, ctx)
45
45
  result = Query::InputValidationResult.new
46
46
  coerced_result = begin
47
- coerce_input(value, ctx)
47
+ ctx.query.with_error_handling do
48
+ coerce_input(value, ctx)
49
+ end
48
50
  rescue GraphQL::CoercionError => err
49
51
  err
50
52
  end
@@ -4,7 +4,7 @@ module GraphQL
4
4
  module DirectivesAreDefined
5
5
  def initialize(*)
6
6
  super
7
- @directive_names = context.schema.directives.keys
7
+ @directive_names = context.warden.directives.map(&:graphql_name)
8
8
  end
9
9
 
10
10
  def on_directive(node, parent)
@@ -373,17 +373,26 @@ module GraphQL
373
373
  # In this context, `parents` represends the "self scope" of the field,
374
374
  # what types may be found at this point in the query.
375
375
  def mutually_exclusive?(parents1, parents2)
376
- parents1.each do |type1|
377
- parents2.each do |type2|
378
- # If the types we're comparing are both different object types,
379
- # they have to be mutually exclusive.
380
- if type1 != type2 && type1.kind.object? && type2.kind.object?
381
- return true
376
+ if parents1.empty? || parents2.empty?
377
+ false
378
+ elsif parents1.length == parents2.length
379
+ parents1.length.times.any? do |i|
380
+ type1 = parents1[i - 1]
381
+ type2 = parents2[i - 1]
382
+ if type1 == type2
383
+ # If the types we're comparing are the same type,
384
+ # then they aren't mutually exclusive
385
+ false
386
+ else
387
+ # Check if these two scopes have _any_ types in common.
388
+ possible_right_types = context.query.possible_types(type1)
389
+ possible_left_types = context.query.possible_types(type2)
390
+ (possible_right_types & possible_left_types).empty?
382
391
  end
383
392
  end
393
+ else
394
+ true
384
395
  end
385
-
386
- false
387
396
  end
388
397
  end
389
398
  end
@@ -23,7 +23,7 @@ module GraphQL
23
23
  defn = if arg_defn && arg_defn.type.unwrap.kind.input_object?
24
24
  arg_defn.type.unwrap
25
25
  else
26
- context.field_definition
26
+ context.directive_definition || context.field_definition
27
27
  end
28
28
 
29
29
  parent_type = context.warden.get_argument(defn, parent_name(parent, defn))
@@ -73,6 +73,11 @@ module GraphQL
73
73
  irep: irep,
74
74
  }
75
75
  end
76
+ rescue GraphQL::ExecutionError => e
77
+ {
78
+ errors: [e],
79
+ irep: nil,
80
+ }
76
81
  end
77
82
 
78
83
  # Invoked when static validation times out.
@@ -34,12 +34,12 @@ module GraphQL
34
34
  # channel: self,
35
35
  # }
36
36
  #
37
- # result = MySchema.execute({
37
+ # result = MySchema.execute(
38
38
  # query: query,
39
39
  # context: context,
40
40
  # variables: variables,
41
41
  # operation_name: operation_name
42
- # })
42
+ # )
43
43
  #
44
44
  # payload = {
45
45
  # result: result.to_h,
@@ -146,14 +146,15 @@ module GraphQL
146
146
  def setup_stream(channel, initial_event)
147
147
  topic = initial_event.topic
148
148
  channel.stream_from(stream_event_name(initial_event), coder: @action_cable_coder) do |message|
149
- object = @serializer.load(message)
150
149
  events_by_fingerprint = @events[topic]
150
+ object = nil
151
151
  events_by_fingerprint.each do |_fingerprint, events|
152
152
  if events.any? && events.first == initial_event
153
153
  # The fingerprint has told us that this response should be shared by all subscribers,
154
154
  # so just run it once, then deliver the result to every subscriber
155
155
  first_event = events.first
156
156
  first_subscription_id = first_event.context.fetch(:subscription_id)
157
+ object ||= @serializer.load(message)
157
158
  result = execute_update(first_subscription_id, first_event, object)
158
159
  # Having calculated the result _once_, send the same payload to all subscribers
159
160
  events.each do |event|
@@ -55,7 +55,14 @@ module GraphQL
55
55
  # @return [Object] An object that load Global::Identification recursive
56
56
  def load_value(value)
57
57
  if value.is_a?(Array)
58
- value.map{|item| load_value(item)}
58
+ is_gids = (v1 = value[0]).is_a?(Hash) && v1.size == 1 && v1[GLOBALID_KEY]
59
+ if is_gids
60
+ # Assume it's an array of global IDs
61
+ ids = value.map { |v| v[GLOBALID_KEY] }
62
+ GlobalID::Locator.locate_many(ids)
63
+ else
64
+ value.map { |item| load_value(item) }
65
+ end
59
66
  elsif value.is_a?(Hash)
60
67
  if value.size == 1
61
68
  case value.keys.first # there's only 1 key
@@ -3,6 +3,7 @@
3
3
  module GraphQL
4
4
  module Types
5
5
  module Relay
6
+ # Include this module to your root Query type to get a Relay-compliant `node(id: ID!): Node` field that uses the schema's `object_from_id` hook.
6
7
  module HasNodeField
7
8
  def self.included(child_class)
8
9
  child_class.field(**field_options, &field_block)
@@ -12,7 +13,6 @@ module GraphQL
12
13
  def field_options
13
14
  {
14
15
  name: "node",
15
- owner: nil,
16
16
  type: GraphQL::Types::Relay::Node,
17
17
  null: true,
18
18
  description: "Fetches an object given its ID.",
@@ -3,6 +3,7 @@
3
3
  module GraphQL
4
4
  module Types
5
5
  module Relay
6
+ # Include this module to your root Query type to get a Relay-style `nodes(id: ID!): [Node]` field that uses the schema's `object_from_id` hook.
6
7
  module HasNodesField
7
8
  def self.included(child_class)
8
9
  child_class.field(**field_options, &field_block)
@@ -12,7 +13,6 @@ module GraphQL
12
13
  def field_options
13
14
  {
14
15
  name: "nodes",
15
- owner: nil,
16
16
  type: [GraphQL::Types::Relay::Node, null: true],
17
17
  null: false,
18
18
  description: "Fetches a list of objects given a list of IDs.",
@@ -6,7 +6,7 @@ module GraphQL
6
6
  # or use it for inspiration for your own field definition.
7
7
  #
8
8
  # @example Adding this field directly
9
- # add_field(GraphQL::Types::Relay::NodeField)
9
+ # include GraphQL::Types::Relay::HasNodeField
10
10
  #
11
11
  # @example Implementing a similar field in your own Query root
12
12
  #
@@ -19,7 +19,7 @@ module GraphQL
19
19
  # context.schema.object_from_id(id, context)
20
20
  # end
21
21
  #
22
- NodeField = GraphQL::Schema::Field.new(**HasNodeField.field_options, &HasNodeField.field_block)
22
+ NodeField = GraphQL::Schema::Field.new(owner: nil, **HasNodeField.field_options, &HasNodeField.field_block)
23
23
  end
24
24
  end
25
25
  end
@@ -6,7 +6,7 @@ module GraphQL
6
6
  # or use it for inspiration for your own field definition.
7
7
  #
8
8
  # @example Adding this field directly
9
- # add_field(GraphQL::Types::Relay::NodesField)
9
+ # include GraphQL::Types::Relay::HasNodesField
10
10
  #
11
11
  # @example Implementing a similar field in your own Query root
12
12
  #
@@ -21,7 +21,7 @@ module GraphQL
21
21
  # end
22
22
  # end
23
23
  #
24
- NodesField = GraphQL::Schema::Field.new(**HasNodesField.field_options, &HasNodesField.field_block)
24
+ NodesField = GraphQL::Schema::Field.new(owner: nil, **HasNodesField.field_options, &HasNodesField.field_block)
25
25
  end
26
26
  end
27
27
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.12.8"
3
+ VERSION = "1.12.14"
4
4
  end
data/readme.md CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  [![CI Suite](https://github.com/rmosolgo/graphql-ruby/actions/workflows/ci.yaml/badge.svg)](https://github.com/rmosolgo/graphql-ruby/actions/workflows/ci.yaml)
4
4
  [![Gem Version](https://badge.fury.io/rb/graphql.svg)](https://rubygems.org/gems/graphql)
5
- [![Code Climate](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/gpa.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
6
- [![Test Coverage](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/coverage.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
7
- [![built with love](https://cloud.githubusercontent.com/assets/2231765/6766607/d07992c6-cfc9-11e4-813f-d9240714dd50.png)](https://rmosolgo.github.io/react-badges/)
8
5
 
9
6
  A Ruby implementation of [GraphQL](https://graphql.org/).
10
7
 
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.12.8
4
+ version: 1.12.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-12 00:00:00.000000000 Z
11
+ date: 2021-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: codeclimate-test-reporter
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.4'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.4'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: concurrent-ruby
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -332,6 +318,8 @@ files:
332
318
  - lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb
333
319
  - lib/graphql/compatibility/query_parser_specification/query_assertions.rb
334
320
  - lib/graphql/compatibility/schema_parser_specification.rb
321
+ - lib/graphql/cop/nullability.rb
322
+ - lib/graphql/cop/resolve_methods.rb
335
323
  - lib/graphql/dataloader.rb
336
324
  - lib/graphql/dataloader/null_dataloader.rb
337
325
  - lib/graphql/dataloader/request.rb
@@ -369,7 +357,6 @@ files:
369
357
  - lib/graphql/execution/interpreter/arguments_cache.rb
370
358
  - lib/graphql/execution/interpreter/execution_errors.rb
371
359
  - lib/graphql/execution/interpreter/handles_raw_value.rb
372
- - lib/graphql/execution/interpreter/hash_response.rb
373
360
  - lib/graphql/execution/interpreter/resolve.rb
374
361
  - lib/graphql/execution/interpreter/runtime.rb
375
362
  - lib/graphql/execution/lazy.rb
@@ -485,6 +472,7 @@ files:
485
472
  - lib/graphql/runtime_type_error.rb
486
473
  - lib/graphql/scalar_type.rb
487
474
  - lib/graphql/schema.rb
475
+ - lib/graphql/schema/addition.rb
488
476
  - lib/graphql/schema/argument.rb
489
477
  - lib/graphql/schema/base_64_bp.rb
490
478
  - lib/graphql/schema/base_64_encoder.rb
@@ -699,7 +687,7 @@ metadata:
699
687
  source_code_uri: https://github.com/rmosolgo/graphql-ruby
700
688
  bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
701
689
  mailing_list_uri: https://tinyletter.com/graphql-ruby
702
- post_install_message:
690
+ post_install_message:
703
691
  rdoc_options: []
704
692
  require_paths:
705
693
  - lib
@@ -714,8 +702,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
714
702
  - !ruby/object:Gem::Version
715
703
  version: '0'
716
704
  requirements: []
717
- rubygems_version: 3.1.4
718
- signing_key:
705
+ rubygems_version: 3.2.15
706
+ signing_key:
719
707
  specification_version: 4
720
708
  summary: A GraphQL language and runtime for Ruby
721
709
  test_files: []
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- module Execution
5
- class Interpreter
6
- # This response class handles `#write` by accumulating
7
- # values into a Hash.
8
- class HashResponse
9
- def initialize
10
- @result = {}
11
- end
12
-
13
- def final_value
14
- @result
15
- end
16
-
17
- def inspect
18
- "#<#{self.class.name} result=#{@result.inspect}>"
19
- end
20
-
21
- # Add `value` at `path`.
22
- # @return [void]
23
- def write(path, value)
24
- if path.empty?
25
- @result = value
26
- elsif (write_target = @result)
27
- i = 0
28
- prefinal_steps = path.size - 1
29
- # Use `while` to avoid a closure
30
- while i < prefinal_steps
31
- path_part = path[i]
32
- i += 1
33
- write_target = write_target[path_part]
34
- end
35
- path_part = path[i]
36
- write_target[path_part] = value
37
- else
38
- # The response is completely nulled out
39
- end
40
-
41
- nil
42
- end
43
- end
44
- end
45
- end
46
- end