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.
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.8.0.pre2"
3
+ VERSION = "1.8.0.pre3"
4
4
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Objects
5
+ BlameRange = GraphQL::ObjectType.define do
6
+ name "BlameRange"
7
+ description "Represents a range of information from a Git blame."
8
+
9
+ scopeless_tokens_as_minimum
10
+
11
+ # Test multiline interfaces
12
+ interfaces [
13
+ Interfaces::A,
14
+ Interfaces::B,
15
+ ]
16
+
17
+ field :startingLine, !types.Int do
18
+ description "The starting line for the range"
19
+
20
+ resolve ->(range, args, context) {
21
+ range.lines.first[:lineno]
22
+ }
23
+ end
24
+
25
+ field :endingLine, !types.Int do
26
+ description "The ending line for the range"
27
+
28
+ resolve ->(range, args, context) {
29
+ range.lines.first[:lineno] + (range.lines.length - 1)
30
+ }
31
+ end
32
+
33
+ field :commit, -> { !Objects::Commit } do
34
+ description "Identifies the line author"
35
+ end
36
+
37
+ field :age, !types.Int do
38
+ description "Identifies the recency of the change, from 1 (new) to 10 (old). This is calculated as a 2-quantile and determines the length of distance between the median age of all the changes in the file and the recency of the current range's change."
39
+ property :scale
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Objects
5
+ class BlameRange < Platform::Objects::Base
6
+ description "Represents a range of information from a Git blame."
7
+
8
+ scopeless_tokens_as_minimum
9
+
10
+ # Test multiline interfaces
11
+ implements Interfaces::A
12
+ implements Interfaces::B
13
+
14
+ field :starting_line, Integer, description: "The starting line for the range", null: false
15
+
16
+ def starting_line
17
+ @object.lines.first[:lineno]
18
+ end
19
+
20
+ field :ending_line, Integer, description: "The ending line for the range", null: false
21
+
22
+ def ending_line
23
+ @object.lines.first[:lineno] + (@object.lines.length - 1)
24
+ end
25
+
26
+ field :commit, Objects::Commit, description: "Identifies the line author", null: false
27
+
28
+ field :age, Integer, method: :scale, description: "Identifies the recency of the change, from 1 (new) to 10 (old). This is calculated as a 2-quantile and determines the length of distance between the median age of all the changes in the file and the recency of the current range's change.", null: false
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Interfaces
5
+ Subscribable = GraphQL::InterfaceType.define do
6
+ name "Subscribable"
7
+ description "Entities that can be subscribed to for web and email notifications."
8
+
9
+ field :id, !GraphQL::ID_TYPE, property: :global_relay_id
10
+
11
+ field :viewerSubscription, -> { !Enums::SubscriptionState } do
12
+ description "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity."
13
+
14
+ resolve ->(subscribable, arguments, context) do
15
+ if context[:viewer].nil?
16
+ return "unsubscribed"
17
+ end
18
+
19
+ subscription_status_response = subscribable.async_subscription_status(context[:viewer]).sync
20
+
21
+ if subscription_status_response.failed?
22
+ error = Platform::Errors::ServiceUnavailable.new("Subscriptions are currently unavailable. Please try again later.")
23
+ error.ast_node = context.irep_node.ast_node
24
+ error.path = context.path
25
+ context.errors << error
26
+ return "unavailable"
27
+ end
28
+
29
+ subscription = subscription_status_response.value
30
+ if subscription.included?
31
+ "unsubscribed"
32
+ elsif subscription.subscribed?
33
+ "subscribed"
34
+ elsif subscription.ignored?
35
+ "ignored"
36
+ end
37
+ end
38
+ end
39
+
40
+ field :viewerCanSubscribe, !types.Boolean do
41
+ description "Check if the viewer is able to change their subscription status for the repository."
42
+
43
+ resolve ->(subscribable, arguments, context) do
44
+ return false if context[:viewer].nil?
45
+
46
+ subscribable.async_subscription_status(context[:viewer]).then(&:success?)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Interfaces
5
+ class Subscribable < Platform::Interfaces::Base
6
+ description "Entities that can be subscribed to for web and email notifications."
7
+
8
+ field :id, GraphQL::ID_TYPE, method: :global_relay_id, null: false
9
+
10
+ field :viewer_subscription, Enums::SubscriptionState, description: "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", null: false
11
+
12
+ def viewer_subscription
13
+ if @context[:viewer].nil?
14
+ return "unsubscribed"
15
+ end
16
+
17
+ subscription_status_response = @object.async_subscription_status(@context[:viewer]).sync
18
+
19
+ if subscription_status_response.failed?
20
+ error = Platform::Errors::ServiceUnavailable.new("Subscriptions are currently unavailable. Please try again later.")
21
+ error.ast_node = @context.irep_node.ast_node
22
+ error.path = @context.path
23
+ @context.errors << error
24
+ return "unavailable"
25
+ end
26
+
27
+ subscription = subscription_status_response.value
28
+ if subscription.included?
29
+ "unsubscribed"
30
+ elsif subscription.subscribed?
31
+ "subscribed"
32
+ elsif subscription.ignored?
33
+ "ignored"
34
+ end
35
+ end
36
+
37
+ field :viewer_can_subscribe, Boolean, description: "Check if the viewer is able to change their subscription status for the repository.", null: false
38
+
39
+ def viewer_can_subscribe
40
+ return false if @context[:viewer].nil?
41
+
42
+ @object.async_subscription_status(@context[:viewer]).then(&:success?)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Objects
5
+ X = define_active_record_type(-> { ::X }) do
6
+ name "X"
7
+ description "An x on a y."
8
+ visibility :internal
9
+ minimum_accepted_scopes ["z"]
10
+
11
+ global_id_field :id
12
+ interfaces [GraphQL::Relay::Node.interface]
13
+
14
+ field :f1, !Objects::O1, "The x being y."
15
+ field :f2, !Enums::E1, "x for the y.", property: :field_2
16
+ field :f3, Enums::E2, "x for y."
17
+ field :details, types.String, "Details."
18
+
19
+ field :f4, !Objects::O2, "x as a y inside the z." do
20
+ resolve ->(obj_x, arguments, context) do
21
+ Class1.new(
22
+ a: Class2.new(
23
+ b: obj_x.b_1,
24
+ c: obj_x.c_1
25
+ ),
26
+ d: Class3.new(
27
+ b: obj_x.b_2,
28
+ c: obj_x.c_3,
29
+ )
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Platform
4
+ module Objects
5
+ class X < Platform::Objects::Base
6
+ model_name "X"
7
+ description "An x on a y."
8
+ visibility :internal
9
+ minimum_accepted_scopes ["z"]
10
+
11
+ global_id_field :id
12
+ implements GraphQL::Relay::Node.interface
13
+
14
+ field :f1, Objects::O1, "The x being y.", null: false
15
+ field :f2, Enums::E1, "x for the y.", method: :field_2, null: false
16
+ field :f3, Enums::E2, "x for y.", null: true
17
+ field :details, String, "Details.", null: true
18
+
19
+ field :f4, Objects::O2, "x as a y inside the z.", null: false
20
+
21
+ def f4
22
+ Class1.new(
23
+ a: Class2.new(
24
+ b: @object.b_1,
25
+ c: @object.c_1
26
+ ),
27
+ d: Class3.new(
28
+ b: @object.b_2,
29
+ c: @object.c_3,
30
+ )
31
+ )
32
+ end
33
+ end
34
+ end
35
+ end
@@ -2,316 +2,749 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe GraphQL::Language::DocumentFromSchemaDefinition do
5
- let(:schema_idl) { <<-GRAPHQL
6
- type QueryType {
7
- foo: Foo
8
- }
9
-
10
- type Foo implements Bar {
11
- one: Type
12
- two(argument: InputType!): Type
13
- three(argument: InputType, other: String): Int
14
- four(argument: String = "string"): String
15
- five(argument: [String] = ["string", "string"]): String
16
- six(argument: String): Type
17
- }
18
-
19
- interface Bar {
20
- one: Type
21
- four(argument: String = "string"): String
22
- }
23
-
24
- type Type {
25
- a: String
26
- }
27
-
28
- input InputType {
29
- key: String!
30
- answer: Int = 42
31
- }
32
-
33
- type MutationType {
34
- a(input: InputType): String
35
- }
36
-
37
- # Scalar description
38
- scalar CustomScalar
39
-
40
- enum Site {
41
- DESKTOP
42
- MOBILE
43
- }
44
-
45
- union Union = Type | QueryType
46
-
47
- schema {
48
- query: QueryType
49
- mutation: MutationType
50
- }
51
- GRAPHQL
52
- }
53
-
54
- let(:expected_complete_idl) { <<-GRAPHQL
55
- # Represents `true` or `false` values.
56
- scalar Boolean
57
-
58
- # Represents textual data as UTF-8 character sequences. This type is most often
59
- # used by GraphQL to represent free-form human-readable text.
60
- scalar String
61
-
62
- # The fundamental unit of any GraphQL Schema is the type. There are many kinds of
63
- # types in GraphQL as represented by the `__TypeKind` enum.
64
- #
65
- # Depending on the kind of a type, certain fields describe information about that
66
- # type. Scalar types provide no information beyond a name and description, while
67
- # Enum types provide their values. Object and Interface types provide the fields
68
- # they describe. Abstract types, Union and Interface, provide the Object types
69
- # possible at runtime. List and NonNull types compose other types.
70
- type __Type {
71
- kind: __TypeKind!
72
- name: String
73
- description: String
74
- fields(includeDeprecated: Boolean = false): [__Field!]
75
- interfaces: [__Type!]
76
- possibleTypes: [__Type!]
77
- enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
78
- inputFields: [__InputValue!]
79
- ofType: __Type
80
- }
81
-
82
- # An enum describing what kind of type a given `__Type` is.
83
- enum __TypeKind {
84
- # Indicates this type is a scalar.
85
- SCALAR
86
-
87
- # Indicates this type is an object. `fields` and `interfaces` are valid fields.
88
- OBJECT
89
-
90
- # Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
91
- INTERFACE
92
-
93
- # Indicates this type is a union. `possibleTypes` is a valid field.
94
- UNION
95
-
96
- # Indicates this type is an enum. `enumValues` is a valid field.
97
- ENUM
98
-
99
- # Indicates this type is an input object. `inputFields` is a valid field.
100
- INPUT_OBJECT
101
-
102
- # Indicates this type is a list. `ofType` is a valid field.
103
- LIST
104
-
105
- # Indicates this type is a non-null. `ofType` is a valid field.
106
- NON_NULL
107
- }
108
-
109
- # Object and Interface types are described by a list of Fields, each of which has
110
- # a name, potentially a list of arguments, and a return type.
111
- type __Field {
112
- name: String!
113
- description: String
114
- args: [__InputValue!]!
115
- type: __Type!
116
- isDeprecated: Boolean!
117
- deprecationReason: String
118
- }
119
-
120
- # Arguments provided to Fields or Directives and the input fields of an
121
- # InputObject are represented as Input Values which describe their type and
122
- # optionally a default value.
123
- type __InputValue {
124
- name: String!
125
- description: String
126
- type: __Type!
127
-
128
- # A GraphQL-formatted string representing the default value for this input value.
129
- defaultValue: String
130
- }
131
-
132
- # One possible value for a given Enum. Enum values are unique values, not a
133
- # placeholder for a string or numeric value. However an Enum value is returned in
134
- # a JSON response as a string.
135
- type __EnumValue {
136
- name: String!
137
- description: String
138
- isDeprecated: Boolean!
139
- deprecationReason: String
140
- }
141
-
142
- type QueryType {
143
- foo: Foo
144
- }
145
-
146
- type Foo implements Bar {
147
- one: Type
148
- two(argument: InputType!): Type
149
- three(argument: InputType, other: String): Int
150
- four(argument: String = "string"): String
151
- five(argument: [String] = ["string", "string"]): String
152
- six(argument: String): Type
153
- }
154
-
155
- interface Bar {
156
- one: Type
157
- four(argument: String = "string"): String
158
- }
159
-
160
- type Type {
161
- a: String
162
- }
163
-
164
- input InputType {
165
- key: String!
166
- answer: Int = 42
167
- }
168
-
169
- # Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
170
- scalar Int
171
-
172
- type MutationType {
173
- a(input: InputType): String
174
- }
175
-
176
- # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
177
- # available types and directives on the server, as well as the entry points for
178
- # query, mutation, and subscription operations.
179
- type __Schema {
180
- # A list of all types supported by this server.
181
- types: [__Type!]!
182
-
183
- # The type that query operations will be rooted at.
184
- queryType: __Type!
185
-
186
- # If this server supports mutation, the type that mutation operations will be rooted at.
187
- mutationType: __Type
188
-
189
- # If this server support subscription, the type that subscription operations will be rooted at.
190
- subscriptionType: __Type
191
-
192
- # A list of all directives supported by this server.
193
- directives: [__Directive!]!
194
- }
5
+ let(:subject) { GraphQL::Language::DocumentFromSchemaDefinition }
195
6
 
196
- # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
197
- #
198
- # In some cases, you need to provide options to alter GraphQL's execution behavior
199
- # in ways field arguments will not suffice, such as conditionally including or
200
- # skipping a field. Directives provide this by describing additional information
201
- # to the executor.
202
- type __Directive {
203
- name: String!
204
- description: String
205
- locations: [__DirectiveLocation!]!
206
- args: [__InputValue!]!
207
- onOperation: Boolean!
208
- onFragment: Boolean!
209
- onField: Boolean!
7
+ describe "#document" do
8
+ let(:schema_idl) { <<-GRAPHQL
9
+ type QueryType {
10
+ foo: Foo
11
+ }
12
+
13
+ type Foo implements Bar {
14
+ one: Type
15
+ two(argument: InputType!): Site
16
+ three(argument: InputType, other: String): CustomScalar
17
+ four(argument: String = "string"): String
18
+ five(argument: [String] = ["string", "string"]): String
19
+ six(argument: String): Type
20
+ }
21
+
22
+ interface Bar {
23
+ one: Type
24
+ four(argument: String = "string"): String
25
+ }
26
+
27
+ type Type {
28
+ a: String
29
+ }
30
+
31
+ input InputType {
32
+ key: String!
33
+ answer: Int = 42
34
+ }
35
+
36
+ type MutationType {
37
+ a(input: InputType): String
38
+ }
39
+
40
+ # Scalar description
41
+ scalar CustomScalar
42
+
43
+ enum Site {
44
+ DESKTOP
45
+ MOBILE
46
+ }
47
+
48
+ union Union = Type | QueryType
49
+
50
+ schema {
51
+ query: QueryType
52
+ mutation: MutationType
53
+ }
54
+ GRAPHQL
210
55
  }
211
56
 
212
- # A Directive can be adjacent to many parts of the GraphQL language, a
213
- # __DirectiveLocation describes one such possible adjacencies.
214
- enum __DirectiveLocation {
215
- # Location adjacent to a query operation.
216
- QUERY
217
-
218
- # Location adjacent to a mutation operation.
219
- MUTATION
220
-
221
- # Location adjacent to a subscription operation.
222
- SUBSCRIPTION
223
-
224
- # Location adjacent to a field.
225
- FIELD
226
-
227
- # Location adjacent to a fragment definition.
228
- FRAGMENT_DEFINITION
229
-
230
- # Location adjacent to a fragment spread.
231
- FRAGMENT_SPREAD
232
-
233
- # Location adjacent to an inline fragment.
234
- INLINE_FRAGMENT
235
-
236
- # Location adjacent to a schema definition.
237
- SCHEMA
238
-
239
- # Location adjacent to a scalar definition.
240
- SCALAR
241
-
242
- # Location adjacent to an object type definition.
243
- OBJECT
244
-
245
- # Location adjacent to a field definition.
246
- FIELD_DEFINITION
247
-
248
- # Location adjacent to an argument definition.
249
- ARGUMENT_DEFINITION
250
-
251
- # Location adjacent to an interface definition.
252
- INTERFACE
253
-
254
- # Location adjacent to a union definition.
255
- UNION
256
-
257
- # Location adjacent to an enum definition.
258
- ENUM
259
-
260
- # Location adjacent to an enum value definition.
261
- ENUM_VALUE
57
+ let(:schema) { GraphQL::Schema.from_definition(schema_idl) }
58
+
59
+ let(:expected_document) { GraphQL.parse(expected_idl) }
60
+
61
+ describe "when printing and schema respects root name conventions" do
62
+ let(:schema_idl) { <<-GRAPHQL
63
+ type Query {
64
+ foo: Foo
65
+ }
66
+
67
+ type Foo implements Bar {
68
+ one: Type
69
+ two(argument: InputType!): Site
70
+ three(argument: InputType, other: String): CustomScalar
71
+ four(argument: String = "string"): String
72
+ five(argument: [String] = ["string", "string"]): String
73
+ six(argument: String): Type
74
+ }
75
+
76
+ interface Bar {
77
+ one: Type
78
+ four(argument: String = "string"): String
79
+ }
80
+
81
+ type Type {
82
+ a: String
83
+ }
84
+
85
+ input InputType {
86
+ key: String!
87
+ answer: Int = 42
88
+ }
89
+
90
+ type Mutation {
91
+ a(input: InputType): String
92
+ }
93
+
94
+ # Scalar description
95
+ scalar CustomScalar
96
+
97
+ enum Site {
98
+ DESKTOP
99
+ MOBILE
100
+ }
101
+
102
+ union Union = Type | Query
103
+
104
+ schema {
105
+ query: Query
106
+ mutation: Mutation
107
+ }
108
+ GRAPHQL
109
+ }
110
+
111
+ let(:expected_idl) { <<-GRAPHQL
112
+ type QueryType {
113
+ foo: Foo
114
+ }
115
+
116
+ type Foo implements Bar {
117
+ one: Type
118
+ two(argument: InputType!): Site
119
+ three(argument: InputType, other: String): CustomScalar
120
+ four(argument: String = "string"): String
121
+ five(argument: [String] = ["string", "string"]): String
122
+ six(argument: String): Type
123
+ }
124
+
125
+ interface Bar {
126
+ one: Type
127
+ four(argument: String = "string"): String
128
+ }
129
+
130
+ type Type {
131
+ a: String
132
+ }
133
+
134
+ input InputType {
135
+ key: String!
136
+ answer: Int = 42
137
+ }
138
+
139
+ type MutationType {
140
+ a(input: InputType): String
141
+ }
142
+
143
+ # Scalar description
144
+ scalar CustomScalar
145
+
146
+ enum Site {
147
+ DESKTOP
148
+ MOBILE
149
+ }
150
+
151
+ union Union = Type | QueryType
152
+ GRAPHQL
153
+ }
154
+
155
+ let(:document) {
156
+ subject.new(
157
+ schema
158
+ ).document
159
+ }
160
+
161
+ it "returns the IDL without introspection, built ins and schema root" do
162
+ assert equivalent_node?(expected_document, document)
163
+ end
164
+ end
262
165
 
263
- # Location adjacent to an input object type definition.
264
- INPUT_OBJECT
166
+ describe "with defaults" do
167
+ let(:expected_idl) { <<-GRAPHQL
168
+ type QueryType {
169
+ foo: Foo
170
+ }
171
+
172
+ type Foo implements Bar {
173
+ one: Type
174
+ two(argument: InputType!): Site
175
+ three(argument: InputType, other: String): CustomScalar
176
+ four(argument: String = "string"): String
177
+ five(argument: [String] = ["string", "string"]): String
178
+ six(argument: String): Type
179
+ }
180
+
181
+ interface Bar {
182
+ one: Type
183
+ four(argument: String = "string"): String
184
+ }
185
+
186
+ type Type {
187
+ a: String
188
+ }
189
+
190
+ input InputType {
191
+ key: String!
192
+ answer: Int = 42
193
+ }
194
+
195
+ type MutationType {
196
+ a(input: InputType): String
197
+ }
198
+
199
+ # Scalar description
200
+ scalar CustomScalar
201
+
202
+ enum Site {
203
+ DESKTOP
204
+ MOBILE
205
+ }
206
+
207
+ union Union = Type | QueryType
208
+
209
+ schema {
210
+ query: QueryType
211
+ mutation: MutationType
212
+ }
213
+ GRAPHQL
214
+ }
215
+
216
+ let(:document) {
217
+ subject.new(
218
+ schema
219
+ ).document
220
+ }
221
+
222
+ it "returns the IDL without introspection, built ins and schema if it doesnt respect name conventions" do
223
+ assert equivalent_node?(expected_document, document)
224
+ end
225
+ end
265
226
 
266
- # Location adjacent to an input object field definition.
267
- INPUT_FIELD_DEFINITION
268
- }
227
+ describe "with an except filter" do
228
+ let(:expected_idl) { <<-GRAPHQL
229
+ type QueryType {
230
+ foo: Foo
231
+ }
232
+
233
+ type Foo implements Bar {
234
+ three(argument: InputType, other: String): CustomScalar
235
+ four(argument: String = "string"): String
236
+ five(argument: [String] = ["string", "string"]): Site
237
+ }
238
+
239
+ interface Bar {
240
+ one: Type
241
+ four(argument: String = "string"): String
242
+ }
243
+
244
+ input InputType {
245
+ key: String!
246
+ answer: Int = 42
247
+ }
248
+
249
+ type MutationType {
250
+ a(input: InputType): String
251
+ }
252
+
253
+ # Scalar description
254
+ scalar CustomScalar
255
+
256
+ enum Site {
257
+ DESKTOP
258
+ MOBILE
259
+ }
260
+
261
+ schema {
262
+ query: QueryType
263
+ mutation: MutationType
264
+ }
265
+ GRAPHQL
266
+ }
267
+
268
+ let(:document) {
269
+ subject.new(
270
+ schema,
271
+ except: ->(m, _ctx) { m.is_a?(GraphQL::BaseType) && m.name == "Type" }
272
+ ).document
273
+ }
274
+
275
+ it "returns the IDL minus the filtered members" do
276
+ assert equivalent_node?(expected_document, document)
277
+ end
278
+ end
269
279
 
270
- # Represents signed double-precision fractional values as specified by [IEEE
271
- # 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
272
- scalar Float
280
+ describe "with an only filter" do
281
+ let(:expected_idl) { <<-GRAPHQL
282
+ type QueryType {
283
+ foo: Foo
284
+ }
285
+
286
+ type Foo implements Bar {
287
+ three(argument: InputType, other: String): CustomScalar
288
+ four(argument: String = "string"): String
289
+ five(argument: [String] = ["string", "string"]): Site
290
+ }
291
+
292
+ interface Bar {
293
+ one: Type
294
+ four(argument: String = "string"): String
295
+ }
296
+
297
+ input InputType {
298
+ key: String!
299
+ answer: Int = 42
300
+ }
301
+
302
+ type MutationType {
303
+ a(input: InputType): String
304
+ }
305
+
306
+ enum Site {
307
+ DESKTOP
308
+ MOBILE
309
+ }
310
+
311
+ schema {
312
+ query: QueryType
313
+ mutation: MutationType
314
+ }
315
+ GRAPHQL
316
+ }
317
+
318
+ let(:document) {
319
+ subject.new(
320
+ schema,
321
+ only: ->(m, _ctx) { !(m.is_a?(GraphQL::ScalarType) && m.name == "CustomScalar") }
322
+ ).document
323
+ }
324
+
325
+ it "returns the IDL minus the filtered members" do
326
+ assert equivalent_node?(expected_document, document)
327
+ end
328
+ end
273
329
 
274
- # Represents a unique identifier that is Base64 obfuscated. It is often used to
275
- # refetch an object or as key for a cache. The ID type appears in a JSON response
276
- # as a String; however, it is not intended to be human-readable. When expected as
277
- # an input type, any string (such as `"VXNlci0xMA=="`) or integer (such as `4`)
278
- # input value will be accepted as an ID.
279
- scalar ID
330
+ describe "when excluding built ins and introspection types" do
331
+ let(:expected_idl) { <<-GRAPHQL
332
+ type QueryType {
333
+ foo: Foo
334
+ }
335
+
336
+ type Foo implements Bar {
337
+ one: Type
338
+ two(argument: InputType!): Site
339
+ three(argument: InputType, other: String): CustomScalar
340
+ four(argument: String = "string"): String
341
+ five(argument: [String] = ["string", "string"]): String
342
+ six(argument: String): Type
343
+ }
344
+
345
+ interface Bar {
346
+ one: Type
347
+ four(argument: String = "string"): String
348
+ }
349
+
350
+ type Type {
351
+ a: String
352
+ }
353
+
354
+ input InputType {
355
+ key: String!
356
+ answer: Int = 42
357
+ }
358
+
359
+ type MutationType {
360
+ a(input: InputType): String
361
+ }
362
+
363
+ # Scalar description
364
+ scalar CustomScalar
365
+
366
+ enum Site {
367
+ DESKTOP
368
+ MOBILE
369
+ }
370
+
371
+ union Union = Type | QueryType
372
+
373
+ schema {
374
+ query: QueryType
375
+ mutation: MutationType
376
+ }
377
+ GRAPHQL
378
+ }
379
+
380
+ let(:document) {
381
+ subject.new(
382
+ schema,
383
+ always_include_schema: true
384
+ ).document
385
+ }
386
+
387
+ it "returns the schema idl besides introspection types and built ins" do
388
+ assert equivalent_node?(expected_document, document)
389
+ end
390
+ end
280
391
 
281
- # Scalar description
282
- scalar CustomScalar
392
+ describe "when printing excluding only introspection types" do
393
+ let(:expected_idl) { <<-GRAPHQL
394
+ # Represents `true` or `false` values.
395
+ scalar Boolean
396
+
397
+ # Represents textual data as UTF-8 character sequences. This type is most often
398
+ # used by GraphQL to represent free-form human-readable text.
399
+ scalar String
400
+
401
+ type QueryType {
402
+ foo: Foo
403
+ }
404
+
405
+ type Foo implements Bar {
406
+ one: Type
407
+ two(argument: InputType!): Type
408
+ three(argument: InputType, other: String): CustomScalar
409
+ four(argument: String = "string"): String
410
+ five(argument: [String] = ["string", "string"]): String
411
+ six(argument: String): Type
412
+ }
413
+
414
+ interface Bar {
415
+ one: Type
416
+ four(argument: String = "string"): String
417
+ }
418
+
419
+ type Type {
420
+ a: String
421
+ }
422
+
423
+ input InputType {
424
+ key: String!
425
+ answer: Int = 42
426
+ }
427
+
428
+ # Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
429
+ scalar Int
430
+
431
+ type MutationType {
432
+ a(input: InputType): String
433
+ }
434
+
435
+ # Represents signed double-precision fractional values as specified by [IEEE
436
+ # 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
437
+ scalar Float
438
+
439
+ # Represents a unique identifier that is Base64 obfuscated. It is often used to
440
+ # refetch an object or as key for a cache. The ID type appears in a JSON response
441
+ # as a String; however, it is not intended to be human-readable. When expected as
442
+ # an input type, any string (such as `"VXNlci0xMA=="`) or integer (such as `4`)
443
+ # input value will be accepted as an ID.
444
+ scalar ID
445
+
446
+ # Scalar description
447
+ scalar CustomScalar
448
+
449
+ enum Site {
450
+ DESKTOP
451
+ MOBILE
452
+ }
453
+
454
+ union Union = Type | QueryType
455
+
456
+ directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
457
+
458
+ directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
459
+
460
+ # Marks an element of a GraphQL schema as no longer supported.
461
+ directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
462
+
463
+ schema {
464
+ query: QueryType
465
+ mutation: MutationType
466
+ }
467
+ GRAPHQL
468
+ }
469
+
470
+ let(:document) {
471
+ subject.new(
472
+ schema,
473
+ include_built_in_scalars: true,
474
+ include_built_in_directives: true,
475
+ ).document
476
+ }
477
+
478
+ it "returns the the schema IDL including only the built ins and not introspection types" do
479
+ assert equivalent_node?(expected_document, document)
480
+ end
481
+ end
283
482
 
284
- enum Site {
285
- DESKTOP
286
- MOBILE
287
- }
483
+ describe "when printing the full schema" do
484
+ let(:expected_idl) { <<-GRAPHQL
485
+ # Represents `true` or `false` values.
486
+ scalar Boolean
487
+
488
+ # Represents textual data as UTF-8 character sequences. This type is most often
489
+ # used by GraphQL to represent free-form human-readable text.
490
+ scalar String
491
+
492
+ # The fundamental unit of any GraphQL Schema is the type. There are many kinds of
493
+ # types in GraphQL as represented by the `__TypeKind` enum.
494
+ #
495
+ # Depending on the kind of a type, certain fields describe information about that
496
+ # type. Scalar types provide no information beyond a name and description, while
497
+ # Enum types provide their values. Object and Interface types provide the fields
498
+ # they describe. Abstract types, Union and Interface, provide the Object types
499
+ # possible at runtime. List and NonNull types compose other types.
500
+ type __Type {
501
+ kind: __TypeKind!
502
+ name: String
503
+ description: String
504
+ fields(includeDeprecated: Boolean = false): [__Field!]
505
+ interfaces: [__Type!]
506
+ possibleTypes: [__Type!]
507
+ enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
508
+ inputFields: [__InputValue!]
509
+ ofType: __Type
510
+ }
511
+
512
+ # An enum describing what kind of type a given `__Type` is.
513
+ enum __TypeKind {
514
+ # Indicates this type is a scalar.
515
+ SCALAR
516
+
517
+ # Indicates this type is an object. `fields` and `interfaces` are valid fields.
518
+ OBJECT
519
+
520
+ # Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
521
+ INTERFACE
522
+
523
+ # Indicates this type is a union. `possibleTypes` is a valid field.
524
+ UNION
525
+
526
+ # Indicates this type is an enum. `enumValues` is a valid field.
527
+ ENUM
528
+
529
+ # Indicates this type is an input object. `inputFields` is a valid field.
530
+ INPUT_OBJECT
531
+
532
+ # Indicates this type is a list. `ofType` is a valid field.
533
+ LIST
534
+
535
+ # Indicates this type is a non-null. `ofType` is a valid field.
536
+ NON_NULL
537
+ }
538
+
539
+ # Object and Interface types are described by a list of Fields, each of which has
540
+ # a name, potentially a list of arguments, and a return type.
541
+ type __Field {
542
+ name: String!
543
+ description: String
544
+ args: [__InputValue!]!
545
+ type: __Type!
546
+ isDeprecated: Boolean!
547
+ deprecationReason: String
548
+ }
549
+
550
+ # Arguments provided to Fields or Directives and the input fields of an
551
+ # InputObject are represented as Input Values which describe their type and
552
+ # optionally a default value.
553
+ type __InputValue {
554
+ name: String!
555
+ description: String
556
+ type: __Type!
557
+
558
+ # A GraphQL-formatted string representing the default value for this input value.
559
+ defaultValue: String
560
+ }
561
+
562
+ # One possible value for a given Enum. Enum values are unique values, not a
563
+ # placeholder for a string or numeric value. However an Enum value is returned in
564
+ # a JSON response as a string.
565
+ type __EnumValue {
566
+ name: String!
567
+ description: String
568
+ isDeprecated: Boolean!
569
+ deprecationReason: String
570
+ }
571
+
572
+ type QueryType {
573
+ foo: Foo
574
+ }
575
+
576
+ type Foo implements Bar {
577
+ one: Type
578
+ two(argument: InputType!): Type
579
+ three(argument: InputType, other: String): Int
580
+ four(argument: String = "string"): String
581
+ five(argument: [String] = ["string", "string"]): String
582
+ six(argument: String): Type
583
+ }
584
+
585
+ interface Bar {
586
+ one: Type
587
+ four(argument: String = "string"): String
588
+ }
589
+
590
+ type Type {
591
+ a: String
592
+ }
593
+
594
+ input InputType {
595
+ key: String!
596
+ answer: Int = 42
597
+ }
598
+
599
+ # Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
600
+ scalar Int
601
+
602
+ type MutationType {
603
+ a(input: InputType): String
604
+ }
605
+
606
+ # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
607
+ # available types and directives on the server, as well as the entry points for
608
+ # query, mutation, and subscription operations.
609
+ type __Schema {
610
+ # A list of all types supported by this server.
611
+ types: [__Type!]!
612
+
613
+ # The type that query operations will be rooted at.
614
+ queryType: __Type!
615
+
616
+ # If this server supports mutation, the type that mutation operations will be rooted at.
617
+ mutationType: __Type
618
+
619
+ # If this server support subscription, the type that subscription operations will be rooted at.
620
+ subscriptionType: __Type
621
+
622
+ # A list of all directives supported by this server.
623
+ directives: [__Directive!]!
624
+ }
625
+
626
+ # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
627
+ #
628
+ # In some cases, you need to provide options to alter GraphQL's execution behavior
629
+ # in ways field arguments will not suffice, such as conditionally including or
630
+ # skipping a field. Directives provide this by describing additional information
631
+ # to the executor.
632
+ type __Directive {
633
+ name: String!
634
+ description: String
635
+ locations: [__DirectiveLocation!]!
636
+ args: [__InputValue!]!
637
+ onOperation: Boolean!
638
+ onFragment: Boolean!
639
+ onField: Boolean!
640
+ }
641
+
642
+ # A Directive can be adjacent to many parts of the GraphQL language, a
643
+ # __DirectiveLocation describes one such possible adjacencies.
644
+ enum __DirectiveLocation {
645
+ # Location adjacent to a query operation.
646
+ QUERY
647
+
648
+ # Location adjacent to a mutation operation.
649
+ MUTATION
650
+
651
+ # Location adjacent to a subscription operation.
652
+ SUBSCRIPTION
653
+
654
+ # Location adjacent to a field.
655
+ FIELD
656
+
657
+ # Location adjacent to a fragment definition.
658
+ FRAGMENT_DEFINITION
659
+
660
+ # Location adjacent to a fragment spread.
661
+ FRAGMENT_SPREAD
662
+
663
+ # Location adjacent to an inline fragment.
664
+ INLINE_FRAGMENT
665
+
666
+ # Location adjacent to a schema definition.
667
+ SCHEMA
668
+
669
+ # Location adjacent to a scalar definition.
670
+ SCALAR
671
+
672
+ # Location adjacent to an object type definition.
673
+ OBJECT
674
+
675
+ # Location adjacent to a field definition.
676
+ FIELD_DEFINITION
677
+
678
+ # Location adjacent to an argument definition.
679
+ ARGUMENT_DEFINITION
680
+
681
+ # Location adjacent to an interface definition.
682
+ INTERFACE
683
+
684
+ # Location adjacent to a union definition.
685
+ UNION
686
+
687
+ # Location adjacent to an enum definition.
688
+ ENUM
288
689
 
289
- union Union = Type | QueryType
690
+ # Location adjacent to an enum value definition.
691
+ ENUM_VALUE
290
692
 
291
- directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
693
+ # Location adjacent to an input object type definition.
694
+ INPUT_OBJECT
695
+
696
+ # Location adjacent to an input object field definition.
697
+ INPUT_FIELD_DEFINITION
698
+ }
699
+
700
+ # Represents signed double-precision fractional values as specified by [IEEE
701
+ # 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
702
+ scalar Float
703
+
704
+ # Represents a unique identifier that is Base64 obfuscated. It is often used to
705
+ # refetch an object or as key for a cache. The ID type appears in a JSON response
706
+ # as a String; however, it is not intended to be human-readable. When expected as
707
+ # an input type, any string (such as `"VXNlci0xMA=="`) or integer (such as `4`)
708
+ # input value will be accepted as an ID.
709
+ scalar ID
292
710
 
293
- directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
711
+ # Scalar description
712
+ scalar CustomScalar
294
713
 
295
- # Marks an element of a GraphQL schema as no longer supported.
296
- directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
714
+ enum Site {
715
+ DESKTOP
716
+ MOBILE
717
+ }
297
718
 
298
- schema {
299
- query: QueryType
300
- mutation: MutationType
301
- }
302
- GRAPHQL
303
- }
719
+ union Union = Type | QueryType
304
720
 
305
- let(:subject) { GraphQL::Language::DocumentFromSchemaDefinition }
721
+ directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
722
+
723
+ directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
306
724
 
307
- describe "#document" do
308
- it "returns the document AST from the given schema" do
309
- schema = GraphQL::Schema.from_definition(schema_idl)
310
- document = subject.new(schema).document
725
+ # Marks an element of a GraphQL schema as no longer supported.
726
+ directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
727
+
728
+ schema {
729
+ query: QueryType
730
+ mutation: MutationType
731
+ }
732
+ GRAPHQL
733
+ }
311
734
 
312
- expected_document = GraphQL.parse(expected_complete_idl)
735
+ let(:document) {
736
+ subject.new(
737
+ schema,
738
+ include_introspection_types: true,
739
+ include_built_in_directives: true,
740
+ include_built_in_scalars: true,
741
+ always_include_schema: true,
742
+ ).document
743
+ }
313
744
 
314
- assert equivalent_node?(expected_document, document)
745
+ it "returns the full document AST from the given schema including built ins and introspection" do
746
+ assert equivalent_node?(expected_document, document)
747
+ end
315
748
  end
316
749
  end
317
750
 
@@ -321,12 +754,12 @@ describe GraphQL::Language::DocumentFromSchemaDefinition do
321
754
  return false unless expected.is_a?(node.class)
322
755
 
323
756
  if expected.respond_to?(:children) && expected.respond_to?(:scalars)
324
- children_equal = node.children.all? do |child|
325
- expected.children.find { |expected_child| equivalent_node?(expected_child, child) }
757
+ children_equal = expected.children.all? do |expected_child|
758
+ node.children.find { |child| equivalent_node?(expected_child, child) }
326
759
  end
327
760
 
328
- scalars_equal = node.children.all? do |child|
329
- expected.children.find { |expected_child| equivalent_node?(expected_child, child) }
761
+ scalars_equal = expected.children.all? do |expected_child|
762
+ node.children.find { |child| equivalent_node?(expected_child, child) }
330
763
  end
331
764
 
332
765
  children_equal && scalars_equal