graphql 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/compatibility/schema_parser_specification.rb +28 -0
- data/lib/graphql/enum_type.rb +3 -3
- data/lib/graphql/execution_error.rb +13 -1
- data/lib/graphql/introspection.rb +0 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +1 -1
- data/lib/graphql/introspection/type_type.rb +1 -2
- data/lib/graphql/language/parser.rb +2 -2
- data/lib/graphql/language/parser.y +2 -2
- data/lib/graphql/railtie.rb +6 -6
- data/lib/graphql/schema/resolver.rb +0 -1
- data/lib/graphql/schema/warden.rb +17 -10
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +2 -2
- data/lib/graphql/upgrader/member.rb +6 -6
- data/lib/graphql/version.rb +1 -1
- data/spec/fixtures/upgrader/blame_range.transformed.rb +2 -2
- data/spec/fixtures/upgrader/delete_project.transformed.rb +4 -4
- data/spec/fixtures/upgrader/increment_count.transformed.rb +1 -1
- data/spec/fixtures/upgrader/photo.transformed.rb +1 -1
- data/spec/fixtures/upgrader/starrable.transformed.rb +5 -5
- data/spec/fixtures/upgrader/subscribable.transformed.rb +7 -7
- data/spec/fixtures/upgrader/type_x.transformed.rb +6 -6
- data/spec/graphql/execution/multiplex_spec.rb +1 -1
- data/spec/graphql/execution_error_spec.rb +20 -1
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/relay/mongo_relation_connection_spec.rb +12 -1
- data/spec/graphql/schema/warden_spec.rb +129 -0
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +17 -9
- data/spec/graphql/upgrader/member_spec.rb +5 -5
- data/spec/spec_helper.rb +20 -1
- data/spec/support/dummy/schema.rb +7 -0
- metadata +2 -21
- data/lib/graphql/introspection/schema_field.rb +0 -16
- data/lib/graphql/introspection/type_by_name_field.rb +0 -22
- data/lib/graphql/introspection/typename_field.rb +0 -12
- data/spec/graphql/introspection/type_by_name_field_spec.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d3ae1b02473b2855990db63798b1c5d2fea46de
|
4
|
+
data.tar.gz: cfdc979146afea3eb44a969b66ac3a0763956db7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 762efe82d940d001685c0cf242e1b6fc0c7ee9a5b77de66c4917268b6d2ae0340346daf707d74d41c9b1dd77b71c2d2d1f887e74e2eae2ab9c7869a787a5a74b
|
7
|
+
data.tar.gz: 4bcd06d7c866bb65154310cb8d11965902372860747aaaa99ebf44a73ebac3f6b1743e459e47730ba44e7fab57588031352bd1ed63925a42ec89550d32bf7906
|
@@ -78,6 +78,34 @@ module GraphQL
|
|
78
78
|
assert_equal [], type.values[2].directives
|
79
79
|
end
|
80
80
|
|
81
|
+
def test_it_parses_union_types
|
82
|
+
document = parse(
|
83
|
+
"union BagOfThings = \n" \
|
84
|
+
"A |\n" \
|
85
|
+
"B |\n" \
|
86
|
+
"C"
|
87
|
+
)
|
88
|
+
|
89
|
+
union = document.definitions.first
|
90
|
+
|
91
|
+
assert_equal GraphQL::Language::Nodes::UnionTypeDefinition, union.class
|
92
|
+
assert_equal 'BagOfThings', union.name
|
93
|
+
assert_equal 3, union.types.length
|
94
|
+
assert_equal [1, 1], union.position
|
95
|
+
|
96
|
+
assert_equal GraphQL::Language::Nodes::TypeName, union.types[0].class
|
97
|
+
assert_equal 'A', union.types[0].name
|
98
|
+
assert_equal [2, 1], union.types[0].position
|
99
|
+
|
100
|
+
assert_equal GraphQL::Language::Nodes::TypeName, union.types[1].class
|
101
|
+
assert_equal 'B', union.types[1].name
|
102
|
+
assert_equal [3, 1], union.types[1].position
|
103
|
+
|
104
|
+
assert_equal GraphQL::Language::Nodes::TypeName, union.types[2].class
|
105
|
+
assert_equal 'C', union.types[2].name
|
106
|
+
assert_equal [4, 1], union.types[2].position
|
107
|
+
end
|
108
|
+
|
81
109
|
def test_it_parses_input_types
|
82
110
|
document = parse('
|
83
111
|
input EmptyMutationInput {
|
data/lib/graphql/enum_type.rb
CHANGED
@@ -12,8 +12,8 @@ module GraphQL
|
|
12
12
|
#
|
13
13
|
# @example An enum of programming languages
|
14
14
|
# LanguageEnum = GraphQL::EnumType.define do
|
15
|
-
# name "
|
16
|
-
# description "Programming
|
15
|
+
# name "Language"
|
16
|
+
# description "Programming language for Web projects"
|
17
17
|
# value("PYTHON", "A dynamic, function-oriented language")
|
18
18
|
# value("RUBY", "A very dynamic language aimed at programmer happiness")
|
19
19
|
# value("JAVASCRIPT", "Accidental lingua franca of the web")
|
@@ -57,7 +57,7 @@ module GraphQL
|
|
57
57
|
# }
|
58
58
|
#
|
59
59
|
# @example Enum whose values are different in ActiveRecord-land
|
60
|
-
# class Language < ActiveRecord::
|
60
|
+
# class Language < ActiveRecord::Base
|
61
61
|
# enum language: {
|
62
62
|
# rb: 0
|
63
63
|
# }
|
@@ -12,11 +12,19 @@ module GraphQL
|
|
12
12
|
attr_accessor :path
|
13
13
|
|
14
14
|
# @return [Hash] Optional data for error objects
|
15
|
+
# @deprecated Use `extensions` instead of `options`. The GraphQL spec
|
16
|
+
# recommends that any custom entries in an error be under the
|
17
|
+
# `extensions` key.
|
15
18
|
attr_accessor :options
|
16
19
|
|
17
|
-
|
20
|
+
# @return [Hash] Optional custom data for error objects which will be added
|
21
|
+
# under the `extensions` key.
|
22
|
+
attr_accessor :extensions
|
23
|
+
|
24
|
+
def initialize(message, ast_node: nil, options: nil, extensions: nil)
|
18
25
|
@ast_node = ast_node
|
19
26
|
@options = options
|
27
|
+
@extensions = extensions
|
20
28
|
super(message)
|
21
29
|
end
|
22
30
|
|
@@ -39,6 +47,10 @@ module GraphQL
|
|
39
47
|
if options
|
40
48
|
hash.merge!(options)
|
41
49
|
end
|
50
|
+
if extensions
|
51
|
+
hash["extensions"] ||= {}
|
52
|
+
hash["extensions"].merge!(extensions)
|
53
|
+
end
|
42
54
|
hash
|
43
55
|
end
|
44
56
|
end
|
@@ -5,7 +5,6 @@ module GraphQL
|
|
5
5
|
end
|
6
6
|
|
7
7
|
require "graphql/introspection/base_object"
|
8
|
-
require "graphql/introspection/typename_field"
|
9
8
|
require "graphql/introspection/input_value_type"
|
10
9
|
require "graphql/introspection/enum_value_type"
|
11
10
|
require "graphql/introspection/type_kind_enum"
|
@@ -14,8 +13,6 @@ require "graphql/introspection/field_type"
|
|
14
13
|
require "graphql/introspection/directive_location_enum"
|
15
14
|
require "graphql/introspection/directive_type"
|
16
15
|
require "graphql/introspection/schema_type"
|
17
|
-
require "graphql/introspection/schema_field"
|
18
|
-
require "graphql/introspection/type_by_name_field"
|
19
16
|
require "graphql/introspection/introspection_query"
|
20
17
|
require "graphql/introspection/dynamic_fields"
|
21
18
|
require "graphql/introspection/entry_points"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Introspection
|
4
|
-
class DynamicFields <
|
4
|
+
class DynamicFields < Introspection::BaseObject
|
5
5
|
field :__typename, String, "The name of this type", null: false, extras: [:irep_node]
|
6
6
|
def __typename(irep_node:)
|
7
7
|
irep_node.owner_type.name
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Introspection
|
4
|
-
class EntryPoints <
|
4
|
+
class EntryPoints < Introspection::BaseObject
|
5
5
|
field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false
|
6
6
|
field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", null: true do
|
7
7
|
argument :name, String, required: true
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Introspection
|
4
|
-
class TypeType <
|
4
|
+
class TypeType < Introspection::BaseObject
|
5
5
|
graphql_name "__Type"
|
6
6
|
description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
|
7
7
|
"GraphQL as represented by the `__TypeKind` enum.\n\n"\
|
@@ -24,7 +24,6 @@ module GraphQL
|
|
24
24
|
end
|
25
25
|
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true
|
26
26
|
field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
|
27
|
-
introspection true
|
28
27
|
|
29
28
|
def kind
|
30
29
|
@object.kind.name
|
@@ -1651,14 +1651,14 @@ module_eval(<<'.,.,', 'parser.y', 341)
|
|
1651
1651
|
|
1652
1652
|
module_eval(<<'.,.,', 'parser.y', 345)
|
1653
1653
|
def _reduce_141(val, _values, result)
|
1654
|
-
return [make_node(:TypeName, name: val[0])]
|
1654
|
+
return [make_node(:TypeName, name: val[0], position_source: val[0])]
|
1655
1655
|
result
|
1656
1656
|
end
|
1657
1657
|
.,.,
|
1658
1658
|
|
1659
1659
|
module_eval(<<'.,.,', 'parser.y', 346)
|
1660
1660
|
def _reduce_142(val, _values, result)
|
1661
|
-
val[0] << make_node(:TypeName, name: val[2])
|
1661
|
+
val[0] << make_node(:TypeName, name: val[2], position_source: val[2])
|
1662
1662
|
result
|
1663
1663
|
end
|
1664
1664
|
.,.,
|
@@ -343,8 +343,8 @@ rule
|
|
343
343
|
}
|
344
344
|
|
345
345
|
union_members:
|
346
|
-
name { return [make_node(:TypeName, name: val[0])]}
|
347
|
-
| union_members PIPE name { val[0] << make_node(:TypeName, name: val[2]) }
|
346
|
+
name { return [make_node(:TypeName, name: val[0], position_source: val[0])]}
|
347
|
+
| union_members PIPE name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
|
348
348
|
|
349
349
|
union_type_definition:
|
350
350
|
UNION name directives_list_opt EQUALS union_members {
|
data/lib/graphql/railtie.rb
CHANGED
@@ -40,7 +40,7 @@ module GraphQL
|
|
40
40
|
unless File.exists?(destination_file)
|
41
41
|
FileUtils.mkdir_p(File.dirname(destination_file))
|
42
42
|
File.open(destination_file, 'w') do |f|
|
43
|
-
f.
|
43
|
+
f.puts "class Types::BaseScalar < GraphQL::Schema::Scalar\nend"
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -48,7 +48,7 @@ module GraphQL
|
|
48
48
|
unless File.exists?(destination_file)
|
49
49
|
FileUtils.mkdir_p(File.dirname(destination_file))
|
50
50
|
File.open(destination_file, 'w') do |f|
|
51
|
-
f.
|
51
|
+
f.puts "class Types::BaseInputObject < GraphQL::Schema::InputObject\nend"
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -56,7 +56,7 @@ module GraphQL
|
|
56
56
|
unless File.exists?(destination_file)
|
57
57
|
FileUtils.mkdir_p(File.dirname(destination_file))
|
58
58
|
File.open(destination_file, 'w') do |f|
|
59
|
-
f.
|
59
|
+
f.puts "class Types::BaseEnum < GraphQL::Schema::Enum\nend"
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -64,7 +64,7 @@ module GraphQL
|
|
64
64
|
unless File.exists?(destination_file)
|
65
65
|
FileUtils.mkdir_p(File.dirname(destination_file))
|
66
66
|
File.open(destination_file, 'w') do |f|
|
67
|
-
f.
|
67
|
+
f.puts "class Types::BaseUnion < GraphQL::Schema::Union\nend"
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -72,14 +72,14 @@ module GraphQL
|
|
72
72
|
unless File.exists?(destination_file)
|
73
73
|
FileUtils.mkdir_p(File.dirname(destination_file))
|
74
74
|
File.open(destination_file, 'w') do |f|
|
75
|
-
f.
|
75
|
+
f.puts "module Types::BaseInterface\n include GraphQL::Schema::Interface\nend"
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
destination_file = File.join(base_dir, "types", "base_object.rb")
|
80
80
|
unless File.exists?(destination_file)
|
81
81
|
File.open(destination_file, 'w') do |f|
|
82
|
-
f.
|
82
|
+
f.puts "class Types::BaseObject < GraphQL::Schema::Object\nend"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -136,13 +136,17 @@ module GraphQL
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def visible_type?(type_defn)
|
139
|
-
visible?(type_defn)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
139
|
+
return false unless visible?(type_defn)
|
140
|
+
return true if root_type?(type_defn)
|
141
|
+
return true if type_defn.introspection?
|
142
|
+
|
143
|
+
if type_defn.kind.union?
|
144
|
+
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
145
|
+
elsif type_defn.kind.interface?
|
146
|
+
visible_possible_types?(type_defn)
|
147
|
+
else
|
148
|
+
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
149
|
+
end
|
146
150
|
end
|
147
151
|
|
148
152
|
def root_type?(type_defn)
|
@@ -154,6 +158,10 @@ module GraphQL
|
|
154
158
|
members.any? { |m| visible?(m) }
|
155
159
|
end
|
156
160
|
|
161
|
+
def orphan_type?(type_defn)
|
162
|
+
@schema.orphan_types.include?(type_defn)
|
163
|
+
end
|
164
|
+
|
157
165
|
def visible_abstract_type?(type_defn)
|
158
166
|
type_defn.kind.object? && (
|
159
167
|
interfaces(type_defn).any? ||
|
@@ -161,9 +169,8 @@ module GraphQL
|
|
161
169
|
)
|
162
170
|
end
|
163
171
|
|
164
|
-
def
|
165
|
-
(type_defn.
|
166
|
-
@schema.possible_types(type_defn).any? { |t| visible_type?(t) }
|
172
|
+
def visible_possible_types?(type_defn)
|
173
|
+
@schema.possible_types(type_defn).any? { |t| visible_type?(t) }
|
167
174
|
end
|
168
175
|
|
169
176
|
def visible?(member)
|
@@ -19,7 +19,7 @@ module GraphQL
|
|
19
19
|
field = context.warden.get_field(parent_type, ast_field.name)
|
20
20
|
|
21
21
|
if field.nil?
|
22
|
-
if
|
22
|
+
if parent_type.kind.union?
|
23
23
|
context.errors << message("Selections can't be made directly on unions (see selections on #{parent_type.name})", parent, context: context)
|
24
24
|
else
|
25
25
|
context.errors << message("Field '#{ast_field.name}' doesn't exist on type '#{parent_type.name}'", ast_field, context: context)
|
@@ -29,8 +29,8 @@ module GraphQL
|
|
29
29
|
else
|
30
30
|
"Selections can't be made on scalars (%{node_name} returns #{resolved_type.name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
|
31
31
|
end
|
32
|
-
elsif resolved_type.kind.
|
33
|
-
"
|
32
|
+
elsif resolved_type.kind.fields? && ast_node.selections.none?
|
33
|
+
"Field must have selections (%{node_name} returns #{resolved_type.name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
|
34
34
|
else
|
35
35
|
nil
|
36
36
|
end
|
@@ -356,10 +356,10 @@ module GraphQL
|
|
356
356
|
# This is not good, it will hit false positives
|
357
357
|
# Should use AST to make this substitution
|
358
358
|
if obj_arg_name != "_"
|
359
|
-
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\
|
359
|
+
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
|
360
360
|
end
|
361
361
|
if ctx_arg_name != "_"
|
362
|
-
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\
|
362
|
+
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
|
363
363
|
end
|
364
364
|
|
365
365
|
method_defn = "def #{@proc_name}(**#{args_arg_name})\n#{method_defn_indent} #{proc_body}\n#{method_defn_indent}end\n"
|
@@ -491,8 +491,8 @@ module GraphQL
|
|
491
491
|
# - Get the three argument names (obj, arg, ctx)
|
492
492
|
# - Get the proc body
|
493
493
|
# - Find and replace:
|
494
|
-
# - The ctx argument becomes
|
495
|
-
# - The obj argument becomes
|
494
|
+
# - The ctx argument becomes `context`
|
495
|
+
# - The obj argument becomes `object`
|
496
496
|
# - Args is trickier:
|
497
497
|
# - If it's not used, remove it
|
498
498
|
# - If it's used, abandon ship and make it `**args`
|
@@ -513,10 +513,10 @@ module GraphQL
|
|
513
513
|
# This is not good, it will hit false positives
|
514
514
|
# Should use AST to make this substitution
|
515
515
|
if obj_arg_name != "_"
|
516
|
-
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\
|
516
|
+
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
|
517
517
|
end
|
518
518
|
if ctx_arg_name != "_"
|
519
|
-
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\
|
519
|
+
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
|
520
520
|
end
|
521
521
|
|
522
522
|
method_def_indent = " " * (processor.resolve_indent - 2)
|
data/lib/graphql/version.rb
CHANGED
@@ -13,13 +13,13 @@ module Platform
|
|
13
13
|
field :starting_line, Integer, description: "The starting line for the range", null: false
|
14
14
|
|
15
15
|
def starting_line
|
16
|
-
|
16
|
+
object.lines.first[:lineno]
|
17
17
|
end
|
18
18
|
|
19
19
|
field :ending_line, Integer, description: "The ending line for the range", null: false
|
20
20
|
|
21
21
|
def ending_line
|
22
|
-
|
22
|
+
object.lines.first[:lineno] + (object.lines.length - 1)
|
23
23
|
end
|
24
24
|
|
25
25
|
field :commit, Objects::Commit, description: "Identifies the line author", null: false
|
@@ -12,13 +12,13 @@ module Platform
|
|
12
12
|
|
13
13
|
def resolve(**inputs)
|
14
14
|
project = Platform::Helpers::NodeIdentification.typed_object_from_id(
|
15
|
-
[Objects::Project], inputs[:project_id],
|
15
|
+
[Objects::Project], inputs[:project_id], context
|
16
16
|
)
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
context[:permission].can_modify?("DeleteProject", project).sync
|
19
|
+
context[:abilities].authorize_content(:project, :destroy, owner: project.owner)
|
20
20
|
|
21
|
-
project.enqueue_delete(actor:
|
21
|
+
project.enqueue_delete(actor: context[:viewer])
|
22
22
|
|
23
23
|
{ owner: project.owner }
|
24
24
|
end
|
@@ -20,7 +20,7 @@ module Platform
|
|
20
20
|
{ abcDef: 1 }
|
21
21
|
some_method do { xyzAbc: 1 } end
|
22
22
|
|
23
|
-
thing = Platform::Helpers::NodeIdentification.typed_object_from_id(Objects::Thing, inputs[:thing_id],
|
23
|
+
thing = Platform::Helpers::NodeIdentification.typed_object_from_id(Objects::Thing, inputs[:thing_id], context)
|
24
24
|
raise Errors::Validation.new("Thing not found.") unless thing
|
25
25
|
|
26
26
|
ThingActivity.track(thing.id, Time.now.change(min: 0, sec: 0))
|
@@ -13,9 +13,9 @@ module Platform
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def viewer_has_starred(**arguments)
|
16
|
-
if
|
16
|
+
if context[:viewer]
|
17
17
|
->(test_inner_proc) do
|
18
|
-
|
18
|
+
context[:viewer].starred?(object)
|
19
19
|
end
|
20
20
|
else
|
21
21
|
false
|
@@ -27,11 +27,11 @@ module Platform
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def stargazers(**arguments)
|
30
|
-
scope = case
|
30
|
+
scope = case object
|
31
31
|
when Repository
|
32
|
-
|
32
|
+
object.stars
|
33
33
|
when Gist
|
34
|
-
GistStar.where(gist_id:
|
34
|
+
GistStar.where(gist_id: object.id)
|
35
35
|
end
|
36
36
|
|
37
37
|
table = scope.table_name
|
@@ -11,17 +11,17 @@ module Platform
|
|
11
11
|
field :viewer_subscription, Enums::SubscriptionState, description: "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", null: false
|
12
12
|
|
13
13
|
def viewer_subscription
|
14
|
-
if
|
14
|
+
if context[:viewer].nil?
|
15
15
|
return "unsubscribed"
|
16
16
|
end
|
17
17
|
|
18
|
-
subscription_status_response =
|
18
|
+
subscription_status_response = object.async_subscription_status(context[:viewer]).sync
|
19
19
|
|
20
20
|
if subscription_status_response.failed?
|
21
21
|
error = Platform::Errors::ServiceUnavailable.new("Subscriptions are currently unavailable. Please try again later.")
|
22
|
-
error.ast_node =
|
23
|
-
error.path =
|
24
|
-
|
22
|
+
error.ast_node = context.irep_node.ast_node
|
23
|
+
error.path = context.path
|
24
|
+
context.errors << error
|
25
25
|
return "unavailable"
|
26
26
|
end
|
27
27
|
|
@@ -38,9 +38,9 @@ module Platform
|
|
38
38
|
field :viewer_can_subscribe, Boolean, description: "Check if the viewer is able to change their subscription status for the repository.", null: false
|
39
39
|
|
40
40
|
def viewer_can_subscribe
|
41
|
-
return false if
|
41
|
+
return false if context[:viewer].nil?
|
42
42
|
|
43
|
-
|
43
|
+
object.async_subscription_status(context[:viewer]).then(&:success?)
|
44
44
|
end
|
45
45
|
|
46
46
|
field :issues, function: Platform::Functions::Issues.new, description: "A list of issues associated with the milestone.", connection: true
|
@@ -23,12 +23,12 @@ module Platform
|
|
23
23
|
def f4(**arguments)
|
24
24
|
Class1.new(
|
25
25
|
a: Class2.new(
|
26
|
-
b:
|
27
|
-
c:
|
26
|
+
b: object.b_1,
|
27
|
+
c: object.c_1
|
28
28
|
),
|
29
29
|
d: Class3.new(
|
30
|
-
b:
|
31
|
-
c:
|
30
|
+
b: object.b_2,
|
31
|
+
c: object.c_3,
|
32
32
|
)
|
33
33
|
)
|
34
34
|
end
|
@@ -46,9 +46,9 @@ module Platform
|
|
46
46
|
field :f10, String, null: true
|
47
47
|
|
48
48
|
def f10
|
49
|
-
|
49
|
+
object.something do |_|
|
50
50
|
xyz_obj.obj
|
51
|
-
|
51
|
+
object.f10
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -92,7 +92,7 @@ describe GraphQL::Execution::Multiplex do
|
|
92
92
|
},
|
93
93
|
{
|
94
94
|
"errors" => [{
|
95
|
-
"message"=>"
|
95
|
+
"message"=>"Field must have selections (field 'nullableNestedSum' returns LazySum but has no selections. Did you mean 'nullableNestedSum { ... }'?)",
|
96
96
|
"locations"=>[{"line"=>1, "column"=>4}],
|
97
97
|
"fields"=>["query", "validationError"]
|
98
98
|
}]
|
@@ -271,7 +271,26 @@ describe GraphQL::ExecutionError do
|
|
271
271
|
assert_equal(expected_result, result)
|
272
272
|
end
|
273
273
|
end
|
274
|
-
|
274
|
+
|
275
|
+
describe "extensions in ExecutionError" do
|
276
|
+
let(:query_string) {%|
|
277
|
+
{
|
278
|
+
executionErrorWithExtensions
|
279
|
+
}
|
280
|
+
|}
|
281
|
+
it "the error is inserted into the errors key with custom data set in `extensions`" do
|
282
|
+
expected_result = {
|
283
|
+
"data"=>{"executionErrorWithExtensions"=>nil},
|
284
|
+
"errors"=>
|
285
|
+
[{"message"=>"Permission Denied!",
|
286
|
+
"locations"=>[{"line"=>3, "column"=>7}],
|
287
|
+
"path"=>["executionErrorWithExtensions"],
|
288
|
+
"extensions"=>{"code"=>"permission_denied"}}]
|
289
|
+
}
|
290
|
+
assert_equal(expected_result, result)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
275
294
|
describe "more than one ExecutionError" do
|
276
295
|
let(:query_string) { %|{ multipleErrorsOnNonNullableField} |}
|
277
296
|
it "the errors are inserted into the errors key and the data is nil even for a NonNullable field " do
|
@@ -30,6 +30,7 @@ describe GraphQL::Introspection::SchemaType do
|
|
30
30
|
{"name"=>"deepNonNull"},
|
31
31
|
{"name"=>"error"},
|
32
32
|
{"name"=>"executionError"},
|
33
|
+
{"name"=>"executionErrorWithExtensions"},
|
33
34
|
{"name"=>"executionErrorWithOptions"},
|
34
35
|
{"name"=>"favoriteEdible"},
|
35
36
|
{"name"=>"fromSource"},
|
@@ -1,7 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
-
|
4
|
+
if MONGO_DETECTED
|
5
|
+
require "support/star_trek/data"
|
6
|
+
require "support/star_trek/schema"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe GraphQL::Relay::MongoRelationConnection do
|
10
|
+
before do
|
11
|
+
if !MONGO_DETECTED
|
12
|
+
skip("Mongo not detected")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
def get_names(result)
|
6
17
|
ships = result["data"]["federation"]["bases"]["edges"]
|
7
18
|
ships.map { |e| e["node"]["name"] }
|
@@ -358,6 +358,135 @@ describe GraphQL::Schema::Warden do
|
|
358
358
|
assert_equal false, possible_type_names(res["data"]["LanguageMember"]).include?("Phoneme")
|
359
359
|
end
|
360
360
|
|
361
|
+
it "hides interfaces if all possible types are hidden" do
|
362
|
+
sdl = %|
|
363
|
+
type Query {
|
364
|
+
a: String
|
365
|
+
repository: Repository
|
366
|
+
}
|
367
|
+
|
368
|
+
type Repository implements Node {
|
369
|
+
id: ID!
|
370
|
+
}
|
371
|
+
|
372
|
+
interface Node {
|
373
|
+
id: ID!
|
374
|
+
}
|
375
|
+
|
|
376
|
+
|
377
|
+
schema = GraphQL::Schema.from_definition(sdl)
|
378
|
+
|
379
|
+
query_string = %|
|
380
|
+
{
|
381
|
+
Node: __type(name: "Node") { name }
|
382
|
+
}
|
383
|
+
|
|
384
|
+
|
385
|
+
res = schema.execute(query_string)
|
386
|
+
assert res["data"]["Node"]
|
387
|
+
|
388
|
+
res = schema.execute(query_string, except: ->(m, _) { m.name == "Repository" })
|
389
|
+
assert_nil res["data"]["Node"]
|
390
|
+
end
|
391
|
+
|
392
|
+
it "hides unions if all possible types are hidden or its references are hidden" do
|
393
|
+
sdl = "
|
394
|
+
type Query {
|
395
|
+
bag: BagOfThings
|
396
|
+
}
|
397
|
+
|
398
|
+
type A {
|
399
|
+
id: ID!
|
400
|
+
}
|
401
|
+
|
402
|
+
type B {
|
403
|
+
id: ID!
|
404
|
+
}
|
405
|
+
|
406
|
+
type C {
|
407
|
+
id: ID!
|
408
|
+
}
|
409
|
+
|
410
|
+
union BagOfThings = A | B | C
|
411
|
+
"
|
412
|
+
|
413
|
+
schema = GraphQL::Schema.from_definition(sdl)
|
414
|
+
schema.orphan_types = []
|
415
|
+
|
416
|
+
query_string = %|
|
417
|
+
{
|
418
|
+
BagOfThings: __type(name: "BagOfThings") { name }
|
419
|
+
Query: __type(name: "Query") { fields { name } }
|
420
|
+
}
|
421
|
+
|
|
422
|
+
|
423
|
+
res = schema.execute(query_string)
|
424
|
+
assert res["data"]["BagOfThings"]
|
425
|
+
assert_equal ["bag"], res["data"]["Query"]["fields"].map { |f| f["name"] }
|
426
|
+
|
427
|
+
# Hide the union when all its possible types are gone. This will cause the field to be hidden too.
|
428
|
+
res = schema.execute(query_string, except: ->(m, _) { ["A", "B", "C"].include?(m.name) })
|
429
|
+
assert_nil res["data"]["BagOfThings"]
|
430
|
+
assert_equal [], res["data"]["Query"]["fields"]
|
431
|
+
|
432
|
+
res = schema.execute(query_string, except: ->(m, _) { m.name == "bag" })
|
433
|
+
assert_nil res["data"]["BagOfThings"]
|
434
|
+
assert_equal [], res["data"]["Query"]["fields"]
|
435
|
+
|
436
|
+
# Unreferenced but still visible because orphan type
|
437
|
+
schema.orphan_types = [schema.find("BagOfThings")]
|
438
|
+
res = schema.execute(query_string, except: ->(m, _) { m.name == "bag" })
|
439
|
+
assert res["data"]["BagOfThings"]
|
440
|
+
end
|
441
|
+
|
442
|
+
it "hides interfaces if all possible types are hidden or its references are hidden" do
|
443
|
+
sdl = "
|
444
|
+
type Query {
|
445
|
+
node: Node
|
446
|
+
}
|
447
|
+
|
448
|
+
type A implements Node {
|
449
|
+
id: ID!
|
450
|
+
}
|
451
|
+
|
452
|
+
type B implements Node {
|
453
|
+
id: ID!
|
454
|
+
}
|
455
|
+
|
456
|
+
type C implements Node {
|
457
|
+
id: ID!
|
458
|
+
}
|
459
|
+
|
460
|
+
interface Node {
|
461
|
+
id: ID!
|
462
|
+
}
|
463
|
+
"
|
464
|
+
|
465
|
+
schema = GraphQL::Schema.from_definition(sdl)
|
466
|
+
|
467
|
+
query_string = %|
|
468
|
+
{
|
469
|
+
Node: __type(name: "Node") { name }
|
470
|
+
Query: __type(name: "Query") { fields { name } }
|
471
|
+
}
|
472
|
+
|
|
473
|
+
|
474
|
+
res = schema.execute(query_string)
|
475
|
+
assert res["data"]["Node"]
|
476
|
+
assert_equal ["node"], res["data"]["Query"]["fields"].map { |f| f["name"] }
|
477
|
+
|
478
|
+
# When the possible types are all hidden, hide the interface and fields pointing to it
|
479
|
+
res = schema.execute(query_string, except: ->(m, _) { ["A", "B", "C"].include?(m.name) })
|
480
|
+
assert_nil res["data"]["Node"]
|
481
|
+
assert_equal [], res["data"]["Query"]["fields"]
|
482
|
+
|
483
|
+
# Even when it's not the return value of a field,
|
484
|
+
# still show the interface since it allows code reuse
|
485
|
+
res = schema.execute(query_string, except: ->(m, _) { m.name == "node" })
|
486
|
+
assert_equal "Node", res["data"]["Node"]["name"]
|
487
|
+
assert_equal [], res["data"]["Query"]["fields"]
|
488
|
+
end
|
489
|
+
|
361
490
|
it "can't be a fragment condition" do
|
362
491
|
query_string = %|
|
363
492
|
{
|
@@ -6,32 +6,40 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
|
|
6
6
|
let(:query_string) {"
|
7
7
|
query getCheese {
|
8
8
|
okCheese: cheese(id: 1) { fatContent, similarCheese(source: YAK) { source } }
|
9
|
-
|
9
|
+
missingFieldsObject: cheese(id: 1)
|
10
|
+
missingFieldsInterface: cheese(id: 1) { selfAsEdible }
|
10
11
|
illegalSelectionCheese: cheese(id: 1) { id { something, ... someFields } }
|
11
12
|
incorrectFragmentSpread: cheese(id: 1) { flavor { ... on String { __typename } } }
|
12
13
|
}
|
13
14
|
"}
|
14
15
|
|
15
16
|
it "adds errors for selections on scalars" do
|
16
|
-
assert_equal(
|
17
|
+
assert_equal(4, errors.length)
|
17
18
|
|
18
19
|
illegal_selection_error = {
|
19
20
|
"message"=>"Selections can't be made on scalars (field 'id' returns Int but has selections [something, someFields])",
|
20
|
-
"locations"=>[{"line"=>
|
21
|
+
"locations"=>[{"line"=>6, "column"=>47}],
|
21
22
|
"fields"=>["query getCheese", "illegalSelectionCheese", "id"],
|
22
23
|
}
|
23
24
|
assert_includes(errors, illegal_selection_error, "finds illegal selections on scalars")
|
24
25
|
|
25
|
-
|
26
|
-
"message"=>"
|
26
|
+
objects_selection_required_error = {
|
27
|
+
"message"=>"Field must have selections (field 'cheese' returns Cheese but has no selections. Did you mean 'cheese { ... }'?)",
|
27
28
|
"locations"=>[{"line"=>4, "column"=>7}],
|
28
|
-
"fields"=>["query getCheese", "
|
29
|
+
"fields"=>["query getCheese", "missingFieldsObject"],
|
30
|
+
}
|
31
|
+
assert_includes(errors, objects_selection_required_error, "finds objects without selections")
|
32
|
+
|
33
|
+
interfaces_selection_required_error = {
|
34
|
+
"message"=>"Field must have selections (field 'selfAsEdible' returns Edible but has no selections. Did you mean 'selfAsEdible { ... }'?)",
|
35
|
+
"locations"=>[{"line"=>5, "column"=>47}],
|
36
|
+
"fields"=>["query getCheese", "missingFieldsInterface", "selfAsEdible"],
|
29
37
|
}
|
30
|
-
assert_includes(errors,
|
38
|
+
assert_includes(errors, interfaces_selection_required_error, "finds interfaces without selections")
|
31
39
|
|
32
40
|
incorrect_fragment_error = {
|
33
41
|
"message"=>"Selections can't be made on scalars (field 'flavor' returns String but has inline fragments [String])",
|
34
|
-
"locations"=>[{"line"=>
|
42
|
+
"locations"=>[{"line"=>7, "column"=>48}],
|
35
43
|
"fields"=>["query getCheese", "incorrectFragmentSpread", "flavor"],
|
36
44
|
}
|
37
45
|
assert_includes(errors, incorrect_fragment_error, "finds scalar fields with selections")
|
@@ -43,7 +51,7 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
|
|
43
51
|
assert_equal(1, errors.length)
|
44
52
|
|
45
53
|
selections_required_error = {
|
46
|
-
"message"=> "
|
54
|
+
"message"=> "Field must have selections (anonymous query returns Query but has no selections. Did you mean ' { ... }'?)",
|
47
55
|
"locations"=>[{"line"=>1, "column"=>1}],
|
48
56
|
"fields"=>["query"]
|
49
57
|
}
|
@@ -195,7 +195,7 @@ RUBY
|
|
195
195
|
end
|
196
196
|
|
197
197
|
describe "resolve proc to method" do
|
198
|
-
it "converts
|
198
|
+
it "converts object and context" do
|
199
199
|
old = %{
|
200
200
|
field :firstName, !types.String do
|
201
201
|
resolve ->(obj, arg, ctx) {
|
@@ -211,11 +211,11 @@ RUBY
|
|
211
211
|
field :first_name, String, null: false
|
212
212
|
|
213
213
|
def first_name
|
214
|
-
|
214
|
+
context.something
|
215
215
|
other_ctx # test combined identifiers
|
216
216
|
|
217
|
-
|
218
|
-
|
217
|
+
object[context] + object
|
218
|
+
object.given_name
|
219
219
|
end
|
220
220
|
}
|
221
221
|
assert_equal new, upgrade(old)
|
@@ -233,7 +233,7 @@ RUBY
|
|
233
233
|
field :first_name, String, null: false
|
234
234
|
|
235
235
|
def first_name
|
236
|
-
|
236
|
+
object.given_name
|
237
237
|
end
|
238
238
|
}
|
239
239
|
assert_equal new, upgrade(old)
|
data/spec/spec_helper.rb
CHANGED
@@ -27,6 +27,22 @@ require "pry"
|
|
27
27
|
require "minitest/autorun"
|
28
28
|
require "minitest/focus"
|
29
29
|
require "minitest/reporters"
|
30
|
+
|
31
|
+
MONGO_DETECTED = begin
|
32
|
+
require "mongo"
|
33
|
+
Mongo::Client.new('mongodb://127.0.0.1:27017/graphql_ruby_test',
|
34
|
+
connect_timeout: 1,
|
35
|
+
socket_timeout: 1,
|
36
|
+
server_selection_timeout: 1,
|
37
|
+
logger: Logger.new(nil)
|
38
|
+
)
|
39
|
+
.database
|
40
|
+
.collections
|
41
|
+
rescue StandardError, LoadError => err # rubocop:disable Lint/UselessAssignment
|
42
|
+
# puts err.message, err.backtrace
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
30
46
|
Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(color: true)
|
31
47
|
|
32
48
|
Minitest::Spec.make_my_diffs_pretty!
|
@@ -62,9 +78,12 @@ NO_OP_RESOLVE_TYPE = ->(type, obj, ctx) {
|
|
62
78
|
|
63
79
|
# Load support files
|
64
80
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
|
81
|
+
# These require mongodb in order to run,
|
82
|
+
# so only load them in the specific tests that require them.
|
83
|
+
next if f.include?("star_trek")
|
84
|
+
|
65
85
|
unless rails_should_be_installed?
|
66
86
|
next if f.end_with?('star_wars/data.rb')
|
67
|
-
next if f.end_with?('star_trek/data.rb')
|
68
87
|
next if f.end_with?('base_generator_test.rb')
|
69
88
|
end
|
70
89
|
require f
|
@@ -381,6 +381,13 @@ module Dummy
|
|
381
381
|
}
|
382
382
|
end
|
383
383
|
|
384
|
+
field :executionErrorWithExtensions do
|
385
|
+
type GraphQL::INT_TYPE
|
386
|
+
resolve ->(t, a, c) {
|
387
|
+
GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
|
388
|
+
}
|
389
|
+
end
|
390
|
+
|
384
391
|
# To test possibly-null fields
|
385
392
|
field :maybeNull, MaybeNullType do
|
386
393
|
resolve ->(t, a, c) { OpenStruct.new(cheese: nil) }
|
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.8.
|
4
|
+
version: 1.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -304,20 +304,6 @@ dependencies:
|
|
304
304
|
- - ">="
|
305
305
|
- !ruby/object:Gem::Version
|
306
306
|
version: '0'
|
307
|
-
- !ruby/object:Gem::Dependency
|
308
|
-
name: algoliasearch-jekyll
|
309
|
-
requirement: !ruby/object:Gem::Requirement
|
310
|
-
requirements:
|
311
|
-
- - ">="
|
312
|
-
- !ruby/object:Gem::Version
|
313
|
-
version: '0'
|
314
|
-
type: :development
|
315
|
-
prerelease: false
|
316
|
-
version_requirements: !ruby/object:Gem::Requirement
|
317
|
-
requirements:
|
318
|
-
- - ">="
|
319
|
-
- !ruby/object:Gem::Version
|
320
|
-
version: '0'
|
321
307
|
description: A plain-Ruby implementation of GraphQL.
|
322
308
|
email:
|
323
309
|
- rdmosolgo@gmail.com
|
@@ -433,12 +419,9 @@ files:
|
|
433
419
|
- lib/graphql/introspection/field_type.rb
|
434
420
|
- lib/graphql/introspection/input_value_type.rb
|
435
421
|
- lib/graphql/introspection/introspection_query.rb
|
436
|
-
- lib/graphql/introspection/schema_field.rb
|
437
422
|
- lib/graphql/introspection/schema_type.rb
|
438
|
-
- lib/graphql/introspection/type_by_name_field.rb
|
439
423
|
- lib/graphql/introspection/type_kind_enum.rb
|
440
424
|
- lib/graphql/introspection/type_type.rb
|
441
|
-
- lib/graphql/introspection/typename_field.rb
|
442
425
|
- lib/graphql/invalid_name_error.rb
|
443
426
|
- lib/graphql/invalid_null_error.rb
|
444
427
|
- lib/graphql/language.rb
|
@@ -1005,7 +988,6 @@ files:
|
|
1005
988
|
- spec/graphql/introspection/input_value_type_spec.rb
|
1006
989
|
- spec/graphql/introspection/introspection_query_spec.rb
|
1007
990
|
- spec/graphql/introspection/schema_type_spec.rb
|
1008
|
-
- spec/graphql/introspection/type_by_name_field_spec.rb
|
1009
991
|
- spec/graphql/introspection/type_type_spec.rb
|
1010
992
|
- spec/graphql/language/block_string_spec.rb
|
1011
993
|
- spec/graphql/language/definition_slice_spec.rb
|
@@ -1553,7 +1535,6 @@ test_files:
|
|
1553
1535
|
- spec/graphql/introspection/input_value_type_spec.rb
|
1554
1536
|
- spec/graphql/introspection/introspection_query_spec.rb
|
1555
1537
|
- spec/graphql/introspection/schema_type_spec.rb
|
1556
|
-
- spec/graphql/introspection/type_by_name_field_spec.rb
|
1557
1538
|
- spec/graphql/introspection/type_type_spec.rb
|
1558
1539
|
- spec/graphql/language/block_string_spec.rb
|
1559
1540
|
- spec/graphql/language/definition_slice_spec.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Introspection
|
4
|
-
SchemaField = GraphQL::Field.define do
|
5
|
-
name("__schema")
|
6
|
-
description("This GraphQL schema")
|
7
|
-
type(GraphQL::Schema::LateBoundType.new("__Schema").to_non_null_type)
|
8
|
-
resolve ->(o, a, ctx) {
|
9
|
-
# Apply wrapping manually since this field isn't wrapped by instrumentation
|
10
|
-
schema = ctx.query.schema
|
11
|
-
schema_type = schema.introspection_system.schema_type
|
12
|
-
schema_type.metadata[:type_class].new(schema, ctx.query.context)
|
13
|
-
}
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Introspection
|
4
|
-
TypeByNameField = GraphQL::Field.define do
|
5
|
-
name("__type")
|
6
|
-
description("A type in the GraphQL system")
|
7
|
-
introspection true
|
8
|
-
type(GraphQL::Schema::LateBoundType.new("__Type"))
|
9
|
-
argument :name, !types.String
|
10
|
-
resolve ->(o, args, ctx) {
|
11
|
-
type = ctx.warden.get_type(args["name"])
|
12
|
-
if type
|
13
|
-
# Apply wrapping manually since this field isn't wrapped by instrumentation
|
14
|
-
type_type = ctx.schema.introspection_system.type_type
|
15
|
-
type_type.metadata[:type_class].new(type, ctx)
|
16
|
-
else
|
17
|
-
nil
|
18
|
-
end
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Introspection
|
4
|
-
TypenameField = GraphQL::Field.define do
|
5
|
-
name "__typename"
|
6
|
-
description "The name of this type"
|
7
|
-
type -> { !GraphQL::STRING_TYPE }
|
8
|
-
introspection true
|
9
|
-
resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
describe GraphQL::Introspection::TypeByNameField do
|
5
|
-
describe "after instrumentation" do
|
6
|
-
# Just make sure it returns a new object, not the original field
|
7
|
-
class DupInstrumenter
|
8
|
-
def self.instrument(t, f)
|
9
|
-
f.redefine {
|
10
|
-
resolve ->(o, a, c) { :no_op }
|
11
|
-
}
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class ArgAnalyzer
|
16
|
-
def call(_, _, node)
|
17
|
-
if node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
|
18
|
-
node.arguments
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
let(:instrumented_schema) {
|
24
|
-
# This was probably assigned earlier in the test suite, but to simulate an application, clear it.
|
25
|
-
GraphQL::Introspection::TypeByNameField.arguments_class = nil
|
26
|
-
|
27
|
-
Dummy::Schema.redefine {
|
28
|
-
instrument(:field, DupInstrumenter)
|
29
|
-
query_analyzer(ArgAnalyzer.new)
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
it "still works with __type" do
|
34
|
-
res = instrumented_schema.execute("{ __type(name: \"X\") { name } }")
|
35
|
-
assert_equal({"data"=>{"__type"=>nil}}, res)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|