graphql 1.8.6 → 1.8.7
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 +5 -5
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/templates/base_enum.erb +3 -1
- data/lib/generators/graphql/templates/base_input_object.erb +3 -1
- data/lib/generators/graphql/templates/base_interface.erb +4 -2
- data/lib/generators/graphql/templates/base_object.erb +3 -1
- data/lib/generators/graphql/templates/base_union.erb +3 -1
- data/lib/generators/graphql/templates/enum.erb +5 -3
- data/lib/generators/graphql/templates/interface.erb +6 -4
- data/lib/generators/graphql/templates/loader.erb +14 -12
- data/lib/generators/graphql/templates/mutation.erb +9 -6
- data/lib/generators/graphql/templates/mutation_type.erb +8 -6
- data/lib/generators/graphql/templates/object.erb +6 -4
- data/lib/generators/graphql/templates/query_type.erb +13 -11
- data/lib/generators/graphql/templates/union.erb +5 -3
- data/lib/graphql/argument.rb +19 -2
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +2 -0
- data/lib/graphql/enum_type.rb +1 -0
- data/lib/graphql/execution/instrumentation.rb +28 -20
- data/lib/graphql/field.rb +3 -3
- data/lib/graphql/input_object_type.rb +2 -1
- data/lib/graphql/query.rb +1 -9
- data/lib/graphql/query/variables.rb +1 -18
- data/lib/graphql/relay.rb +0 -1
- data/lib/graphql/relay/mongo_relation_connection.rb +10 -0
- data/lib/graphql/relay/mutation.rb +2 -1
- data/lib/graphql/schema.rb +5 -4
- data/lib/graphql/schema/base_64_bp.rb +25 -0
- data/lib/graphql/schema/base_64_encoder.rb +5 -1
- data/lib/graphql/schema/field.rb +52 -22
- data/lib/graphql/schema/interface.rb +2 -0
- data/lib/graphql/schema/list.rb +3 -15
- data/lib/graphql/schema/member.rb +8 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +12 -6
- data/lib/graphql/schema/member/has_arguments.rb +7 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -0
- data/lib/graphql/schema/member/scoped.rb +21 -0
- data/lib/graphql/schema/non_null.rb +8 -17
- data/lib/graphql/schema/resolver.rb +99 -76
- data/lib/graphql/schema/unique_within_type.rb +4 -1
- data/lib/graphql/schema/wrapper.rb +29 -0
- data/lib/graphql/static_validation/validation_context.rb +1 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/type_kinds.rb +32 -8
- data/lib/graphql/types/relay/base_connection.rb +17 -3
- data/lib/graphql/types/relay/base_edge.rb +12 -0
- data/lib/graphql/version.rb +1 -1
- data/spec/generators/graphql/enum_generator_spec.rb +8 -6
- data/spec/generators/graphql/install_generator_spec.rb +24 -20
- data/spec/generators/graphql/interface_generator_spec.rb +6 -4
- data/spec/generators/graphql/loader_generator_spec.rb +30 -26
- data/spec/generators/graphql/mutation_generator_spec.rb +18 -13
- data/spec/generators/graphql/object_generator_spec.rb +12 -6
- data/spec/generators/graphql/union_generator_spec.rb +10 -4
- data/spec/graphql/authorization_spec.rb +55 -14
- data/spec/graphql/input_object_type_spec.rb +11 -0
- data/spec/graphql/language/generation_spec.rb +8 -6
- data/spec/graphql/language/nodes_spec.rb +8 -6
- data/spec/graphql/relay/connection_instrumentation_spec.rb +1 -1
- data/spec/graphql/relay/mongo_relation_connection_spec.rb +54 -0
- data/spec/graphql/schema/field_spec.rb +9 -0
- data/spec/graphql/schema/list_spec.rb +46 -0
- data/spec/graphql/schema/member/scoped_spec.rb +161 -0
- data/spec/graphql/schema/non_null_spec.rb +46 -0
- data/spec/graphql/schema/object_spec.rb +15 -0
- data/spec/graphql/schema/resolver_spec.rb +165 -25
- data/spec/graphql/subscriptions/serialize_spec.rb +0 -22
- data/spec/graphql/subscriptions_spec.rb +19 -31
- data/spec/support/global_id.rb +23 -0
- data/spec/support/lazy_helpers.rb +1 -1
- data/spec/support/star_trek/data.rb +19 -2
- data/spec/support/star_trek/schema.rb +37 -22
- data/spec/support/star_wars/schema.rb +24 -17
- metadata +220 -208
@@ -7,12 +7,14 @@ class GraphQLGeneratorsEnumGeneratorTest < BaseGeneratorTest
|
|
7
7
|
|
8
8
|
test "it generate enums with values" do
|
9
9
|
expected_content = <<-RUBY
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
module Types
|
11
|
+
class FamilyType < Types::BaseEnum
|
12
|
+
value "NIGHTSHADE"
|
13
|
+
value "BRASSICA", value: Family::COLE
|
14
|
+
value "UMBELLIFER", value: :umbellifer
|
15
|
+
value "LEGUME", value: "bean & friends"
|
16
|
+
value "CURCURBITS", value: 5
|
17
|
+
end
|
16
18
|
end
|
17
19
|
RUBY
|
18
20
|
|
@@ -48,15 +48,17 @@ RUBY
|
|
48
48
|
|
49
49
|
|
50
50
|
expected_query_type = <<-RUBY
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
module Types
|
52
|
+
class QueryType < Types::BaseObject
|
53
|
+
# Add root-level fields here.
|
54
|
+
# They will be entry points for queries on your schema.
|
55
|
+
|
56
|
+
# TODO: remove me
|
57
|
+
field :test_field, String, null: false,
|
58
|
+
description: \"An example field added by the generator\"
|
59
|
+
def test_field
|
60
|
+
\"Hello World!\"
|
61
|
+
end
|
60
62
|
end
|
61
63
|
end
|
62
64
|
RUBY
|
@@ -80,18 +82,20 @@ RUBY
|
|
80
82
|
end
|
81
83
|
|
82
84
|
expected_query_type = <<-RUBY
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
85
|
+
module Types
|
86
|
+
class QueryType < Types::BaseObject
|
87
|
+
# Add root-level fields here.
|
88
|
+
# They will be entry points for queries on your schema.
|
89
|
+
|
90
|
+
# TODO: remove me
|
91
|
+
field :test_field, String, null: false,
|
92
|
+
description: \"An example field added by the generator\"
|
93
|
+
def test_field
|
94
|
+
\"Hello World!\"
|
95
|
+
end
|
93
96
|
|
94
|
-
|
97
|
+
field :node, field: GraphQL::Relay::Node.field
|
98
|
+
end
|
95
99
|
end
|
96
100
|
RUBY
|
97
101
|
|
@@ -16,10 +16,12 @@ class GraphQLGeneratorsInterfaceGeneratorTest < BaseGeneratorTest
|
|
16
16
|
]
|
17
17
|
|
18
18
|
expected_content = <<-RUBY
|
19
|
-
module Types
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
module Types
|
20
|
+
module BirdType
|
21
|
+
include Types::BaseInterface
|
22
|
+
field :wingspan, Integer, null: false
|
23
|
+
field :foliage, [Types::ColorType], null: true
|
24
|
+
end
|
23
25
|
end
|
24
26
|
RUBY
|
25
27
|
|
@@ -9,19 +9,21 @@ class GraphQLGeneratorsLoaderGeneratorTest < BaseGeneratorTest
|
|
9
9
|
run_generator(["RecordLoader"])
|
10
10
|
|
11
11
|
expected_content = <<-RUBY
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
module Loaders
|
13
|
+
class RecordLoader < GraphQL::Batch::Loader
|
14
|
+
# Define `initialize` to store grouping arguments, eg
|
15
|
+
#
|
16
|
+
# Loaders::RecordLoader.for(group).load(value)
|
17
|
+
#
|
18
|
+
# def initialize()
|
19
|
+
# end
|
20
|
+
|
21
|
+
# `keys` contains each key from `.load(key)`.
|
22
|
+
# Find the corresponding values, then
|
23
|
+
# call `fulfill(key, value)` or `fulfill(key, nil)`
|
24
|
+
# for each key.
|
25
|
+
def perform(keys)
|
26
|
+
end
|
25
27
|
end
|
26
28
|
end
|
27
29
|
RUBY
|
@@ -33,19 +35,21 @@ RUBY
|
|
33
35
|
run_generator(["active_record::record_loader"])
|
34
36
|
|
35
37
|
expected_content = <<-RUBY
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
38
|
+
module Loaders
|
39
|
+
class ActiveRecord::RecordLoader < GraphQL::Batch::Loader
|
40
|
+
# Define `initialize` to store grouping arguments, eg
|
41
|
+
#
|
42
|
+
# Loaders::ActiveRecord::RecordLoader.for(group).load(value)
|
43
|
+
#
|
44
|
+
# def initialize()
|
45
|
+
# end
|
46
|
+
|
47
|
+
# `keys` contains each key from `.load(key)`.
|
48
|
+
# Find the corresponding values, then
|
49
|
+
# call `fulfill(key, value)` or `fulfill(key, nil)`
|
50
|
+
# for each key.
|
51
|
+
def perform(keys)
|
52
|
+
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
RUBY
|
@@ -20,27 +20,32 @@ class GraphQLGeneratorsMutationGeneratorTest < BaseGeneratorTest
|
|
20
20
|
end
|
21
21
|
|
22
22
|
UPDATE_NAME_MUTATION = <<-RUBY
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
module Mutations
|
24
|
+
class UpdateName < GraphQL::Schema::RelayClassicMutation
|
25
|
+
# TODO: define return fields
|
26
|
+
# field :post, Types::PostType, null: false
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
# TODO: define arguments
|
29
|
+
# argument :name, String, required: true
|
29
30
|
|
30
|
-
def resolve(**inputs)
|
31
31
|
# TODO: define resolve method
|
32
|
+
# def resolve(name:)
|
33
|
+
# { post: ... }
|
34
|
+
# end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
RUBY
|
35
38
|
|
36
39
|
EXPECTED_MUTATION_TYPE = <<-RUBY
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
module Types
|
41
|
+
class MutationType < Types::BaseObject
|
42
|
+
field :updateName, mutation: Mutations::UpdateName
|
43
|
+
# TODO: remove me
|
44
|
+
field :test_field, String, null: false,
|
45
|
+
description: "An example field added by the generator"
|
46
|
+
def test_field
|
47
|
+
"Hello World"
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
RUBY
|
@@ -16,9 +16,11 @@ class GraphQLGeneratorsObjectGeneratorTest < BaseGeneratorTest
|
|
16
16
|
]
|
17
17
|
|
18
18
|
expected_content = <<-RUBY
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
module Types
|
20
|
+
class BirdType < Types::BaseObject
|
21
|
+
field :wingspan, Integer, null: false
|
22
|
+
field :foliage, [Types::ColorType], null: true
|
23
|
+
end
|
22
24
|
end
|
23
25
|
RUBY
|
24
26
|
|
@@ -32,7 +34,9 @@ RUBY
|
|
32
34
|
test "it generates classifed file" do
|
33
35
|
run_generator(["page"])
|
34
36
|
assert_file "app/graphql/types/page_type.rb", <<-RUBY
|
35
|
-
|
37
|
+
module Types
|
38
|
+
class PageType < Types::BaseObject
|
39
|
+
end
|
36
40
|
end
|
37
41
|
RUBY
|
38
42
|
end
|
@@ -40,8 +44,10 @@ RUBY
|
|
40
44
|
test "it makes Relay nodes" do
|
41
45
|
run_generator(["Page", "--node"])
|
42
46
|
assert_file "app/graphql/types/page_type.rb", <<-RUBY
|
43
|
-
|
44
|
-
|
47
|
+
module Types
|
48
|
+
class PageType < Types::BaseObject
|
49
|
+
implements GraphQL::Relay::Node.interface
|
50
|
+
end
|
45
51
|
end
|
46
52
|
RUBY
|
47
53
|
end
|
@@ -14,8 +14,10 @@ class GraphQLGeneratorsUnionGeneratorTest < BaseGeneratorTest
|
|
14
14
|
]
|
15
15
|
|
16
16
|
expected_content = <<-RUBY
|
17
|
-
|
18
|
-
|
17
|
+
module Types
|
18
|
+
class WingedCreatureType < Types::BaseUnion
|
19
|
+
possible_types [Types::InsectType, Types::BirdType]
|
20
|
+
end
|
19
21
|
end
|
20
22
|
RUBY
|
21
23
|
|
@@ -35,7 +37,9 @@ RUBY
|
|
35
37
|
]
|
36
38
|
|
37
39
|
expected_content = <<-RUBY
|
38
|
-
|
40
|
+
module Types
|
41
|
+
class WingedCreatureType < Types::BaseUnion
|
42
|
+
end
|
39
43
|
end
|
40
44
|
RUBY
|
41
45
|
|
@@ -50,7 +54,9 @@ RUBY
|
|
50
54
|
command = ["WingedCreature", "--directory", "app/mydirectory"]
|
51
55
|
|
52
56
|
expected_content = <<-RUBY
|
53
|
-
|
57
|
+
module Types
|
58
|
+
class WingedCreatureType < Types::BaseUnion
|
59
|
+
end
|
54
60
|
end
|
55
61
|
RUBY
|
56
62
|
|
@@ -272,18 +272,27 @@ describe GraphQL::Authorization do
|
|
272
272
|
field :hidden_interface, HiddenInterface, null: false, method: :itself
|
273
273
|
field :hidden_default_interface, HiddenDefaultInterface, null: false, method: :itself
|
274
274
|
field :hidden_connection, RelayObject.connection_type, null: :false, method: :empty_array
|
275
|
-
field :hidden_edge, RelayObject.edge_type, null: :false, method: :
|
275
|
+
field :hidden_edge, RelayObject.edge_type, null: :false, method: :edge_object
|
276
276
|
|
277
277
|
field :inaccessible, Integer, null: false, method: :object_id
|
278
278
|
field :inaccessible_object, InaccessibleObject, null: false, method: :itself
|
279
279
|
field :inaccessible_interface, InaccessibleInterface, null: false, method: :itself
|
280
280
|
field :inaccessible_default_interface, InaccessibleDefaultInterface, null: false, method: :itself
|
281
281
|
field :inaccessible_connection, RelayObject.connection_type, null: :false, method: :empty_array
|
282
|
-
field :inaccessible_edge, RelayObject.edge_type, null: :false, method: :
|
282
|
+
field :inaccessible_edge, RelayObject.edge_type, null: :false, method: :edge_object
|
283
283
|
|
284
284
|
field :unauthorized_object, UnauthorizedObject, null: true, method: :itself
|
285
|
-
field :unauthorized_connection, RelayObject.connection_type, null:
|
286
|
-
field :unauthorized_edge, RelayObject.edge_type, null:
|
285
|
+
field :unauthorized_connection, RelayObject.connection_type, null: false, method: :array_with_item
|
286
|
+
field :unauthorized_edge, RelayObject.edge_type, null: false, method: :edge_object
|
287
|
+
|
288
|
+
def edge_object
|
289
|
+
OpenStruct.new(node: 100)
|
290
|
+
end
|
291
|
+
|
292
|
+
def array_with_item
|
293
|
+
[1]
|
294
|
+
end
|
295
|
+
|
287
296
|
field :unauthorized_lazy_box, UnauthorizedBox, null: true do
|
288
297
|
argument :value, String, required: true
|
289
298
|
end
|
@@ -623,24 +632,56 @@ describe GraphQL::Authorization do
|
|
623
632
|
end
|
624
633
|
|
625
634
|
it "works with edges and connections" do
|
626
|
-
skip <<-MSG
|
627
|
-
This doesn't work because edge and connection type definitions
|
628
|
-
aren't class-based, and authorization is checked during class-based field execution.
|
629
|
-
MSG
|
630
635
|
query = <<-GRAPHQL
|
631
636
|
{
|
632
|
-
unauthorizedConnection {
|
633
|
-
|
637
|
+
unauthorizedConnection {
|
638
|
+
__typename
|
639
|
+
edges {
|
640
|
+
__typename
|
641
|
+
node {
|
642
|
+
__typename
|
643
|
+
}
|
644
|
+
}
|
645
|
+
nodes {
|
646
|
+
__typename
|
647
|
+
}
|
648
|
+
}
|
649
|
+
unauthorizedEdge {
|
650
|
+
__typename
|
651
|
+
node {
|
652
|
+
__typename
|
653
|
+
}
|
654
|
+
}
|
634
655
|
}
|
635
656
|
GRAPHQL
|
636
657
|
|
637
658
|
unauthorized_res = auth_execute(query, context: { unauthorized_relay: true })
|
638
|
-
|
639
|
-
|
659
|
+
conn = unauthorized_res["data"].fetch("unauthorizedConnection")
|
660
|
+
assert_equal "RelayObjectConnection", conn.fetch("__typename")
|
661
|
+
assert_equal nil, conn.fetch("nodes")
|
662
|
+
assert_equal [{"node" => nil, "__typename" => "RelayObjectEdge"}], conn.fetch("edges")
|
663
|
+
|
664
|
+
edge = unauthorized_res["data"].fetch("unauthorizedEdge")
|
665
|
+
assert_nil edge.fetch("node")
|
666
|
+
assert_equal "RelayObjectEdge", edge["__typename"]
|
667
|
+
|
668
|
+
unauthorized_object_paths = [
|
669
|
+
["unauthorizedConnection", "edges", 0, "node"],
|
670
|
+
["unauthorizedConnection", "nodes"],
|
671
|
+
["unauthorizedEdge", "node"]
|
672
|
+
]
|
673
|
+
|
674
|
+
assert_equal unauthorized_object_paths, unauthorized_res["errors"].map { |e| e["path"] }
|
640
675
|
|
641
676
|
authorized_res = auth_execute(query)
|
642
|
-
|
643
|
-
|
677
|
+
conn = authorized_res["data"].fetch("unauthorizedConnection")
|
678
|
+
assert_equal "RelayObjectConnection", conn.fetch("__typename")
|
679
|
+
assert_equal [{"__typename"=>"RelayObject"}], conn.fetch("nodes")
|
680
|
+
assert_equal [{"node" => {"__typename" => "RelayObject"}, "__typename" => "RelayObjectEdge"}], conn.fetch("edges")
|
681
|
+
|
682
|
+
edge = authorized_res["data"].fetch("unauthorizedEdge")
|
683
|
+
assert_equal "RelayObject", edge.fetch("node").fetch("__typename")
|
684
|
+
assert_equal "RelayObjectEdge", edge["__typename"]
|
644
685
|
end
|
645
686
|
|
646
687
|
it "authorizes _after_ resolving lazy objects" do
|
@@ -254,6 +254,10 @@ describe GraphQL::InputObjectType do
|
|
254
254
|
c: String = "Default"
|
255
255
|
d: Boolean = false
|
256
256
|
}
|
257
|
+
|
258
|
+
input SecondLevelInputObject {
|
259
|
+
example: ExampleInputObject = {b: 42, d: true}
|
260
|
+
}
|
257
261
|
|) }
|
258
262
|
let(:input_type) { schema.types['ExampleInputObject'] }
|
259
263
|
|
@@ -295,6 +299,13 @@ describe GraphQL::InputObjectType do
|
|
295
299
|
|
296
300
|
assert_equal false, result['d']
|
297
301
|
end
|
302
|
+
|
303
|
+
it "merges defaults of nested input objects" do
|
304
|
+
result = schema.types['SecondLevelInputObject'].coerce_isolated_input({})
|
305
|
+
assert_equal 42, result['example']['b']
|
306
|
+
assert_equal "Default", result['example']['c']
|
307
|
+
assert_equal true, result['example']['d']
|
308
|
+
end
|
298
309
|
end
|
299
310
|
|
300
311
|
describe "when sent into a query" do
|
@@ -7,11 +7,13 @@ describe GraphQL::Language::Generation do
|
|
7
7
|
GraphQL.parse('type Query { a: String! }')
|
8
8
|
}
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
let(:custom_printer_class) {
|
11
|
+
Class.new(GraphQL::Language::Printer) {
|
12
|
+
def print_field_definition(print_field_definition)
|
13
|
+
"<Field Hidden>"
|
14
|
+
end
|
15
|
+
}
|
16
|
+
}
|
15
17
|
|
16
18
|
it "accepts a custom printer" do
|
17
19
|
expected = <<-SCHEMA
|
@@ -30,7 +32,7 @@ type Query {
|
|
30
32
|
}
|
31
33
|
SCHEMA
|
32
34
|
|
33
|
-
assert_equal expected.chomp, GraphQL::Language::Generation.generate(document, printer:
|
35
|
+
assert_equal expected.chomp, GraphQL::Language::Generation.generate(document, printer: custom_printer_class.new)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -27,11 +27,13 @@ describe GraphQL::Language::Nodes::AbstractNode do
|
|
27
27
|
GraphQL.parse('type Query { a: String! }')
|
28
28
|
}
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
let(:custom_printer_class) {
|
31
|
+
Class.new(GraphQL::Language::Printer) {
|
32
|
+
def print_field_definition(print_field_definition)
|
33
|
+
"<Field Hidden>"
|
34
|
+
end
|
35
|
+
}
|
36
|
+
}
|
35
37
|
|
36
38
|
it "accepts a custom printer" do
|
37
39
|
expected = <<-SCHEMA
|
@@ -39,7 +41,7 @@ type Query {
|
|
39
41
|
<Field Hidden>
|
40
42
|
}
|
41
43
|
SCHEMA
|
42
|
-
assert_equal expected.chomp, document.to_query_string(printer:
|
44
|
+
assert_equal expected.chomp, document.to_query_string(printer: custom_printer_class.new)
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|