graphql 1.5.10 → 1.5.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e87f7a05371764ee8744616a781f61f103f761c
4
- data.tar.gz: e8d2eafe80fbe962c1dd5c017201b82b86def0ad
3
+ metadata.gz: bb2841b1c8677bc9188757eca08b2f365f0e0af8
4
+ data.tar.gz: 12bc61f9684e3bae2a4d06c22f9378064fcf191d
5
5
  SHA512:
6
- metadata.gz: b83d8c335d98f4149a6ce531b6dc61254fc96bbb5fec35beb2c0fece8eb4fff58693cd7bd48fb89511da84d69cfcec5e639b64372add0c8070c5a9c871804af0
7
- data.tar.gz: ef672d60a38c0e1b5ec87af598d7ec221e36c6511ed92f72840bb32be813a0d434d9a0580d2e57e18ad8ad48f486f150d36b72399dbba347a4915686148b1c4e
6
+ metadata.gz: 7859ae0afed299edb29dedc59d014f057b85dde4e3547a300d312c0ba137f23cc23d6c70c664a3afd6985c3b393483aa012c8e7ba6e70e0713ad203163dbc089
7
+ data.tar.gz: 61ab9c38a66e013b09bec6f5865aae178110ba99b230b2a94b325ea1afef7b1bb9beb98744c52cee0d8b2c2813b377a39dbef13c920bf319cddfeef1ba2f3e07
@@ -9,7 +9,7 @@ class Functions::<%= name %> < GraphQL::Function
9
9
  # end
10
10
 
11
11
  # add arguments by type:
12
- # argument :id, !GraphQL::ID_TYPE
12
+ # argument :id, !types.ID
13
13
 
14
14
  # Resolve function:
15
15
  def call(obj, args, ctx)
@@ -29,6 +29,5 @@
29
29
  }
30
30
  <% end %><% if options[:batch] %>
31
31
  # GraphQL::Batch setup:
32
- lazy_resolve(Promise, :sync)
33
- instrument(:query, GraphQL::Batch::Setup)
32
+ use GraphQL::Batch
34
33
  <% end %>end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  require 'rails/generators/base'
3
3
  require 'graphql'
4
+ require 'active_support'
5
+ require 'active_support/core_ext/string/inflections'
4
6
 
5
7
  module Graphql
6
8
  module Generators
@@ -39,10 +41,10 @@ module Graphql
39
41
  when "Int", "Float", "Boolean", "String", "ID"
40
42
  "types.#{type_expression}"
41
43
  else
42
- "Types::#{type_expression}Type"
44
+ "Types::#{type_expression.camelize}Type"
43
45
  end
44
46
  when :graphql
45
- type_expression
47
+ type_expression.camelize
46
48
  else
47
49
  raise "Unexpected normalize mode: #{mode}"
48
50
  end
@@ -18,7 +18,7 @@ module GraphQL
18
18
 
19
19
  irep = query.internal_representation
20
20
 
21
- irep.each do |name, op_node|
21
+ irep.operation_definitions.each do |name, op_node|
22
22
  reduce_node(op_node, reducer_states)
23
23
  end
24
24
 
@@ -18,7 +18,7 @@ module GraphQL
18
18
  #
19
19
  # argument :id, GraphQL::ID_TYPE
20
20
  #
21
- # def resolve(obj, args, ctx)
21
+ # def call(obj, args, ctx)
22
22
  # @model.find(args.id)
23
23
  # end
24
24
  # end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/internal_representation/document"
2
3
  require "graphql/internal_representation/node"
3
4
  require "graphql/internal_representation/print"
4
5
  require "graphql/internal_representation/rewrite"
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module InternalRepresentation
4
+ class Document
5
+ # @return [Hash<String, Node>] Operation Nodes of this query
6
+ attr_reader :operation_definitions
7
+
8
+ # @return [Hash<String, Node>] Fragment definition Nodes of this query
9
+ attr_reader :fragment_definitions
10
+
11
+ def initialize
12
+ @operation_definitions = {}
13
+ @fragment_definitions = {}
14
+ end
15
+
16
+ def [](key)
17
+ warn "#{self.class}#[] is deprecated; use `operation_definitions[]` instead"
18
+ operation_definitions[key]
19
+ end
20
+
21
+ def each(&block)
22
+ warn "#{self.class}#each is deprecated; use `operation_definitions.each` instead"
23
+ operation_definitions.each(&block)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -18,11 +18,17 @@ module GraphQL
18
18
 
19
19
  NO_DIRECTIVES = [].freeze
20
20
 
21
- # @return [Hash<String, Node>] Roots of this query
22
- attr_reader :operations
21
+ # @return InternalRepresentation::Document
22
+ attr_reader :document
23
23
 
24
24
  def initialize
25
- @operations = {}
25
+ @document = InternalRepresentation::Document.new
26
+ end
27
+
28
+ # @return [Hash<String, Node>] Roots of this query
29
+ def operations
30
+ warn "#{self.class}#operations is deprecated; use `document.operation_definitions` instead"
31
+ document.operation_definitions
26
32
  end
27
33
 
28
34
  def validate(context)
@@ -39,14 +45,13 @@ module GraphQL
39
45
  # Array<Scope>
40
46
  scopes_stack = []
41
47
 
42
- fragment_definitions = {}
43
48
  skip_nodes = Set.new
44
49
 
45
- visit_op = VisitDefinition.new(context, @operations, nodes_stack, scopes_stack)
50
+ visit_op = VisitDefinition.new(context, @document.operation_definitions, nodes_stack, scopes_stack)
46
51
  visitor[Nodes::OperationDefinition].enter << visit_op.method(:enter)
47
52
  visitor[Nodes::OperationDefinition].leave << visit_op.method(:leave)
48
53
 
49
- visit_frag = VisitDefinition.new(context, fragment_definitions, nodes_stack, scopes_stack)
54
+ visit_frag = VisitDefinition.new(context, @document.fragment_definitions, nodes_stack, scopes_stack)
50
55
  visitor[Nodes::FragmentDefinition].enter << visit_frag.method(:enter)
51
56
  visitor[Nodes::FragmentDefinition].leave << visit_frag.method(:leave)
52
57
 
@@ -137,7 +142,7 @@ module GraphQL
137
142
  # can be shared between its usages.
138
143
  context.on_dependency_resolve do |defn_ast_node, spread_ast_nodes, frag_ast_node|
139
144
  frag_name = frag_ast_node.name
140
- fragment_node = fragment_definitions[frag_name]
145
+ fragment_node = @document.fragment_definitions[frag_name]
141
146
 
142
147
  if fragment_node
143
148
  spread_ast_nodes.each do |spread_ast_node|
@@ -39,25 +39,26 @@ module GraphQL
39
39
  def to_s
40
40
  "[#{of_type.to_s}]"
41
41
  end
42
+ alias_method :inspect, :to_s
42
43
 
43
44
  def coerce_result(value, ctx = nil)
44
45
  if ctx.nil?
45
46
  warn_deprecated_coerce("coerce_isolated_result")
46
47
  ctx = GraphQL::Query::NullContext
47
48
  end
48
- Array(value).map { |item| item.nil? ? nil : of_type.coerce_result(item, ctx) }
49
+ ensure_array(value).map { |item| item.nil? ? nil : of_type.coerce_result(item, ctx) }
49
50
  end
50
51
 
51
52
  private
52
53
 
53
54
  def coerce_non_null_input(value, ctx)
54
- Array(value).map { |item| of_type.coerce_input(item, ctx) }
55
+ ensure_array(value).map { |item| of_type.coerce_input(item, ctx) }
55
56
  end
56
57
 
57
58
  def validate_non_null_input(value, ctx)
58
59
  result = GraphQL::Query::InputValidationResult.new
59
60
 
60
- Array(value).each_with_index do |item, index|
61
+ ensure_array(value).each_with_index do |item, index|
61
62
  item_result = of_type.validate_input(item, ctx)
62
63
  if !item_result.valid?
63
64
  result.merge_result!(index, item_result)
@@ -66,5 +67,9 @@ module GraphQL
66
67
 
67
68
  result
68
69
  end
70
+
71
+ def ensure_array(value)
72
+ value.is_a?(Array) ? value : [value]
73
+ end
69
74
  end
70
75
  end
@@ -61,5 +61,6 @@ module GraphQL
61
61
  def to_s
62
62
  "#{of_type.to_s}!"
63
63
  end
64
+ alias_method :inspect, :to_s
64
65
  end
65
66
  end
@@ -27,7 +27,7 @@ module GraphQL
27
27
  end
28
28
  end
29
29
 
30
- attr_reader :schema, :document, :context, :fragments, :operations, :root_value, :query_string, :warden, :provided_variables
30
+ attr_reader :schema, :document, :context, :fragments, :operations, :root_value, :query_string, :warden, :provided_variables, :operation_name
31
31
 
32
32
  # Prepare query `query_string` on `schema`
33
33
  # @param schema [GraphQL::Schema]
@@ -83,13 +83,17 @@ module GraphQL
83
83
  @ast_variables = []
84
84
  @mutation = false
85
85
  operation_name_error = nil
86
+ @operation_name = nil
87
+
86
88
  if @operations.any?
87
- @selected_operation = find_operation(@operations, operation_name)
88
- if @selected_operation.nil?
89
+ selected_operation = find_operation(@operations, operation_name)
90
+ if selected_operation.nil?
89
91
  operation_name_error = GraphQL::Query::OperationNameMissingError.new(operation_name)
90
92
  else
91
- @ast_variables = @selected_operation.variables
92
- @mutation = @selected_operation.operation_type == "mutation"
93
+ @operation_name = selected_operation.name
94
+ @ast_variables = selected_operation.variables
95
+ @mutation = selected_operation.operation_type == "mutation"
96
+ @selected_operation = selected_operation
93
97
  end
94
98
  end
95
99
 
@@ -155,7 +159,7 @@ module GraphQL
155
159
  end
156
160
 
157
161
  def irep_selection
158
- @selection ||= internal_representation[selected_operation.name]
162
+ @selection ||= internal_representation.operation_definitions[selected_operation.name]
159
163
  end
160
164
 
161
165
  # Node-level cache for calculating arguments. Used during execution and query analysis.
@@ -399,9 +399,10 @@ module GraphQL
399
399
  # Create schema from an IDL schema.
400
400
  # @param definition_string [String] A schema definition string
401
401
  # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
402
+ # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
402
403
  # @return [GraphQL::Schema] the schema described by `document`
403
- def self.from_definition(string, default_resolve: BuildFromDefinition::DefaultResolve)
404
- GraphQL::Schema::BuildFromDefinition.from_definition(string, default_resolve: default_resolve)
404
+ def self.from_definition(string, default_resolve: BuildFromDefinition::DefaultResolve, parser: BuildFromDefinition::DefaultParser)
405
+ GraphQL::Schema::BuildFromDefinition.from_definition(string, default_resolve: default_resolve, parser: parser)
405
406
  end
406
407
 
407
408
  # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
@@ -3,12 +3,15 @@ module GraphQL
3
3
  class Schema
4
4
  module BuildFromDefinition
5
5
  class << self
6
- def from_definition(definition_string, default_resolve:)
7
- document = GraphQL::parse(definition_string)
6
+ def from_definition(definition_string, default_resolve:, parser: DefaultParser)
7
+ document = parser.parse(definition_string)
8
8
  Builder.build(document, default_resolve: default_resolve)
9
9
  end
10
10
  end
11
11
 
12
+ # @api private
13
+ DefaultParser = GraphQL::Language::Parser
14
+
12
15
  # @api private
13
16
  module DefaultResolve
14
17
  def self.call(type, field, obj, args, ctx)
@@ -12,17 +12,19 @@ module GraphQL
12
12
  end
13
13
 
14
14
  def initialize
15
+ @node_paths = {}
16
+
15
17
  # { name => node } pairs for fragments
16
18
  @fragment_definitions = {}
17
19
 
18
20
  # This tracks dependencies from fragment to Node where it was used
19
- # { frag_name => [dependent_node, dependent_node]}
21
+ # { fragment_definition_node => [dependent_node, dependent_node]}
20
22
  @dependent_definitions = Hash.new { |h, k| h[k] = Set.new }
21
23
 
22
24
  # First-level usages of spreads within definitions
23
25
  # (When a key has an empty list as its value,
24
26
  # we can resolve that key's depenedents)
25
- # { string => [node, node ...] }
27
+ # { definition_node => [node, node ...] }
26
28
  @immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
27
29
  end
28
30
 
@@ -38,8 +40,19 @@ module GraphQL
38
40
  # this node is the one who depends on it
39
41
  current_parent = nil
40
42
 
43
+ visitor[GraphQL::Language::Nodes::Document] << ->(node, prev_node) {
44
+ node.definitions.each do |definition|
45
+ case definition
46
+ when GraphQL::Language::Nodes::OperationDefinition
47
+ when GraphQL::Language::Nodes::FragmentDefinition
48
+ @fragment_definitions[definition.name] = definition
49
+ end
50
+ end
51
+ }
52
+
41
53
  visitor[GraphQL::Language::Nodes::OperationDefinition] << ->(node, prev_node) {
42
- current_parent = NodeWithPath.new(node, context.path)
54
+ @node_paths[node] = NodeWithPath.new(node, context.path)
55
+ current_parent = node
43
56
  }
44
57
 
45
58
  visitor[GraphQL::Language::Nodes::OperationDefinition].leave << ->(node, prev_node) {
@@ -47,7 +60,8 @@ module GraphQL
47
60
  }
48
61
 
49
62
  visitor[GraphQL::Language::Nodes::FragmentDefinition] << ->(node, prev_node) {
50
- current_parent = @fragment_definitions[node.name] = NodeWithPath.new(node, context.path)
63
+ @node_paths[node] = NodeWithPath.new(node, context.path)
64
+ current_parent = node
51
65
  }
52
66
 
53
67
  visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << ->(node, prev_node) {
@@ -55,9 +69,11 @@ module GraphQL
55
69
  }
56
70
 
57
71
  visitor[GraphQL::Language::Nodes::FragmentSpread] << ->(node, prev_node) {
72
+ @node_paths[node] = NodeWithPath.new(node, context.path)
73
+
58
74
  # Track both sides of the dependency
59
- @dependent_definitions[node.name] << current_parent
60
- @immediate_dependencies[current_parent.name] << NodeWithPath.new(node, context.path)
75
+ @dependent_definitions[@fragment_definitions[node.name]] << current_parent
76
+ @immediate_dependencies[current_parent] << node
61
77
  }
62
78
  end
63
79
 
@@ -113,40 +129,39 @@ module GraphQL
113
129
  # determine them at the end. This way, we can treat fragments with the
114
130
  # same name as if they were the same name. If _any_ of the fragments
115
131
  # with that name has a dependency, we record it.
116
- independent_fragment_names = @fragment_definitions.each_key.select { |name| !@immediate_dependencies.key?(name) }
132
+ independent_fragment_nodes = @fragment_definitions.values - @immediate_dependencies.keys
117
133
 
118
- while fragment_name = independent_fragment_names.pop
134
+ while fragment_node = independent_fragment_nodes.pop
119
135
  loops += 1
120
136
  if loops > max_loops
121
137
  raise("Resolution loops exceeded the number of definitions; infinite loop detected.")
122
138
  end
123
- fragment_node = @fragment_definitions[fragment_name]
124
139
  # Since it's independent, let's remove it from here.
125
140
  # That way, we can use the remainder to identify cycles
126
- @immediate_dependencies.delete(fragment_name)
127
- fragment_usages = @dependent_definitions[fragment_name]
141
+ @immediate_dependencies.delete(fragment_node)
142
+ fragment_usages = @dependent_definitions[fragment_node]
128
143
  if fragment_usages.none?
129
144
  # If we didn't record any usages during the visit,
130
145
  # then this fragment is unused.
131
- dependency_map.unused_dependencies << fragment_node
146
+ dependency_map.unused_dependencies << @node_paths[fragment_node]
132
147
  else
133
148
  fragment_usages.each do |definition_node|
134
149
  # Register the dependency AND second-order dependencies
135
150
  dependency_map[definition_node] << fragment_node
136
151
  dependency_map[definition_node].concat(dependency_map[fragment_node])
137
152
  # Since we've regestered it, remove it from our to-do list
138
- deps = @immediate_dependencies[definition_node.name]
153
+ deps = @immediate_dependencies[definition_node]
139
154
  # Can't find a way to _just_ delete from `deps` and return the deleted entries
140
- removed, remaining = deps.partition { |spread| spread.name == fragment_name }
141
- @immediate_dependencies[definition_node.name] = remaining
155
+ removed, remaining = deps.partition { |spread| spread.name == fragment_node.name }
156
+ @immediate_dependencies[definition_node] = remaining
142
157
  if block_given?
143
158
  yield(definition_node, removed, fragment_node)
144
159
  end
145
- if remaining.none? && definition_node.node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
160
+ if remaining.none? && definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
146
161
  # If all of this definition's dependencies have
147
162
  # been resolved, we can now resolve its
148
163
  # own dependents.
149
- independent_fragment_names << definition_node.name
164
+ independent_fragment_nodes << definition_node
150
165
  end
151
166
  end
152
167
  end
@@ -155,21 +170,20 @@ module GraphQL
155
170
  # If any dependencies were _unmet_
156
171
  # (eg, spreads with no corresponding definition)
157
172
  # then they're still in there
158
- @immediate_dependencies.each do |defn_name, deps|
173
+ @immediate_dependencies.each do |defn_node, deps|
159
174
  deps.each do |spread|
160
175
  if @fragment_definitions[spread.name].nil?
161
- defn_node = @fragment_definitions[defn_name]
162
- dependency_map.unmet_dependencies[defn_node] << spread
176
+ dependency_map.unmet_dependencies[@node_paths[defn_node]] << @node_paths[spread]
163
177
  deps.delete(spread)
164
178
  end
165
179
  end
166
180
  if deps.none?
167
- @immediate_dependencies.delete(defn_name)
181
+ @immediate_dependencies.delete(defn_node)
168
182
  end
169
183
  end
170
184
 
171
185
  # Anything left in @immediate_dependencies is cyclical
172
- cyclical_nodes = @immediate_dependencies.keys.map { |n| @fragment_definitions[n] }
186
+ cyclical_nodes = @immediate_dependencies.keys.map { |n| @node_paths[n] }
173
187
  # @immediate_dependencies also includes operation names, but we don't care about
174
188
  # those. They became nil when we looked them up on `@fragment_definitions`, so remove them.
175
189
  cyclical_nodes.compact!
@@ -33,8 +33,8 @@ module GraphQL
33
33
 
34
34
  context.visitor.visit
35
35
  # Post-validation: allow validators to register handlers on rewritten query nodes
36
- rewrite_result = rewrite.operations
37
- GraphQL::InternalRepresentation::Visit.visit_each_node(rewrite_result, context.each_irep_node_handlers)
36
+ rewrite_result = rewrite.document
37
+ GraphQL::InternalRepresentation::Visit.visit_each_node(rewrite_result.operation_definitions, context.each_irep_node_handlers)
38
38
 
39
39
  {
40
40
  errors: context.errors,
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.5.10"
3
+ VERSION = "1.5.11"
4
4
  end
@@ -20,7 +20,7 @@ class Functions::FindRecord < GraphQL::Function
20
20
  # end
21
21
 
22
22
  # add arguments by type:
23
- # argument :id, !GraphQL::ID_TYPE
23
+ # argument :id, !types.ID
24
24
 
25
25
  # Resolve function:
26
26
  def call(obj, args, ctx)
@@ -178,8 +178,7 @@ DummySchema = GraphQL::Schema.define do
178
178
  }
179
179
 
180
180
  # GraphQL::Batch setup:
181
- lazy_resolve(Promise, :sync)
182
- instrument(:query, GraphQL::Batch::Setup)
181
+ use GraphQL::Batch
183
182
  end
184
183
  RUBY
185
184
  end
@@ -30,6 +30,15 @@ RUBY
30
30
  end
31
31
  end
32
32
 
33
+ test "it generates classifed file" do
34
+ run_generator(["page"])
35
+ assert_file "app/graphql/types/page_type.rb", <<-RUBY
36
+ Types::PageType = GraphQL::ObjectType.define do
37
+ name "Page"
38
+ end
39
+ RUBY
40
+ end
41
+
33
42
  test "it makes Relay nodes" do
34
43
  run_generator(["Page", "--node"])
35
44
  assert_file "app/graphql/types/page_type.rb", <<-RUBY
@@ -104,7 +104,7 @@ describe GraphQL::InternalRepresentation::Rewrite do
104
104
  }
105
105
 
106
106
  it "groups selections by object types which they apply to" do
107
- doc = rewrite_result["getPlant"]
107
+ doc = rewrite_result.operation_definitions["getPlant"]
108
108
  assert_equal nil, doc.definition
109
109
 
110
110
  plant_scoped_selection = doc.scoped_children[schema.types["Query"]]["plant"]
@@ -126,7 +126,7 @@ describe GraphQL::InternalRepresentation::Rewrite do
126
126
  end
127
127
 
128
128
  it "tracks parent nodes" do
129
- doc = rewrite_result["getPlant"]
129
+ doc = rewrite_result.operation_definitions["getPlant"]
130
130
  assert_equal nil, doc.parent
131
131
 
132
132
  plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
@@ -171,7 +171,7 @@ describe GraphQL::InternalRepresentation::Rewrite do
171
171
  }
172
172
 
173
173
  it "applies directives from all contexts" do
174
- doc = rewrite_result["getPlant"]
174
+ doc = rewrite_result.operation_definitions["getPlant"]
175
175
  plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
176
176
  leaf_type_selection = plant_selection.typed_children[schema.types["Nut"]]["leafType"]
177
177
  # Only unskipped occurrences in the AST
@@ -208,7 +208,7 @@ describe GraphQL::InternalRepresentation::Rewrite do
208
208
  }
209
209
 
210
210
  it "applies spreads to their parents only" do
211
- doc = rewrite_result[nil]
211
+ doc = rewrite_result.operation_definitions[nil]
212
212
  plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
213
213
  nut_habitat_selections = plant_selection.typed_children[schema.types["Nut"]]["habitats"].typed_children[schema.types["Habitat"]]
214
214
  assert_equal ["averageWeight", "residentName", "seasons"], nut_habitat_selections.keys.sort
@@ -286,4 +286,42 @@ describe GraphQL::InternalRepresentation::Rewrite do
286
286
  end
287
287
  end
288
288
  end
289
+
290
+ describe "fragment definition without query" do
291
+ let(:query_string) {
292
+ <<-GRAPHQL
293
+ fragment NutFields on Nut {
294
+ leafType
295
+ ... TreeFields
296
+ }
297
+
298
+ fragment TreeFields on Tree {
299
+ habitats {
300
+ ... HabitatFields
301
+ }
302
+ }
303
+
304
+ fragment HabitatFields on Habitat {
305
+ seasons
306
+ }
307
+ GRAPHQL
308
+ }
309
+
310
+ let(:validator) {
311
+ rules = GraphQL::StaticValidation::ALL_RULES - [
312
+ GraphQL::StaticValidation::FragmentsAreUsed
313
+ ]
314
+ GraphQL::StaticValidation::Validator.new(schema: schema, rules: rules)
315
+ }
316
+
317
+ it "tracks fragment definitions without operation" do
318
+ doc = rewrite_result.fragment_definitions["NutFields"]
319
+
320
+ assert doc.typed_children[schema.types["Nut"]]["leafType"]
321
+
322
+ assert nut_selections = doc.typed_children[schema.types["Nut"]]
323
+ habitats_selections = nut_selections["habitats"].typed_children[schema.types["Habitat"]]
324
+ assert_equal ["seasons"], habitats_selections.keys
325
+ end
326
+ end
289
327
  end
@@ -8,6 +8,10 @@ describe GraphQL::ListType do
8
8
  assert_equal([1.0, 2.0, 3.0].inspect, float_list.coerce_isolated_input([1, 2, 3]).inspect)
9
9
  end
10
10
 
11
+ it "converts items that are not lists into lists" do
12
+ assert_equal([1.0].inspect, float_list.coerce_isolated_input(1.0).inspect)
13
+ end
14
+
11
15
  describe "validate_input with bad input" do
12
16
  let(:bad_num) { "bad_num" }
13
17
  let(:result) { float_list.validate_isolated_input([bad_num, 2.0, 3.0]) }
@@ -30,4 +34,20 @@ describe GraphQL::ListType do
30
34
  assert_equal(actual, expected)
31
35
  end
32
36
  end
37
+
38
+ describe "list of input objects" do
39
+ let(:input_object) do
40
+ GraphQL::InputObjectType.define do
41
+ name "SomeInputObjectType"
42
+ argument :float, !types.Float
43
+ end
44
+ end
45
+
46
+ let(:input_object_list) { input_object.to_list_type }
47
+
48
+ it "converts hashes into lists of hashes" do
49
+ hash = { 'float' => 1.0 }
50
+ assert_equal([hash].inspect, input_object_list.coerce_isolated_input(hash).map(&:to_h).inspect)
51
+ end
52
+ end
33
53
  end
@@ -58,6 +58,27 @@ describe GraphQL::Query::Executor do
58
58
  end
59
59
  end
60
60
 
61
+ describe "operation and fragment defintions of the same name" do
62
+ let(:query_string) { %|
63
+ query Cheese { cheese(id: 1) { ...Cheese } }
64
+ query MoreCheese { cheese(id: 2) { ...Cheese } }
65
+ fragment Cheese on Cheese { flavor }
66
+ |}
67
+
68
+ let(:operation_name) { "Cheese" }
69
+
70
+ it "runs the named operation" do
71
+ expected = {
72
+ "data" => {
73
+ "cheese" => {
74
+ "flavor" => "Brie"
75
+ }
76
+ }
77
+ }
78
+ assert_equal(expected, result)
79
+ end
80
+ end
81
+
61
82
 
62
83
  describe "execution order" do
63
84
  let(:query_string) {%|
@@ -57,6 +57,32 @@ describe GraphQL::Query do
57
57
  end
58
58
  end
59
59
 
60
+ describe "operation_name" do
61
+ describe "when provided" do
62
+ let(:query_string) { <<-GRAPHQL
63
+ query q1 { cheese(id: 1) { flavor } }
64
+ query q2 { cheese(id: 2) { flavor } }
65
+ GRAPHQL
66
+ }
67
+ let(:operation_name) { "q2" }
68
+
69
+ it "returns the provided name" do
70
+ assert_equal "q2", query.operation_name
71
+ end
72
+ end
73
+
74
+ describe "when inferred" do
75
+ let(:query_string) { <<-GRAPHQL
76
+ query q3 { cheese(id: 3) { flavor } }
77
+ GRAPHQL
78
+ }
79
+
80
+ it "returns the inferred name" do
81
+ assert_equal "q3", query.operation_name
82
+ end
83
+ end
84
+ end
85
+
60
86
  describe "when passed a document instance" do
61
87
  let(:query) { GraphQL::Query.new(
62
88
  schema,
@@ -529,4 +555,14 @@ describe GraphQL::Query do
529
555
  assert_equal([nil], expected_args.first['id'])
530
556
  end
531
557
  end
558
+
559
+ describe '#internal_representation' do
560
+ it "includes all definition roots" do
561
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.internal_representation.operation_definitions["getFlavor"]
562
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.internal_representation.fragment_definitions["cheeseFields"]
563
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.internal_representation.fragment_definitions["edibleFields"]
564
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.internal_representation.fragment_definitions["milkFields"]
565
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.internal_representation.fragment_definitions["dairyFields"]
566
+ end
567
+ end
532
568
  end
@@ -813,5 +813,21 @@ SCHEMA
813
813
  assert_equal(result.to_json, '{"data":{"allTodos":[{"text":"Pay the bills.","from_context":null},{"text":"Buy Milk","from_context":"bar"}]}}')
814
814
  end
815
815
  end
816
+
817
+ describe "custom parser behavior" do
818
+ module BadParser
819
+ ParseError = Class.new(StandardError)
820
+
821
+ def self.parse(string)
822
+ raise ParseError
823
+ end
824
+ end
825
+
826
+ it 'accepts a parser callable' do
827
+ assert_raises(BadParser::ParseError) do
828
+ GraphQL::Schema.from_definition(schema_defn, parser: BadParser)
829
+ end
830
+ end
831
+ end
816
832
  end
817
833
  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.10
4
+ version: 1.5.11
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-04-25 00:00:00.000000000 Z
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -362,6 +362,7 @@ files:
362
362
  - lib/graphql/int_type.rb
363
363
  - lib/graphql/interface_type.rb
364
364
  - lib/graphql/internal_representation.rb
365
+ - lib/graphql/internal_representation/document.rb
365
366
  - lib/graphql/internal_representation/node.rb
366
367
  - lib/graphql/internal_representation/print.rb
367
368
  - lib/graphql/internal_representation/rewrite.rb