graphql 1.8.0.pre2 → 1.8.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -1
- data/lib/graphql/deprecated_dsl.rb +2 -0
- data/lib/graphql/enum_type.rb +1 -1
- data/lib/graphql/field.rb +10 -1
- data/lib/graphql/input_object_type.rb +3 -1
- data/lib/graphql/introspection.rb +3 -10
- data/lib/graphql/introspection/base_object.rb +15 -0
- data/lib/graphql/introspection/directive_location_enum.rb +11 -7
- data/lib/graphql/introspection/directive_type.rb +23 -16
- data/lib/graphql/introspection/dynamic_fields.rb +11 -0
- data/lib/graphql/introspection/entry_points.rb +29 -0
- data/lib/graphql/introspection/enum_value_type.rb +16 -11
- data/lib/graphql/introspection/field_type.rb +21 -12
- data/lib/graphql/introspection/input_value_type.rb +26 -23
- data/lib/graphql/introspection/schema_field.rb +7 -2
- data/lib/graphql/introspection/schema_type.rb +36 -22
- data/lib/graphql/introspection/type_by_name_field.rb +10 -2
- data/lib/graphql/introspection/type_kind_enum.rb +10 -6
- data/lib/graphql/introspection/type_type.rb +85 -23
- data/lib/graphql/introspection/typename_field.rb +1 -0
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/document_from_schema_definition.rb +129 -37
- data/lib/graphql/language/generation.rb +3 -182
- data/lib/graphql/language/nodes.rb +12 -2
- data/lib/graphql/language/parser.rb +63 -55
- data/lib/graphql/language/parser.y +2 -1
- data/lib/graphql/language/printer.rb +351 -0
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/query/arguments.rb +24 -8
- data/lib/graphql/query/context.rb +3 -0
- data/lib/graphql/query/literal_input.rb +4 -1
- data/lib/graphql/railtie.rb +28 -6
- data/lib/graphql/schema.rb +42 -7
- data/lib/graphql/schema/enum.rb +1 -0
- data/lib/graphql/schema/field.rb +26 -5
- data/lib/graphql/schema/field/dynamic_resolve.rb +18 -9
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/introspection_system.rb +93 -0
- data/lib/graphql/schema/late_bound_type.rb +32 -0
- data/lib/graphql/schema/member.rb +21 -1
- data/lib/graphql/schema/member/build_type.rb +8 -6
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/instrumentation.rb +3 -1
- data/lib/graphql/schema/member/list_type_proxy.rb +4 -0
- data/lib/graphql/schema/member/non_null_type_proxy.rb +4 -0
- data/lib/graphql/schema/object.rb +2 -1
- data/lib/graphql/schema/printer.rb +33 -266
- data/lib/graphql/schema/traversal.rb +74 -6
- data/lib/graphql/schema/validation.rb +3 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
- data/lib/graphql/tracing/scout_tracing.rb +2 -2
- data/lib/graphql/upgrader/member.rb +463 -63
- data/lib/graphql/version.rb +1 -1
- data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
- data/spec/fixtures/upgrader/blame_range.transformed.rb +31 -0
- data/spec/fixtures/upgrader/subscribable.original.rb +51 -0
- data/spec/fixtures/upgrader/subscribable.transformed.rb +46 -0
- data/spec/fixtures/upgrader/type_x.original.rb +35 -0
- data/spec/fixtures/upgrader/type_x.transformed.rb +35 -0
- data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
- data/spec/graphql/language/generation_spec.rb +21 -186
- data/spec/graphql/language/nodes_spec.rb +21 -0
- data/spec/graphql/language/printer_spec.rb +203 -0
- data/spec/graphql/query/arguments_spec.rb +14 -4
- data/spec/graphql/query/context_spec.rb +17 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
- data/spec/graphql/schema/field_spec.rb +14 -0
- data/spec/graphql/schema/introspection_system_spec.rb +39 -0
- data/spec/graphql/schema/object_spec.rb +12 -1
- data/spec/graphql/schema/printer_spec.rb +14 -14
- data/spec/graphql/tracing/platform_tracing_spec.rb +2 -2
- data/spec/graphql/upgrader/member_spec.rb +274 -62
- data/spec/support/jazz.rb +75 -3
- metadata +38 -9
- data/lib/graphql/introspection/arguments_field.rb +0 -7
- data/lib/graphql/introspection/enum_values_field.rb +0 -18
- data/lib/graphql/introspection/fields_field.rb +0 -13
- data/lib/graphql/introspection/input_fields_field.rb +0 -12
- data/lib/graphql/introspection/interfaces_field.rb +0 -11
- data/lib/graphql/introspection/of_type_field.rb +0 -6
- data/lib/graphql/introspection/possible_types_field.rb +0 -11
@@ -19,7 +19,7 @@ describe GraphQL::Query::Arguments do
|
|
19
19
|
GraphQL::Query::Arguments.construct_arguments_class(test_input_1)
|
20
20
|
GraphQL::Query::Arguments.construct_arguments_class(test_input_2)
|
21
21
|
arg_values = {a: 1, b: 2, c: { d: 3, e: 4 }}
|
22
|
-
test_input_2.arguments_class.new(arg_values, context: nil)
|
22
|
+
test_input_2.arguments_class.new(arg_values, context: nil, defaults_used: Set.new)
|
23
23
|
}
|
24
24
|
|
25
25
|
it "returns keys as strings, with aliases" do
|
@@ -73,7 +73,7 @@ describe GraphQL::Query::Arguments do
|
|
73
73
|
self.argument_definitions = types
|
74
74
|
end
|
75
75
|
|
76
|
-
new_arguments = args_class.new(transformed_args, context: nil)
|
76
|
+
new_arguments = args_class.new(transformed_args, context: nil, defaults_used: Set.new)
|
77
77
|
expected_hash = {
|
78
78
|
"A" => 1,
|
79
79
|
"B" => 2,
|
@@ -96,7 +96,8 @@ describe GraphQL::Query::Arguments do
|
|
96
96
|
it "wraps input objects, but not other hashes" do
|
97
97
|
args = input_type.arguments_class.new(
|
98
98
|
{a: 1, b: {a: 2}, c: {a: 3}},
|
99
|
-
|
99
|
+
defaults_used: Set.new,
|
100
|
+
context: nil,
|
100
101
|
)
|
101
102
|
assert_kind_of GraphQL::Query::Arguments, args["b"]
|
102
103
|
assert_instance_of Hash, args["c"]
|
@@ -198,6 +199,15 @@ describe GraphQL::Query::Arguments do
|
|
198
199
|
assert_equal({"a" => 1, "b" => 2}, last_args.to_h)
|
199
200
|
end
|
200
201
|
|
202
|
+
it "indicates when default argument values were applied" do
|
203
|
+
schema.execute("{ argTest(a: 1) }")
|
204
|
+
|
205
|
+
last_args = arg_values.last
|
206
|
+
|
207
|
+
assert_equal false, last_args.default_used?('a')
|
208
|
+
assert_equal true, last_args.default_used?('b')
|
209
|
+
end
|
210
|
+
|
201
211
|
it "works from variables" do
|
202
212
|
variables = { "arg" => { "a" => 1, "d" => nil } }
|
203
213
|
schema.execute("query ArgTest($arg: TestInput){ argTest(d: $arg) }", variables: variables)
|
@@ -306,7 +316,7 @@ describe GraphQL::Query::Arguments do
|
|
306
316
|
assert_nil input_object.arguments_class
|
307
317
|
|
308
318
|
GraphQL::Query::Arguments.construct_arguments_class(input_object)
|
309
|
-
args = input_object.arguments_class.new({foo: 3, bar: -90}, context: nil)
|
319
|
+
args = input_object.arguments_class.new({foo: 3, bar: -90}, defaults_used: Set.new, context: nil)
|
310
320
|
|
311
321
|
assert_equal 3, args.foo
|
312
322
|
assert_equal -90, args.bar
|
@@ -243,4 +243,21 @@ TABLE
|
|
243
243
|
assert_equal [expected_err], result["errors"]
|
244
244
|
end
|
245
245
|
end
|
246
|
+
|
247
|
+
describe "custom context class" do
|
248
|
+
it "can be specified" do
|
249
|
+
query_str = '{
|
250
|
+
inspectContext
|
251
|
+
find(id: "Musician/Herbie Hancock") {
|
252
|
+
... on Musician {
|
253
|
+
inspectContext
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}'
|
257
|
+
res = Jazz::Schema.execute(query_str, context: { magic_key: :ignored, normal_key: "normal_value" })
|
258
|
+
expected_values = ["custom_method", "magic_value", "normal_value"]
|
259
|
+
assert_equal expected_values, res["data"]["inspectContext"]
|
260
|
+
assert_equal expected_values, res["data"]["find"]["inspectContext"]
|
261
|
+
end
|
262
|
+
end
|
246
263
|
end
|
@@ -308,7 +308,7 @@ schema {
|
|
308
308
|
}
|
309
309
|
|
310
310
|
type Hello {
|
311
|
-
str(
|
311
|
+
str(bool: Boolean, int: Int): String
|
312
312
|
}
|
313
313
|
SCHEMA
|
314
314
|
|
@@ -505,7 +505,7 @@ type HelloScalars {
|
|
505
505
|
}
|
506
506
|
|
507
507
|
type Mutation {
|
508
|
-
addHelloScalars(
|
508
|
+
addHelloScalars(bool: Boolean, int: Int, str: String): HelloScalars
|
509
509
|
}
|
510
510
|
SCHEMA
|
511
511
|
|
@@ -520,7 +520,7 @@ enum Color {
|
|
520
520
|
}
|
521
521
|
|
522
522
|
type Mutation {
|
523
|
-
hello(
|
523
|
+
hello(color: Color = RED, int: Int, nullDefault: Int = null, str: String): String
|
524
524
|
}
|
525
525
|
|
526
526
|
type Query {
|
@@ -545,7 +545,7 @@ type HelloScalars {
|
|
545
545
|
}
|
546
546
|
|
547
547
|
type Subscription {
|
548
|
-
subscribeHelloScalars(
|
548
|
+
subscribeHelloScalars(bool: Boolean, int: Int, str: String): HelloScalars
|
549
549
|
}
|
550
550
|
SCHEMA
|
551
551
|
|
@@ -603,6 +603,15 @@ type Query {
|
|
603
603
|
|
604
604
|
build_schema_and_compare_output(schema.chop)
|
605
605
|
end
|
606
|
+
|
607
|
+
it 'supports empty types' do
|
608
|
+
schema = <<-SCHEMA
|
609
|
+
type Query {
|
610
|
+
}
|
611
|
+
SCHEMA
|
612
|
+
|
613
|
+
build_schema_and_compare_output(schema.chop)
|
614
|
+
end
|
606
615
|
end
|
607
616
|
|
608
617
|
describe 'Failures' do
|
@@ -14,5 +14,19 @@ describe GraphQL::Schema::Field do
|
|
14
14
|
it "camelizes the field name" do
|
15
15
|
assert_equal 'inspectInput', field.graphql_definition.name
|
16
16
|
end
|
17
|
+
|
18
|
+
describe "description in block" do
|
19
|
+
it "will raise if description is defined both in the argument and in the block" do
|
20
|
+
assert_raises RuntimeError, "You're overriding the description of shouldRaise in the provided block!" do
|
21
|
+
Class.new(Jazz::BaseObject) do
|
22
|
+
graphql_name "JustAName"
|
23
|
+
|
24
|
+
field :should_raise, Jazz::Key, "this should not raise", null: true do
|
25
|
+
description "This should raise"
|
26
|
+
end
|
27
|
+
end.to_graphql
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
17
31
|
end
|
18
32
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::Schema::IntrospectionSystem do
|
5
|
+
describe "custom introspection" do
|
6
|
+
it "serves custom fields on types" do
|
7
|
+
res = Jazz::Schema.execute("{ __schema { isJazzy } }")
|
8
|
+
assert_equal true, res["data"]["__schema"]["isJazzy"]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "serves overridden fields on types" do
|
12
|
+
res = Jazz::Schema.execute(%|{ __type(name: "Ensemble") { name } }|)
|
13
|
+
assert_equal "ENSEMBLE", res["data"]["__type"]["name"]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "serves custom entry points" do
|
17
|
+
res = Jazz::Schema.execute("{ __classname }", root_value: Set.new)
|
18
|
+
assert_equal "Set", res["data"]["__classname"]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "serves custom dynamic fields" do
|
22
|
+
res = Jazz::Schema.execute("{ nowPlaying { __typename __typenameLength __astNodeClass } }")
|
23
|
+
assert_equal "Ensemble", res["data"]["nowPlaying"]["__typename"]
|
24
|
+
assert_equal 8, res["data"]["nowPlaying"]["__typenameLength"]
|
25
|
+
assert_equal "GraphQL::Language::Nodes::Field", res["data"]["nowPlaying"]["__astNodeClass"]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "doesn't affect other schemas" do
|
29
|
+
res = Dummy::Schema.execute("{ __schema { isJazzy } }")
|
30
|
+
assert_equal 1, res["errors"].length
|
31
|
+
|
32
|
+
res = Dummy::Schema.execute("{ __classname }", root_value: Set.new)
|
33
|
+
assert_equal 1, res["errors"].length
|
34
|
+
|
35
|
+
res = Dummy::Schema.execute("{ ensembles { __typenameLength } }")
|
36
|
+
assert_equal 1, res["errors"].length
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -16,7 +16,7 @@ describe GraphQL::Schema::Object do
|
|
16
16
|
it "inherits fields and interfaces" do
|
17
17
|
new_object_class = Class.new(object_class) do
|
18
18
|
field :newField, String, null: true
|
19
|
-
field :name, String, "The new description", null: true
|
19
|
+
field :name, String, description: "The new description", null: true
|
20
20
|
end
|
21
21
|
|
22
22
|
# one more than the parent class
|
@@ -29,6 +29,17 @@ describe GraphQL::Schema::Object do
|
|
29
29
|
name_field = new_object_class.fields.find { |f| f.name == "name" }
|
30
30
|
assert_equal "The new description", name_field.description
|
31
31
|
end
|
32
|
+
|
33
|
+
it "inherits name and description" do
|
34
|
+
# Manually assign a name since `.name` isn't populated for dynamic classes
|
35
|
+
new_subclass_1 = Class.new(object_class) do
|
36
|
+
graphql_name "NewSubclass"
|
37
|
+
end
|
38
|
+
new_subclass_2 = Class.new(new_subclass_1)
|
39
|
+
assert_equal "NewSubclass", new_subclass_1.graphql_name
|
40
|
+
assert_equal "NewSubclass", new_subclass_2.graphql_name
|
41
|
+
assert_equal object_class.description, new_subclass_2.description
|
42
|
+
end
|
32
43
|
end
|
33
44
|
|
34
45
|
describe ".to_graphql_type" do
|
@@ -136,6 +136,14 @@ schema {
|
|
136
136
|
query: Root
|
137
137
|
}
|
138
138
|
|
139
|
+
# Marks an element of a GraphQL schema as no longer supported.
|
140
|
+
directive @deprecated(
|
141
|
+
# Explains why this element was deprecated, usually also including a suggestion
|
142
|
+
# for how to access supported similar data. Formatted in
|
143
|
+
# [Markdown](https://daringfireball.net/projects/markdown/).
|
144
|
+
reason: String = "No longer supported"
|
145
|
+
) on FIELD_DEFINITION | ENUM_VALUE
|
146
|
+
|
139
147
|
# Directs the executor to include this field or fragment only when the `if` argument is true.
|
140
148
|
directive @include(
|
141
149
|
# Included when true.
|
@@ -148,14 +156,6 @@ directive @skip(
|
|
148
156
|
if: Boolean!
|
149
157
|
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
150
158
|
|
151
|
-
# Marks an element of a GraphQL schema as no longer supported.
|
152
|
-
directive @deprecated(
|
153
|
-
# Explains why this element was deprecated, usually also including a suggestion
|
154
|
-
# for how to access supported similar data. Formatted in
|
155
|
-
# [Markdown](https://daringfireball.net/projects/markdown/).
|
156
|
-
reason: String = "No longer supported"
|
157
|
-
) on FIELD_DEFINITION | ENUM_VALUE
|
158
|
-
|
159
159
|
# A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
|
160
160
|
#
|
161
161
|
# In some cases, you need to provide options to alter GraphQL's execution behavior
|
@@ -345,7 +345,6 @@ schema {
|
|
345
345
|
subscription: Subscription
|
346
346
|
}
|
347
347
|
SCHEMA
|
348
|
-
|
349
348
|
assert_match expected, GraphQL::Schema::Printer.print_schema(custom_schema)
|
350
349
|
end
|
351
350
|
|
@@ -390,7 +389,7 @@ type Audio {
|
|
390
389
|
|
391
390
|
enum Choice {
|
392
391
|
BAR
|
393
|
-
BAZ @deprecated(reason: "Use
|
392
|
+
BAZ @deprecated(reason: "Use "BAR".")
|
394
393
|
FOO
|
395
394
|
WOZ @deprecated
|
396
395
|
}
|
@@ -439,7 +438,7 @@ interface Node {
|
|
439
438
|
type Post {
|
440
439
|
body: String!
|
441
440
|
comments: [Comment!]
|
442
|
-
comments_count: Int! @deprecated(reason: "Use
|
441
|
+
comments_count: Int! @deprecated(reason: "Use "comments".")
|
443
442
|
id: ID!
|
444
443
|
title: String!
|
445
444
|
}
|
@@ -489,7 +488,6 @@ enum Choice {
|
|
489
488
|
}
|
490
489
|
|
491
490
|
type Subscription {
|
492
|
-
|
493
491
|
}
|
494
492
|
|
495
493
|
input Varied {
|
@@ -509,7 +507,9 @@ SCHEMA
|
|
509
507
|
when GraphQL::Argument
|
510
508
|
member.name != "id"
|
511
509
|
else
|
512
|
-
member.deprecation_reason
|
510
|
+
if member.respond_to?(:deprecation_reason)
|
511
|
+
member.deprecation_reason.nil?
|
512
|
+
end
|
513
513
|
end
|
514
514
|
}
|
515
515
|
|
@@ -600,7 +600,7 @@ SCHEMA
|
|
600
600
|
type Post {
|
601
601
|
body: String!
|
602
602
|
comments: [Comment!]
|
603
|
-
comments_count: Int! @deprecated(reason:
|
603
|
+
comments_count: Int! @deprecated(reason: "Use "comments".")
|
604
604
|
id: ID!
|
605
605
|
title: String!
|
606
606
|
}
|
@@ -69,10 +69,10 @@ describe GraphQL::Tracing::PlatformTracing do
|
|
69
69
|
schema.execute(" { tracingScalar { traceNil traceFalse traceTrue } }")
|
70
70
|
expected_trace = [
|
71
71
|
"em",
|
72
|
-
"am",
|
73
72
|
"l",
|
74
73
|
"p",
|
75
74
|
"v",
|
75
|
+
"am",
|
76
76
|
"aq",
|
77
77
|
"eq",
|
78
78
|
"Q.t",
|
@@ -98,10 +98,10 @@ describe GraphQL::Tracing::PlatformTracing do
|
|
98
98
|
schema.execute(" { tracingScalar { traceNil traceFalse traceTrue } }")
|
99
99
|
expected_trace = [
|
100
100
|
"em",
|
101
|
-
"am",
|
102
101
|
"l",
|
103
102
|
"p",
|
104
103
|
"v",
|
104
|
+
"am",
|
105
105
|
"aq",
|
106
106
|
"eq",
|
107
107
|
"Q.t",
|
@@ -11,17 +11,23 @@ describe GraphQL::Upgrader::Member do
|
|
11
11
|
describe 'field arguments' do
|
12
12
|
it 'upgrades' do
|
13
13
|
old = %{argument :status, !TodoStatus, "Restrict items to this status"}
|
14
|
-
new = %{argument :status, TodoStatus, "Restrict items to this status",
|
14
|
+
new = %{argument :status, TodoStatus, "Restrict items to this status", required: true}
|
15
15
|
|
16
|
-
assert_equal upgrade(old)
|
16
|
+
assert_equal new, upgrade(old)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'upgrades the property definition to method' do
|
21
21
|
old = %{field :name, String, property: :name}
|
22
|
-
new = %{field :name, String, method: :name, null:
|
22
|
+
new = %{field :name, String, method: :name, null: true}
|
23
23
|
|
24
|
-
assert_equal upgrade(old)
|
24
|
+
assert_equal new, upgrade(old)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'upgrades the property definition in a block to method' do
|
28
|
+
old = %{field :name, String do\n property :name\nend}
|
29
|
+
new = %{field :name, String, method: :name, null: true}
|
30
|
+
assert_equal new, upgrade(old)
|
25
31
|
end
|
26
32
|
|
27
33
|
describe 'name' do
|
@@ -32,10 +38,23 @@ describe GraphQL::Upgrader::Member do
|
|
32
38
|
end
|
33
39
|
}
|
34
40
|
new = %{
|
35
|
-
class UserType < BaseObject
|
41
|
+
class UserType < Types::BaseObject
|
42
|
+
end
|
43
|
+
}
|
44
|
+
assert_equal new, upgrade(old)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'removes the name field if it can be inferred from the class and under a module' do
|
48
|
+
old = %{
|
49
|
+
Types::UserType = GraphQL::ObjectType.define do
|
50
|
+
name "User"
|
51
|
+
end
|
52
|
+
}
|
53
|
+
new = %{
|
54
|
+
class Types::UserType < Types::BaseObject
|
36
55
|
end
|
37
56
|
}
|
38
|
-
assert_equal upgrade(old)
|
57
|
+
assert_equal new, upgrade(old)
|
39
58
|
end
|
40
59
|
|
41
60
|
it 'upgrades the name into graphql_name if it can\'t be inferred from the class' do
|
@@ -45,11 +64,11 @@ describe GraphQL::Upgrader::Member do
|
|
45
64
|
end
|
46
65
|
}
|
47
66
|
new = %{
|
48
|
-
class TeamType < BaseObject
|
67
|
+
class TeamType < Types::BaseObject
|
49
68
|
graphql_name "User"
|
50
69
|
end
|
51
70
|
}
|
52
|
-
assert_equal upgrade(old)
|
71
|
+
assert_equal new, upgrade(old)
|
53
72
|
|
54
73
|
old = %{
|
55
74
|
UserInterface = GraphQL::InterfaceType.define do
|
@@ -57,111 +76,211 @@ describe GraphQL::Upgrader::Member do
|
|
57
76
|
end
|
58
77
|
}
|
59
78
|
new = %{
|
60
|
-
class UserInterface < BaseInterface
|
79
|
+
class UserInterface < Types::BaseInterface
|
61
80
|
graphql_name "User"
|
62
81
|
end
|
63
82
|
}
|
64
|
-
assert_equal upgrade(old)
|
83
|
+
assert_equal new, upgrade(old)
|
65
84
|
|
66
85
|
old = %{
|
67
|
-
|
86
|
+
UserEnum = GraphQL::EnumType.define do
|
68
87
|
name "User"
|
69
88
|
end
|
70
89
|
}
|
71
90
|
new = %{
|
72
|
-
class
|
91
|
+
class UserEnum < Types::BaseEnum
|
73
92
|
graphql_name "User"
|
74
93
|
end
|
75
94
|
}
|
76
|
-
assert_equal upgrade(old)
|
95
|
+
assert_equal new, upgrade(old)
|
77
96
|
end
|
78
97
|
end
|
79
98
|
|
80
99
|
describe 'definition' do
|
81
100
|
it 'upgrades the .define into class based definition' do
|
82
|
-
old = %{UserType = GraphQL::ObjectType.define do
|
83
|
-
|
84
|
-
|
101
|
+
old = %{UserType = GraphQL::ObjectType.define do
|
102
|
+
end}
|
103
|
+
new = %{class UserType < Types::BaseObject
|
104
|
+
end}
|
105
|
+
assert_equal new, upgrade(old)
|
106
|
+
|
107
|
+
old = %{UserInterface = GraphQL::InterfaceType.define do
|
108
|
+
end}
|
109
|
+
new = %{class UserInterface < Types::BaseInterface
|
110
|
+
end}
|
111
|
+
assert_equal new, upgrade(old)
|
112
|
+
|
113
|
+
old = %{UserUnion = GraphQL::UnionType.define do
|
114
|
+
end}
|
115
|
+
new = %{class UserUnion < Types::BaseUnion
|
116
|
+
end}
|
117
|
+
assert_equal new, upgrade(old)
|
85
118
|
|
86
|
-
old = %{
|
87
|
-
|
88
|
-
|
119
|
+
old = %{UserEnum = GraphQL::EnumType.define do
|
120
|
+
end}
|
121
|
+
new = %{class UserEnum < Types::BaseEnum
|
122
|
+
end}
|
123
|
+
assert_equal new, upgrade(old)
|
89
124
|
|
90
|
-
old = %{
|
91
|
-
|
92
|
-
|
125
|
+
old = %{UserInput = GraphQL::InputObjectType.define do
|
126
|
+
end}
|
127
|
+
new = %{class UserInput < Types::BaseInputObject
|
128
|
+
end}
|
129
|
+
assert_equal new, upgrade(old)
|
93
130
|
|
94
|
-
old = %{
|
95
|
-
|
96
|
-
|
131
|
+
old = %{UserScalar = GraphQL::ScalarType.define do
|
132
|
+
end}
|
133
|
+
new = %{class UserScalar < Types::BaseScalar
|
134
|
+
end}
|
135
|
+
assert_equal new, upgrade(old)
|
97
136
|
end
|
98
137
|
|
99
138
|
it 'upgrades including the module' do
|
100
|
-
old = %{Module::UserType = GraphQL::ObjectType.define do
|
101
|
-
|
102
|
-
|
139
|
+
old = %{Module::UserType = GraphQL::ObjectType.define do
|
140
|
+
end}
|
141
|
+
new = %{class Module::UserType < Types::BaseObject
|
142
|
+
end}
|
143
|
+
assert_equal new, upgrade(old)
|
103
144
|
end
|
104
145
|
end
|
105
146
|
|
106
147
|
describe 'fields' do
|
148
|
+
it 'underscorizes field name' do
|
149
|
+
old = %{field :firstName, !types.String}
|
150
|
+
new = %{field :first_name, String, null: false}
|
151
|
+
assert_equal new, upgrade(old)
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "resolve proc to method" do
|
155
|
+
it "converts @object and @context" do
|
156
|
+
old = %{
|
157
|
+
field :firstName, !types.String do
|
158
|
+
resolve ->(obj, arg, ctx) {
|
159
|
+
ctx.something
|
160
|
+
other_ctx # test combined identifiers
|
161
|
+
|
162
|
+
obj[ctx] + obj
|
163
|
+
obj.given_name
|
164
|
+
}
|
165
|
+
end
|
166
|
+
}
|
167
|
+
new = %{
|
168
|
+
field :first_name, String, null: false
|
169
|
+
|
170
|
+
def first_name
|
171
|
+
@context.something
|
172
|
+
other_ctx # test combined identifiers
|
173
|
+
|
174
|
+
@object[@context] + @object
|
175
|
+
@object.given_name
|
176
|
+
end
|
177
|
+
}
|
178
|
+
assert_equal new, upgrade(old)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "handles `_` var names" do
|
182
|
+
old = %{
|
183
|
+
field :firstName, !types.String do
|
184
|
+
resolve ->(obj, _, _) {
|
185
|
+
obj.given_name
|
186
|
+
}
|
187
|
+
end
|
188
|
+
}
|
189
|
+
new = %{
|
190
|
+
field :first_name, String, null: false
|
191
|
+
|
192
|
+
def first_name
|
193
|
+
@object.given_name
|
194
|
+
end
|
195
|
+
}
|
196
|
+
assert_equal new, upgrade(old)
|
197
|
+
end
|
198
|
+
|
199
|
+
it "creates **arguments if necessary" do
|
200
|
+
old = %{
|
201
|
+
field :firstName, !types.String do
|
202
|
+
argument :ctx, types.String, default_value: "abc"
|
203
|
+
resolve ->(obj, args, ctx) {
|
204
|
+
args[:ctx]
|
205
|
+
}
|
206
|
+
end
|
207
|
+
}
|
208
|
+
new = %{
|
209
|
+
field :first_name, String, null: false do
|
210
|
+
argument :ctx, String, default_value: "abc", required: false
|
211
|
+
end
|
212
|
+
|
213
|
+
def first_name(**args)
|
214
|
+
args[:ctx]
|
215
|
+
end
|
216
|
+
}
|
217
|
+
assert_equal new, upgrade(old)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
|
107
222
|
it 'upgrades to the new definition' do
|
108
223
|
old = %{field :name, !types.String}
|
109
224
|
new = %{field :name, String, null: false}
|
110
|
-
assert_equal upgrade(old)
|
225
|
+
assert_equal new, upgrade(old)
|
111
226
|
|
112
227
|
old = %{field :name, !types.String, "description", method: :name}
|
113
228
|
new = %{field :name, String, "description", method: :name, null: false}
|
114
|
-
assert_equal upgrade(old)
|
229
|
+
assert_equal new, upgrade(old)
|
115
230
|
|
116
231
|
old = %{field :name, -> { !types.String }}
|
117
|
-
new = %{field :name,
|
118
|
-
assert_equal upgrade(old)
|
232
|
+
new = %{field :name, String, null: false}
|
233
|
+
assert_equal new, upgrade(old)
|
119
234
|
|
120
235
|
old = %{connection :name, Name.connection_type, "names"}
|
121
|
-
new = %{field :name, Name.connection_type, "names", null:
|
122
|
-
assert_equal upgrade(old)
|
236
|
+
new = %{field :name, Name.connection_type, "names", null: true, connection: true}
|
237
|
+
assert_equal new, upgrade(old)
|
123
238
|
|
124
239
|
old = %{connection :name, !Name.connection_type, "names"}
|
125
240
|
new = %{field :name, Name.connection_type, "names", null: false, connection: true}
|
126
|
-
assert_equal upgrade(old)
|
241
|
+
assert_equal new, upgrade(old)
|
127
242
|
|
128
243
|
old = %{field :names, types[types.String]}
|
129
|
-
new = %{field :names, [String], null:
|
130
|
-
assert_equal upgrade(old)
|
244
|
+
new = %{field :names, [String], null: true}
|
245
|
+
assert_equal new, upgrade(old)
|
131
246
|
|
132
247
|
old = %{field :names, !types[types.String]}
|
133
248
|
new = %{field :names, [String], null: false}
|
134
|
-
assert_equal upgrade(old)
|
249
|
+
assert_equal new, upgrade(old)
|
135
250
|
|
136
251
|
old = %{
|
137
252
|
field :name, types.String do
|
138
253
|
end
|
139
254
|
}
|
140
255
|
new = %{
|
141
|
-
field :name, String, null:
|
142
|
-
end
|
256
|
+
field :name, String, null: true
|
143
257
|
}
|
144
|
-
assert_equal upgrade(old)
|
258
|
+
assert_equal new, upgrade(old)
|
145
259
|
|
146
260
|
old = %{
|
147
261
|
field :name, !types.String do
|
262
|
+
description "abc"
|
263
|
+
end
|
264
|
+
|
265
|
+
field :name2, !types.Int do
|
266
|
+
description "def"
|
148
267
|
end
|
149
268
|
}
|
150
269
|
new = %{
|
151
|
-
field :name, String, null: false
|
152
|
-
|
270
|
+
field :name, String, description: "abc", null: false
|
271
|
+
|
272
|
+
field :name2, Integer, description: "def", null: false
|
153
273
|
}
|
154
|
-
assert_equal upgrade(old)
|
274
|
+
assert_equal new, upgrade(old)
|
155
275
|
|
156
276
|
old = %{
|
157
277
|
field :name, -> { !types.String } do
|
158
278
|
end
|
159
279
|
}
|
160
280
|
new = %{
|
161
|
-
field :name,
|
162
|
-
end
|
281
|
+
field :name, String, null: false
|
163
282
|
}
|
164
|
-
assert_equal upgrade(old)
|
283
|
+
assert_equal new, upgrade(old)
|
165
284
|
|
166
285
|
old = %{
|
167
286
|
field :name do
|
@@ -169,21 +288,25 @@ describe GraphQL::Upgrader::Member do
|
|
169
288
|
end
|
170
289
|
}
|
171
290
|
new = %{
|
172
|
-
field :name,
|
173
|
-
end
|
291
|
+
field :name, String, null: true
|
174
292
|
}
|
175
|
-
assert_equal upgrade(old)
|
293
|
+
assert_equal new, upgrade(old)
|
176
294
|
|
177
295
|
old = %{
|
178
296
|
field :name do
|
179
297
|
type !String
|
180
298
|
end
|
299
|
+
|
300
|
+
field :name2 do
|
301
|
+
type !String
|
302
|
+
end
|
181
303
|
}
|
182
304
|
new = %{
|
183
|
-
field :name, String, null: false
|
184
|
-
|
305
|
+
field :name, String, null: false
|
306
|
+
|
307
|
+
field :name2, String, null: false
|
185
308
|
}
|
186
|
-
assert_equal upgrade(old)
|
309
|
+
assert_equal new, upgrade(old)
|
187
310
|
|
188
311
|
old = %{
|
189
312
|
field :name, -> { types.String },
|
@@ -191,10 +314,9 @@ describe GraphQL::Upgrader::Member do
|
|
191
314
|
end
|
192
315
|
}
|
193
316
|
new = %{
|
194
|
-
field :name,
|
195
|
-
end
|
317
|
+
field :name, String, "newline description", null: true
|
196
318
|
}
|
197
|
-
assert_equal upgrade(old)
|
319
|
+
assert_equal new, upgrade(old)
|
198
320
|
|
199
321
|
old = %{
|
200
322
|
field :name, -> { !types.String },
|
@@ -202,10 +324,9 @@ describe GraphQL::Upgrader::Member do
|
|
202
324
|
end
|
203
325
|
}
|
204
326
|
new = %{
|
205
|
-
field :name,
|
206
|
-
end
|
327
|
+
field :name, String, "newline description", null: false
|
207
328
|
}
|
208
|
-
assert_equal upgrade(old)
|
329
|
+
assert_equal new, upgrade(old)
|
209
330
|
|
210
331
|
old = %{
|
211
332
|
field :name, String,
|
@@ -213,10 +334,101 @@ describe GraphQL::Upgrader::Member do
|
|
213
334
|
end
|
214
335
|
}
|
215
336
|
new = %{
|
216
|
-
field :name, String, field: SomeField, null:
|
217
|
-
|
337
|
+
field :name, String, field: SomeField, null: true
|
338
|
+
}
|
339
|
+
assert_equal new, upgrade(old)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
describe 'multi-line field with property/method' do
|
344
|
+
it 'upgrades without breaking syntax' do
|
345
|
+
old = %{
|
346
|
+
field :is_example_field, types.Boolean,
|
347
|
+
property: :example_field?
|
348
|
+
}
|
349
|
+
new = %{
|
350
|
+
field :is_example_field, Boolean, null: true
|
351
|
+
method: :example_field?
|
352
|
+
}
|
353
|
+
|
354
|
+
assert_equal new, upgrade(old)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
describe 'multi-line connection with property/method' do
|
359
|
+
it 'upgrades without breaking syntax' do
|
360
|
+
old = %{
|
361
|
+
connection :example_connection, -> { ExampleConnectionType },
|
362
|
+
property: :example_connections
|
363
|
+
}
|
364
|
+
new = %{
|
365
|
+
field :example_connection, ExampleConnectionType, null: true, connection: true
|
366
|
+
method: :example_connections
|
367
|
+
}
|
368
|
+
|
369
|
+
assert_equal new, upgrade(old)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
describe 'input_field' do
|
374
|
+
it 'upgrades to argument' do
|
375
|
+
old = %{input_field :id, !types.ID}
|
376
|
+
new = %{argument :id, ID, required: true}
|
377
|
+
assert_equal new, upgrade(old)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
describe 'implements' do
|
382
|
+
it 'upgrades interfaces to implements' do
|
383
|
+
old = %{
|
384
|
+
interfaces [Types::SearchableType, Types::CommentableType]
|
385
|
+
interfaces [Types::ShareableType]
|
386
|
+
}
|
387
|
+
new = %{
|
388
|
+
implements Types::SearchableType
|
389
|
+
implements Types::CommentableType
|
390
|
+
implements Types::ShareableType
|
391
|
+
}
|
392
|
+
assert_equal new, upgrade(old)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
describe "fixtures" do
|
397
|
+
class ActiveRecordTypeToClassTransform < GraphQL::Upgrader::Transform
|
398
|
+
def initialize
|
399
|
+
@find_pattern = /^( +)([a-zA-Z_0-9:]*) = define_active_record_type\(-> ?\{ ?:{0,2}([a-zA-Z_0-9:]*) ?\} ?\) do/
|
400
|
+
@replace_pattern = "\\1class \\2 < Platform::Objects::Base\n\\1 model_name \"\\3\""
|
401
|
+
end
|
402
|
+
|
403
|
+
def apply(input_text)
|
404
|
+
input_text.sub(@find_pattern, @replace_pattern)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def custom_upgrade(original_text)
|
409
|
+
# Replace the default one with a custom one:
|
410
|
+
type_transforms = GraphQL::Upgrader::Member::DEFAULT_TYPE_TRANSFORMS.map { |t|
|
411
|
+
if t == GraphQL::Upgrader::TypeDefineToClassTransform
|
412
|
+
GraphQL::Upgrader::TypeDefineToClassTransform.new(base_class_pattern: "Platform::\\2s::Base")
|
413
|
+
else
|
414
|
+
t
|
415
|
+
end
|
218
416
|
}
|
219
|
-
|
417
|
+
|
418
|
+
type_transforms.unshift(ActiveRecordTypeToClassTransform)
|
419
|
+
upgrader = GraphQL::Upgrader::Member.new(original_text, type_transforms: type_transforms)
|
420
|
+
upgrader.upgrade
|
421
|
+
end
|
422
|
+
|
423
|
+
original_files = Dir.glob("spec/fixtures/upgrader/*.original.rb")
|
424
|
+
original_files.each do |original_file|
|
425
|
+
transformed_file = original_file.sub(".original.", ".transformed.")
|
426
|
+
it "transforms #{original_file} -> #{transformed_file}" do
|
427
|
+
original_text = File.read(original_file)
|
428
|
+
expected_text = File.read(transformed_file)
|
429
|
+
transformed_text = custom_upgrade(original_text)
|
430
|
+
assert_equal(expected_text, transformed_text)
|
431
|
+
end
|
220
432
|
end
|
221
433
|
end
|
222
434
|
end
|