graphql 0.19.3 → 0.19.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/max_query_complexity.rb +1 -1
  3. data/lib/graphql/analysis/max_query_depth.rb +1 -1
  4. data/lib/graphql/boolean_type.rb +2 -2
  5. data/lib/graphql/define/instance_definable.rb +2 -2
  6. data/lib/graphql/enum_type.rb +3 -3
  7. data/lib/graphql/field.rb +6 -6
  8. data/lib/graphql/float_type.rb +2 -2
  9. data/lib/graphql/id_type.rb +2 -2
  10. data/lib/graphql/input_object_type.rb +1 -1
  11. data/lib/graphql/int_type.rb +2 -2
  12. data/lib/graphql/internal_representation/rewrite.rb +12 -12
  13. data/lib/graphql/introspection/arguments_field.rb +1 -1
  14. data/lib/graphql/introspection/enum_value_type.rb +1 -1
  15. data/lib/graphql/introspection/enum_values_field.rb +1 -1
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/fields_field.rb +1 -1
  18. data/lib/graphql/introspection/input_fields_field.rb +1 -1
  19. data/lib/graphql/introspection/input_value_type.rb +2 -2
  20. data/lib/graphql/introspection/interfaces_field.rb +1 -1
  21. data/lib/graphql/introspection/of_type_field.rb +1 -1
  22. data/lib/graphql/introspection/possible_types_field.rb +1 -1
  23. data/lib/graphql/introspection/schema_field.rb +1 -1
  24. data/lib/graphql/introspection/schema_type.rb +5 -5
  25. data/lib/graphql/introspection/type_by_name_field.rb +1 -1
  26. data/lib/graphql/introspection/type_type.rb +6 -6
  27. data/lib/graphql/introspection/typename_field.rb +1 -1
  28. data/lib/graphql/language.rb +1 -0
  29. data/lib/graphql/language/comments.rb +44 -0
  30. data/lib/graphql/language/definition_slice.rb +1 -1
  31. data/lib/graphql/language/generation.rb +35 -12
  32. data/lib/graphql/language/lexer.rb +29 -10
  33. data/lib/graphql/language/lexer.rl +25 -6
  34. data/lib/graphql/language/nodes.rb +30 -23
  35. data/lib/graphql/language/parser.rb +33 -14
  36. data/lib/graphql/language/parser.y +33 -14
  37. data/lib/graphql/language/parser_tests.rb +86 -2
  38. data/lib/graphql/language/token.rb +3 -2
  39. data/lib/graphql/language/visitor.rb +3 -3
  40. data/lib/graphql/object_type.rb +1 -1
  41. data/lib/graphql/query/arguments.rb +23 -2
  42. data/lib/graphql/query/serial_execution/field_resolution.rb +31 -14
  43. data/lib/graphql/relay/base_connection.rb +1 -3
  44. data/lib/graphql/relay/connection_type.rb +1 -1
  45. data/lib/graphql/relay/mutation.rb +1 -1
  46. data/lib/graphql/relay/relation_connection.rb +7 -3
  47. data/lib/graphql/scalar_type.rb +1 -1
  48. data/lib/graphql/schema.rb +19 -8
  49. data/lib/graphql/schema/loader.rb +2 -2
  50. data/lib/graphql/schema/printer.rb +63 -8
  51. data/lib/graphql/schema/timeout_middleware.rb +11 -11
  52. data/lib/graphql/schema/validation.rb +12 -12
  53. data/lib/graphql/static_validation/arguments_validator.rb +1 -1
  54. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  55. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  56. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  57. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
  58. data/lib/graphql/static_validation/rules/fields_will_merge.rb +3 -2
  59. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  60. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  61. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +9 -4
  62. data/lib/graphql/static_validation/rules/fragments_are_named.rb +1 -1
  63. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  64. data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -3
  65. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  66. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  67. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  68. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  69. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  70. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  71. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -6
  72. data/lib/graphql/static_validation/type_stack.rb +2 -2
  73. data/lib/graphql/string_type.rb +2 -2
  74. data/lib/graphql/version.rb +1 -1
  75. data/readme.md +1 -1
  76. data/spec/graphql/analysis/analyze_query_spec.rb +3 -3
  77. data/spec/graphql/analysis/query_complexity_spec.rb +7 -7
  78. data/spec/graphql/introspection/directive_type_spec.rb +2 -2
  79. data/spec/graphql/introspection/introspection_query_spec.rb +26 -26
  80. data/spec/graphql/language/generation_spec.rb +137 -53
  81. data/spec/graphql/language/lexer_spec.rb +22 -0
  82. data/spec/graphql/language/visitor_spec.rb +6 -6
  83. data/spec/graphql/query/arguments_spec.rb +45 -1
  84. data/spec/graphql/query/context_spec.rb +4 -4
  85. data/spec/graphql/query/executor_spec.rb +1 -1
  86. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -1
  87. data/spec/graphql/relay/mutation_spec.rb +2 -2
  88. data/spec/graphql/relay/node_spec.rb +2 -2
  89. data/spec/graphql/relay/relation_connection_spec.rb +16 -0
  90. data/spec/graphql/schema/loader_spec.rb +2 -2
  91. data/spec/graphql/schema/middleware_chain_spec.rb +6 -6
  92. data/spec/graphql/schema/printer_spec.rb +268 -18
  93. data/spec/graphql/schema/rescue_middleware_spec.rb +1 -1
  94. data/spec/graphql/schema/timeout_middleware_spec.rb +2 -2
  95. data/spec/graphql/schema_spec.rb +2 -2
  96. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +13 -0
  97. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
  98. data/spec/graphql/static_validation/type_stack_spec.rb +1 -1
  99. data/spec/support/dairy_app.rb +25 -25
  100. data/spec/support/dairy_data.rb +2 -0
  101. data/spec/support/star_wars_data.rb +2 -1
  102. data/spec/support/star_wars_schema.rb +18 -18
  103. metadata +19 -2
@@ -19,7 +19,9 @@ describe GraphQL::Schema::Printer do
19
19
 
20
20
  sub_input_type = GraphQL::InputObjectType.define do
21
21
  name "Sub"
22
- input_field :string, types.String
22
+ description "Test"
23
+ input_field :string, types.String, 'Something'
24
+ input_field :int, types.Int, 'Something'
23
25
  end
24
26
 
25
27
  variant_input_type = GraphQL::InputObjectType.define do
@@ -51,6 +53,30 @@ describe GraphQL::Schema::Printer do
51
53
  field :comments_count, !types.Int, deprecation_reason: 'Use "comments".'
52
54
  end
53
55
 
56
+ audio_type = GraphQL::ObjectType.define do
57
+ name "Audio"
58
+
59
+ field :id, !types.ID
60
+ field :name, !types.String
61
+ field :duration, !types.Int
62
+ end
63
+
64
+ image_type = GraphQL::ObjectType.define do
65
+ name "Image"
66
+
67
+ field :id, !types.ID
68
+ field :name, !types.String
69
+ field :width, !types.Int
70
+ field :height, !types.Int
71
+ end
72
+
73
+ media_union_type = GraphQL::UnionType.define do
74
+ name "Media"
75
+ description "Media objects"
76
+
77
+ possible_types [image_type, audio_type]
78
+ end
79
+
54
80
  query_root = GraphQL::ObjectType.define do
55
81
  name "Query"
56
82
  description "The query root of this schema"
@@ -59,57 +85,152 @@ describe GraphQL::Schema::Printer do
59
85
  type post_type
60
86
  argument :id, !types.ID
61
87
  argument :varied, variant_input_type, default_value: { id: "123", int: 234, float: 2.3, enum: :foo, sub: [{ string: "str" }] }
62
- resolve -> (obj, args, ctx) { Post.find(args["id"]) }
88
+ resolve ->(obj, args, ctx) { Post.find(args["id"]) }
89
+ end
90
+ end
91
+
92
+ create_post_mutation = GraphQL::Relay::Mutation.define do
93
+ name "CreatePost"
94
+ description "Create a blog post"
95
+
96
+ input_field :title, !types.String
97
+ input_field :body, !types.String
98
+
99
+ return_field :post, post_type
100
+
101
+ resolve ->(_, _, _) { }
102
+ end
103
+
104
+ mutation_root = GraphQL::ObjectType.define do
105
+ name "Mutation"
106
+
107
+ field :createPost, field: create_post_mutation.field
108
+ end
109
+
110
+ subscription_root = GraphQL::ObjectType.define do
111
+ name "Subscription"
112
+
113
+ field :post do
114
+ type post_type
115
+ argument :id, !types.ID
116
+ resolve ->(_, _, _) { }
63
117
  end
64
118
  end
65
119
 
66
- GraphQL::Schema.define(query: query_root, resolve_type: :pass)
120
+ GraphQL::Schema.define(
121
+ query: query_root,
122
+ mutation: mutation_root,
123
+ subscription: subscription_root,
124
+ resolve_type: :pass,
125
+ orphan_types: [media_union_type]
126
+ )
67
127
  }
68
128
 
69
129
  describe ".print_introspection_schema" do
70
130
  it "returns the schema as a string for the introspection types" do
131
+ # From https://github.com/graphql/graphql-js/blob/6a0e00fe46951767287f2cc62e1a10b167b2eaa6/src/utilities/__tests__/schemaPrinter-test.js#L599
71
132
  expected = <<SCHEMA
72
133
  schema {
73
- query: Query
134
+ query: Root
74
135
  }
75
136
 
76
- directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
77
-
78
- directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
79
-
80
- directive @deprecated(reason: String = \"No longer supported\") on FIELD_DEFINITION | ENUM_VALUE
81
-
137
+ # Directs the executor to include this field or fragment only when the \`if\` argument is true.
138
+ directive @include(
139
+ # Included when true.
140
+ if: Boolean!
141
+ ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
142
+
143
+ # Directs the executor to skip this field or fragment when the \`if\` argument is true.
144
+ directive @skip(
145
+ # Skipped when true.
146
+ if: Boolean!
147
+ ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
148
+
149
+ # Marks an element of a GraphQL schema as no longer supported.
150
+ directive @deprecated(
151
+ # Explains why this element was deprecated, usually also including a suggestion
152
+ # for how to access supported similar data. Formatted in
153
+ # [Markdown](https://daringfireball.net/projects/markdown/).
154
+ reason: String = "No longer supported"
155
+ ) on FIELD_DEFINITION | ENUM_VALUE
156
+
157
+ # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
158
+ #
159
+ # In some cases, you need to provide options to alter GraphQL's execution behavior
160
+ # in ways field arguments will not suffice, such as conditionally including or
161
+ # skipping a field. Directives provide this by describing additional information
162
+ # to the executor.
82
163
  type __Directive {
83
164
  name: String!
84
165
  description: String
85
166
  locations: [__DirectiveLocation!]!
86
167
  args: [__InputValue!]!
87
- onOperation: Boolean! @deprecated(reason: \"Use `locations`.\")
88
- onFragment: Boolean! @deprecated(reason: \"Use `locations`.\")
89
- onField: Boolean! @deprecated(reason: \"Use `locations`.\")
168
+ onOperation: Boolean! @deprecated(reason: "Use \`locations\`.")
169
+ onFragment: Boolean! @deprecated(reason: "Use \`locations\`.")
170
+ onField: Boolean! @deprecated(reason: "Use \`locations\`.")
90
171
  }
91
172
 
173
+ # A Directive can be adjacent to many parts of the GraphQL language, a
174
+ # __DirectiveLocation describes one such possible adjacencies.
92
175
  enum __DirectiveLocation {
176
+ # Location adjacent to a query operation.
93
177
  QUERY
178
+
179
+ # Location adjacent to a mutation operation.
94
180
  MUTATION
181
+
182
+ # Location adjacent to a subscription operation.
95
183
  SUBSCRIPTION
184
+
185
+ # Location adjacent to a field.
96
186
  FIELD
187
+
188
+ # Location adjacent to a fragment definition.
97
189
  FRAGMENT_DEFINITION
190
+
191
+ # Location adjacent to a fragment spread.
98
192
  FRAGMENT_SPREAD
193
+
194
+ # Location adjacent to an inline fragment.
99
195
  INLINE_FRAGMENT
196
+
197
+ # Location adjacent to a schema definition.
100
198
  SCHEMA
199
+
200
+ # Location adjacent to a scalar definition.
101
201
  SCALAR
202
+
203
+ # Location adjacent to an object type definition.
102
204
  OBJECT
205
+
206
+ # Location adjacent to a field definition.
103
207
  FIELD_DEFINITION
208
+
209
+ # Location adjacent to an argument definition.
104
210
  ARGUMENT_DEFINITION
211
+
212
+ # Location adjacent to an interface definition.
105
213
  INTERFACE
214
+
215
+ # Location adjacent to a union definition.
106
216
  UNION
217
+
218
+ # Location adjacent to an enum definition.
107
219
  ENUM
220
+
221
+ # Location adjacent to an enum value definition.
108
222
  ENUM_VALUE
223
+
224
+ # Location adjacent to an input object type definition.
109
225
  INPUT_OBJECT
226
+
227
+ # Location adjacent to an input object field definition.
110
228
  INPUT_FIELD_DEFINITION
111
229
  }
112
230
 
231
+ # One possible value for a given Enum. Enum values are unique values, not a
232
+ # placeholder for a string or numeric value. However an Enum value is returned in
233
+ # a JSON response as a string.
113
234
  type __EnumValue {
114
235
  name: String!
115
236
  description: String
@@ -117,6 +238,8 @@ type __EnumValue {
117
238
  deprecationReason: String
118
239
  }
119
240
 
241
+ # Object and Interface types are described by a list of Fields, each of which has
242
+ # a name, potentially a list of arguments, and a return type.
120
243
  type __Field {
121
244
  name: String!
122
245
  description: String
@@ -126,41 +249,82 @@ type __Field {
126
249
  deprecationReason: String
127
250
  }
128
251
 
252
+ # Arguments provided to Fields or Directives and the input fields of an
253
+ # InputObject are represented as Input Values which describe their type and
254
+ # optionally a default value.
129
255
  type __InputValue {
130
256
  name: String!
131
257
  description: String
132
258
  type: __Type!
259
+
260
+ # A GraphQL-formatted string representing the default value for this input value.
133
261
  defaultValue: String
134
262
  }
135
263
 
264
+ # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
265
+ # available types and directives on the server, as well as the entry points for
266
+ # query, mutation, and subscription operations.
136
267
  type __Schema {
268
+ # A list of all types supported by this server.
137
269
  types: [__Type!]!
270
+
271
+ # The type that query operations will be rooted at.
138
272
  queryType: __Type!
273
+
274
+ # If this server supports mutation, the type that mutation operations will be rooted at.
139
275
  mutationType: __Type
276
+
277
+ # If this server support subscription, the type that subscription operations will be rooted at.
140
278
  subscriptionType: __Type
279
+
280
+ # A list of all directives supported by this server.
141
281
  directives: [__Directive!]!
142
282
  }
143
283
 
284
+ # The fundamental unit of any GraphQL Schema is the type. There are many kinds of
285
+ # types in GraphQL as represented by the \`__TypeKind\` enum.
286
+ #
287
+ # Depending on the kind of a type, certain fields describe information about that
288
+ # type. Scalar types provide no information beyond a name and description, while
289
+ # Enum types provide their values. Object and Interface types provide the fields
290
+ # they describe. Abstract types, Union and Interface, provide the Object types
291
+ # possible at runtime. List and NonNull types compose other types.
144
292
  type __Type {
293
+ kind: __TypeKind!
145
294
  name: String
146
295
  description: String
147
- kind: __TypeKind!
148
296
  fields(includeDeprecated: Boolean = false): [__Field!]
149
- ofType: __Type
150
- inputFields: [__InputValue!]
297
+ interfaces: [__Type!]
151
298
  possibleTypes: [__Type!]
152
299
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
153
- interfaces: [__Type!]
300
+ inputFields: [__InputValue!]
301
+ ofType: __Type
154
302
  }
155
303
 
304
+ # An enum describing what kind of type a given \`__Type\` is.
156
305
  enum __TypeKind {
306
+ # Indicates this type is a scalar.
157
307
  SCALAR
308
+
309
+ # Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields.
158
310
  OBJECT
311
+
312
+ # Indicates this type is an interface. \`fields\` and \`possibleTypes\` are valid fields.
159
313
  INTERFACE
314
+
315
+ # Indicates this type is a union. \`possibleTypes\` is a valid field.
160
316
  UNION
317
+
318
+ # Indicates this type is an enum. \`enumValues\` is a valid field.
161
319
  ENUM
320
+
321
+ # Indicates this type is an input object. \`inputFields\` is a valid field.
162
322
  INPUT_OBJECT
323
+
324
+ # Indicates this type is a list. \`ofType\` is a valid field.
163
325
  LIST
326
+
327
+ # Indicates this type is a non-null. \`ofType\` is a valid field.
164
328
  NON_NULL
165
329
  }
166
330
  SCHEMA
@@ -169,10 +333,54 @@ SCHEMA
169
333
  end
170
334
 
171
335
  describe ".print_schema" do
172
- it "returns the schema as a string for the defined types" do
336
+ it "includes schema definition when query root name doesn't match convention" do
337
+ schema.query.name = 'MyQueryRoot'
338
+
339
+ expected = <<SCHEMA
340
+ schema {
341
+ query: MyQueryRoot
342
+ mutation: Mutation
343
+ subscription: Subscription
344
+ }
345
+ SCHEMA
346
+
347
+ assert_match expected, GraphQL::Schema::Printer.print_schema(schema)
348
+ end
349
+
350
+ it "includes schema definition when mutation root name doesn't match convention" do
351
+ schema.mutation.name = 'MyMutationRoot'
352
+
353
+ expected = <<SCHEMA
354
+ schema {
355
+ query: Query
356
+ mutation: MyMutationRoot
357
+ subscription: Subscription
358
+ }
359
+ SCHEMA
360
+
361
+ assert_match expected, GraphQL::Schema::Printer.print_schema(schema)
362
+ end
363
+
364
+ it "includes schema definition when subscription root name doesn't match convention" do
365
+ schema.subscription.name = 'MySubscriptionRoot'
366
+
173
367
  expected = <<SCHEMA
174
368
  schema {
175
369
  query: Query
370
+ mutation: Mutation
371
+ subscription: MySubscriptionRoot
372
+ }
373
+ SCHEMA
374
+
375
+ assert_match expected, GraphQL::Schema::Printer.print_schema(schema)
376
+ end
377
+
378
+ it "returns the schema as a string for the defined types" do
379
+ expected = <<SCHEMA
380
+ type Audio {
381
+ id: ID!
382
+ name: String!
383
+ duration: Int!
176
384
  }
177
385
 
178
386
  enum Choice {
@@ -182,14 +390,46 @@ enum Choice {
182
390
  WOZ @deprecated
183
391
  }
184
392
 
393
+ # A blog comment
185
394
  type Comment implements Node {
186
395
  id: ID!
187
396
  }
188
397
 
398
+ # Autogenerated input type of CreatePost
399
+ input CreatePostInput {
400
+ # A unique identifier for the client performing the mutation.
401
+ clientMutationId: String
402
+ title: String!
403
+ body: String!
404
+ }
405
+
406
+ # Autogenerated return type of CreatePost
407
+ type CreatePostPayload {
408
+ # A unique identifier for the client performing the mutation.
409
+ clientMutationId: String
410
+ post: Post
411
+ }
412
+
413
+ type Image {
414
+ id: ID!
415
+ name: String!
416
+ width: Int!
417
+ height: Int!
418
+ }
419
+
420
+ # Media objects
421
+ union Media = Image | Audio
422
+
423
+ type Mutation {
424
+ # Create a blog post
425
+ createPost(input: CreatePostInput!): CreatePostPayload
426
+ }
427
+
189
428
  interface Node {
190
429
  id: ID!
191
430
  }
192
431
 
432
+ # A blog post
193
433
  type Post {
194
434
  id: ID!
195
435
  title: String!
@@ -198,12 +438,22 @@ type Post {
198
438
  comments_count: Int! @deprecated(reason: \"Use \\\"comments\\\".\")
199
439
  }
200
440
 
441
+ # The query root of this schema
201
442
  type Query {
202
443
  post(id: ID!, varied: Varied = {id: \"123\", int: 234, float: 2.3, enum: FOO, sub: [{string: \"str\"}]}): Post
203
444
  }
204
445
 
446
+ # Test
205
447
  input Sub {
448
+ # Something
206
449
  string: String
450
+
451
+ # Something
452
+ int: Int
453
+ }
454
+
455
+ type Subscription {
456
+ post(id: ID!): Post
207
457
  }
208
458
 
209
459
  input Varied {
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  class SpecExampleError < StandardError; end
4
4
 
5
5
  describe GraphQL::Schema::RescueMiddleware do
6
- let(:error_middleware) { -> (next_middleware) { raise(error_class) } }
6
+ let(:error_middleware) { ->(next_middleware) { raise(error_class) } }
7
7
 
8
8
  let(:rescue_middleware) do
9
9
  middleware = GraphQL::Schema::RescueMiddleware.new
@@ -5,7 +5,7 @@ describe GraphQL::Schema::TimeoutMiddleware do
5
5
  let(:timeout_middleware) { GraphQL::Schema::TimeoutMiddleware.new(max_seconds: max_seconds) }
6
6
  let(:timeout_schema) {
7
7
 
8
- sleep_for_seconds_resolve = -> (obj, args, ctx) {
8
+ sleep_for_seconds_resolve = ->(obj, args, ctx) {
9
9
  sleep(args[:seconds])
10
10
  args[:seconds]
11
11
  }
@@ -13,7 +13,7 @@ describe GraphQL::Schema::TimeoutMiddleware do
13
13
  nested_sleep_type = GraphQL::ObjectType.define do
14
14
  name "NestedSleep"
15
15
  field :seconds, types.Float do
16
- resolve -> (obj, args, ctx) { obj }
16
+ resolve ->(obj, args, ctx) { obj }
17
17
  end
18
18
 
19
19
  field :nestedSleep, -> { nested_sleep_type } do