graphql 1.8.0.pre2 → 1.8.0.pre3

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +1 -1
  3. data/lib/graphql/deprecated_dsl.rb +2 -0
  4. data/lib/graphql/enum_type.rb +1 -1
  5. data/lib/graphql/field.rb +10 -1
  6. data/lib/graphql/input_object_type.rb +3 -1
  7. data/lib/graphql/introspection.rb +3 -10
  8. data/lib/graphql/introspection/base_object.rb +15 -0
  9. data/lib/graphql/introspection/directive_location_enum.rb +11 -7
  10. data/lib/graphql/introspection/directive_type.rb +23 -16
  11. data/lib/graphql/introspection/dynamic_fields.rb +11 -0
  12. data/lib/graphql/introspection/entry_points.rb +29 -0
  13. data/lib/graphql/introspection/enum_value_type.rb +16 -11
  14. data/lib/graphql/introspection/field_type.rb +21 -12
  15. data/lib/graphql/introspection/input_value_type.rb +26 -23
  16. data/lib/graphql/introspection/schema_field.rb +7 -2
  17. data/lib/graphql/introspection/schema_type.rb +36 -22
  18. data/lib/graphql/introspection/type_by_name_field.rb +10 -2
  19. data/lib/graphql/introspection/type_kind_enum.rb +10 -6
  20. data/lib/graphql/introspection/type_type.rb +85 -23
  21. data/lib/graphql/introspection/typename_field.rb +1 -0
  22. data/lib/graphql/language.rb +1 -0
  23. data/lib/graphql/language/document_from_schema_definition.rb +129 -37
  24. data/lib/graphql/language/generation.rb +3 -182
  25. data/lib/graphql/language/nodes.rb +12 -2
  26. data/lib/graphql/language/parser.rb +63 -55
  27. data/lib/graphql/language/parser.y +2 -1
  28. data/lib/graphql/language/printer.rb +351 -0
  29. data/lib/graphql/object_type.rb +1 -1
  30. data/lib/graphql/query.rb +1 -1
  31. data/lib/graphql/query/arguments.rb +24 -8
  32. data/lib/graphql/query/context.rb +3 -0
  33. data/lib/graphql/query/literal_input.rb +4 -1
  34. data/lib/graphql/railtie.rb +28 -6
  35. data/lib/graphql/schema.rb +42 -7
  36. data/lib/graphql/schema/enum.rb +1 -0
  37. data/lib/graphql/schema/field.rb +26 -5
  38. data/lib/graphql/schema/field/dynamic_resolve.rb +18 -9
  39. data/lib/graphql/schema/input_object.rb +2 -2
  40. data/lib/graphql/schema/introspection_system.rb +93 -0
  41. data/lib/graphql/schema/late_bound_type.rb +32 -0
  42. data/lib/graphql/schema/member.rb +21 -1
  43. data/lib/graphql/schema/member/build_type.rb +8 -6
  44. data/lib/graphql/schema/member/has_fields.rb +1 -1
  45. data/lib/graphql/schema/member/instrumentation.rb +3 -1
  46. data/lib/graphql/schema/member/list_type_proxy.rb +4 -0
  47. data/lib/graphql/schema/member/non_null_type_proxy.rb +4 -0
  48. data/lib/graphql/schema/object.rb +2 -1
  49. data/lib/graphql/schema/printer.rb +33 -266
  50. data/lib/graphql/schema/traversal.rb +74 -6
  51. data/lib/graphql/schema/validation.rb +3 -2
  52. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
  53. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  54. data/lib/graphql/upgrader/member.rb +463 -63
  55. data/lib/graphql/version.rb +1 -1
  56. data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
  57. data/spec/fixtures/upgrader/blame_range.transformed.rb +31 -0
  58. data/spec/fixtures/upgrader/subscribable.original.rb +51 -0
  59. data/spec/fixtures/upgrader/subscribable.transformed.rb +46 -0
  60. data/spec/fixtures/upgrader/type_x.original.rb +35 -0
  61. data/spec/fixtures/upgrader/type_x.transformed.rb +35 -0
  62. data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
  63. data/spec/graphql/language/generation_spec.rb +21 -186
  64. data/spec/graphql/language/nodes_spec.rb +21 -0
  65. data/spec/graphql/language/printer_spec.rb +203 -0
  66. data/spec/graphql/query/arguments_spec.rb +14 -4
  67. data/spec/graphql/query/context_spec.rb +17 -0
  68. data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
  69. data/spec/graphql/schema/field_spec.rb +14 -0
  70. data/spec/graphql/schema/introspection_system_spec.rb +39 -0
  71. data/spec/graphql/schema/object_spec.rb +12 -1
  72. data/spec/graphql/schema/printer_spec.rb +14 -14
  73. data/spec/graphql/tracing/platform_tracing_spec.rb +2 -2
  74. data/spec/graphql/upgrader/member_spec.rb +274 -62
  75. data/spec/support/jazz.rb +75 -3
  76. metadata +38 -9
  77. data/lib/graphql/introspection/arguments_field.rb +0 -7
  78. data/lib/graphql/introspection/enum_values_field.rb +0 -18
  79. data/lib/graphql/introspection/fields_field.rb +0 -13
  80. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  81. data/lib/graphql/introspection/interfaces_field.rb +0 -11
  82. data/lib/graphql/introspection/of_type_field.rb +0 -6
  83. 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
- context: nil
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(int: Int, bool: Boolean): String
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(str: String, int: Int, bool: Boolean): HelloScalars
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(str: String, int: Int, color: Color = RED, nullDefault: Int = null): String
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(str: String, int: Int, bool: Boolean): HelloScalars
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 \\\"BAR\\\".")
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 \\\"comments\\\".")
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.nil?
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: \"Use \\\"comments\\\".\")
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", null: false}
14
+ new = %{argument :status, TodoStatus, "Restrict items to this status", required: true}
15
15
 
16
- assert_equal upgrade(old), new
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: false}
22
+ new = %{field :name, String, method: :name, null: true}
23
23
 
24
- assert_equal upgrade(old), new
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), new
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), new
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), new
83
+ assert_equal new, upgrade(old)
65
84
 
66
85
  old = %{
67
- UserInterface = GraphQL::InterfaceType.define do
86
+ UserEnum = GraphQL::EnumType.define do
68
87
  name "User"
69
88
  end
70
89
  }
71
90
  new = %{
72
- class UserInterface < BaseInterface
91
+ class UserEnum < Types::BaseEnum
73
92
  graphql_name "User"
74
93
  end
75
94
  }
76
- assert_equal upgrade(old), new
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
- new = %{class UserType < BaseObject}
84
- assert_equal upgrade(old), new
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 = %{UserInterface = GraphQL::InterfaceType.define do}
87
- new = %{class UserInterface < BaseInterface}
88
- assert_equal upgrade(old), new
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 = %{UserUnion = GraphQL::UnionType.define do}
91
- new = %{class UserUnion < BaseUnion}
92
- assert_equal upgrade(old), new
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 = %{UserEnum = GraphQL::EnumType.define do}
95
- new = %{class UserEnum < BaseEnum}
96
- assert_equal upgrade(old), new
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
- new = %{class Module::UserType < BaseObject}
102
- assert_equal upgrade(old), new
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), new
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), new
229
+ assert_equal new, upgrade(old)
115
230
 
116
231
  old = %{field :name, -> { !types.String }}
117
- new = %{field :name, -> { String }, null: false}
118
- assert_equal upgrade(old), new
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: false, connection: true}
122
- assert_equal upgrade(old), new
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), new
241
+ assert_equal new, upgrade(old)
127
242
 
128
243
  old = %{field :names, types[types.String]}
129
- new = %{field :names, [String], null: false}
130
- assert_equal upgrade(old), new
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), new
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: false do
142
- end
256
+ field :name, String, null: true
143
257
  }
144
- assert_equal upgrade(old), new
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 do
152
- end
270
+ field :name, String, description: "abc", null: false
271
+
272
+ field :name2, Integer, description: "def", null: false
153
273
  }
154
- assert_equal upgrade(old), new
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, -> { String }, null: false do
162
- end
281
+ field :name, String, null: false
163
282
  }
164
- assert_equal upgrade(old), new
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, -> { String }, null: false do
173
- end
291
+ field :name, String, null: true
174
292
  }
175
- assert_equal upgrade(old), new
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 do
184
- end
305
+ field :name, String, null: false
306
+
307
+ field :name2, String, null: false
185
308
  }
186
- assert_equal upgrade(old), new
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, -> { String }, "newline description", null: false do
195
- end
317
+ field :name, String, "newline description", null: true
196
318
  }
197
- assert_equal upgrade(old), new
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, -> { String }, "newline description", null: false do
206
- end
327
+ field :name, String, "newline description", null: false
207
328
  }
208
- assert_equal upgrade(old), new
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: false do
217
- end
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
- assert_equal upgrade(old), new
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