graphql 1.6.3 → 1.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +31 -5
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -1
- data/lib/graphql/query.rb +5 -0
- data/lib/graphql/query/literal_input.rb +4 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +3 -2
- data/lib/graphql/schema/printer.rb +6 -6
- data/lib/graphql/static_validation/validator.rb +9 -5
- data/lib/graphql/version.rb +1 -1
- data/readme.md +2 -0
- data/spec/generators/graphql/install_generator_spec.rb +17 -5
- data/spec/graphql/base_type_spec.rb +1 -1
- data/spec/graphql/query/literal_input_spec.rb +18 -0
- data/spec/graphql/query_spec.rb +21 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +21 -21
- data/spec/graphql/schema/printer_spec.rb +100 -98
- data/spec/graphql/static_validation/validator_spec.rb +10 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 347eef5d121c7ccb7f0c217370e2a02285d36096
|
4
|
+
data.tar.gz: e2b7083f415d77f05dcb888c121075617c93e677
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07a84a28ba76c6b7f0586b1c4e73745ae4d279482cab00b2a1ae6d087e566156359f993d325cc102c7af3ed23b0dc3f381d29635fef85ebe73d71ed103d7e0f2
|
7
|
+
data.tar.gz: d5b0dcfeb682086a666c839ebf4d0dcfd695201682016cc55d16d28d6f487012ac8f82e6360ea58780e3a6874c4eee52b49d0e8f44d37817e0672decdb27753f
|
@@ -68,6 +68,11 @@ module Graphql
|
|
68
68
|
default: false,
|
69
69
|
desc: "Include GraphQL::Batch installation"
|
70
70
|
|
71
|
+
# These two options are taken from Rails' own generators'
|
72
|
+
class_option :api,
|
73
|
+
type: :boolean,
|
74
|
+
desc: "Preconfigure smaller stack for API only apps"
|
75
|
+
|
71
76
|
|
72
77
|
GRAPHIQL_ROUTE = <<-RUBY
|
73
78
|
if Rails.env.development?
|
@@ -83,19 +88,40 @@ RUBY
|
|
83
88
|
template("graphql_controller.erb", "app/controllers/graphql_controller.rb")
|
84
89
|
route('post "/graphql", to: "graphql#execute"')
|
85
90
|
|
86
|
-
if !options[:skip_graphiql]
|
87
|
-
gem("graphiql-rails", group: :development)
|
88
|
-
route(GRAPHIQL_ROUTE)
|
89
|
-
end
|
90
|
-
|
91
91
|
if options[:batch]
|
92
92
|
gem("graphql-batch")
|
93
93
|
create_dir("app/graphql/loaders")
|
94
94
|
end
|
95
|
+
|
96
|
+
if options.api?
|
97
|
+
say("Skipped graphiql, as this rails project is API only")
|
98
|
+
say(" You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app")
|
99
|
+
elsif !options[:skip_graphiql]
|
100
|
+
gem("graphiql-rails", group: :development)
|
101
|
+
|
102
|
+
# This is a little cheat just to get cleaner shell output:
|
103
|
+
log :route, 'graphiql-rails'
|
104
|
+
shell.mute do
|
105
|
+
route(GRAPHIQL_ROUTE)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
if gemfile_modified?
|
110
|
+
say "Gemfile has been modified, make sure you `bundle install`"
|
111
|
+
end
|
95
112
|
end
|
96
113
|
|
97
114
|
private
|
98
115
|
|
116
|
+
def gemfile_modified?
|
117
|
+
@gemfile_modified
|
118
|
+
end
|
119
|
+
|
120
|
+
def gem(*args)
|
121
|
+
@gemfile_modified = true
|
122
|
+
super(*args)
|
123
|
+
end
|
124
|
+
|
99
125
|
def create_dir(dir)
|
100
126
|
empty_directory(dir)
|
101
127
|
if !options[:skip_keeps]
|
@@ -2,11 +2,12 @@ class GraphqlController < ApplicationController
|
|
2
2
|
def execute
|
3
3
|
variables = ensure_hash(params[:variables])
|
4
4
|
query = params[:query]
|
5
|
+
operation_name = params[:operationName]
|
5
6
|
context = {
|
6
7
|
# Query context goes here, for example:
|
7
8
|
# current_user: current_user,
|
8
9
|
}
|
9
|
-
result = <%= schema_name %>.execute(query, variables: variables, context: context)
|
10
|
+
result = <%= schema_name %>.execute(query, variables: variables, context: context, operation_name: operation_name)
|
10
11
|
render json: result
|
11
12
|
end
|
12
13
|
|
data/lib/graphql/query.rb
CHANGED
@@ -29,6 +29,9 @@ module GraphQL
|
|
29
29
|
|
30
30
|
attr_reader :schema, :context, :root_value, :warden, :provided_variables, :operation_name
|
31
31
|
|
32
|
+
# @return [Boolean] if false, static validation is skipped (execution behavior for invalid queries is undefined)
|
33
|
+
attr_accessor :validate
|
34
|
+
|
32
35
|
attr_accessor :query_string
|
33
36
|
|
34
37
|
# @return [GraphQL::Language::Nodes::Document]
|
@@ -59,6 +62,7 @@ module GraphQL
|
|
59
62
|
@root_value = root_value
|
60
63
|
@fragments = nil
|
61
64
|
@operations = nil
|
65
|
+
@validate = validate
|
62
66
|
|
63
67
|
@analysis_errors = []
|
64
68
|
if variables.is_a?(String)
|
@@ -270,6 +274,7 @@ module GraphQL
|
|
270
274
|
|
271
275
|
@validation_pipeline = GraphQL::Query::ValidationPipeline.new(
|
272
276
|
query: self,
|
277
|
+
validate: @validate,
|
273
278
|
parse_error: parse_error,
|
274
279
|
operation_name_error: operation_name_error,
|
275
280
|
max_depth: @max_depth,
|
@@ -77,6 +77,10 @@ module GraphQL
|
|
77
77
|
# `context` isn't present when pre-calculating defaults
|
78
78
|
if context
|
79
79
|
value = arg_defn.prepare(value, context)
|
80
|
+
if value.is_a?(GraphQL::ExecutionError)
|
81
|
+
value.ast_node = ast_arg
|
82
|
+
raise value
|
83
|
+
end
|
80
84
|
end
|
81
85
|
values_hash[arg_name] = value
|
82
86
|
end
|
@@ -24,7 +24,7 @@ module GraphQL
|
|
24
24
|
def result
|
25
25
|
result_name = irep_node.name
|
26
26
|
raw_value = get_raw_value
|
27
|
-
if raw_value
|
27
|
+
if raw_value.is_a?(GraphQL::Execution::Execute::Skip)
|
28
28
|
{}
|
29
29
|
else
|
30
30
|
{ result_name => get_finished_value(raw_value) }
|
@@ -14,10 +14,11 @@ module GraphQL
|
|
14
14
|
#
|
15
15
|
# @api private
|
16
16
|
class ValidationPipeline
|
17
|
-
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
17
|
+
def initialize(query:, validate:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
18
18
|
@validation_errors = []
|
19
19
|
@analysis_errors = []
|
20
20
|
@internal_representation = nil
|
21
|
+
@validate = validate
|
21
22
|
@parse_error = parse_error
|
22
23
|
@operation_name_error = operation_name_error
|
23
24
|
@query = query
|
@@ -76,7 +77,7 @@ module GraphQL
|
|
76
77
|
elsif @operation_name_error
|
77
78
|
@validation_errors << @operation_name_error
|
78
79
|
else
|
79
|
-
validation_result = @schema.static_validator.validate(@query)
|
80
|
+
validation_result = @schema.static_validator.validate(@query, validate: @validate)
|
80
81
|
@validation_errors.concat(validation_result[:errors])
|
81
82
|
@internal_representation = validation_result[:irep]
|
82
83
|
|
@@ -186,7 +186,7 @@ module GraphQL
|
|
186
186
|
end
|
187
187
|
|
188
188
|
out = "(\n".dup
|
189
|
-
out << arguments.map.with_index{ |arg, i|
|
189
|
+
out << arguments.sort_by(&:name).map.with_index{ |arg, i|
|
190
190
|
"#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\
|
191
191
|
"#{print_input_value(arg)}"
|
192
192
|
}.join("\n")
|
@@ -244,7 +244,7 @@ module GraphQL
|
|
244
244
|
include DescriptionPrinter
|
245
245
|
def print_fields(warden, type)
|
246
246
|
fields = warden.fields(type)
|
247
|
-
fields.map.with_index { |field, i|
|
247
|
+
fields.sort_by(&:name).map.with_index { |field, i|
|
248
248
|
"#{print_description(field, ' ', i == 0)}"\
|
249
249
|
" #{field.name}#{print_args(warden, field, ' ')}: #{field.type}#{print_deprecated(field)}"
|
250
250
|
}.join("\n")
|
@@ -275,7 +275,7 @@ module GraphQL
|
|
275
275
|
def self.print(warden, type)
|
276
276
|
interfaces = warden.interfaces(type)
|
277
277
|
if interfaces.any?
|
278
|
-
implementations = " implements #{interfaces.map(&:to_s).join(", ")}"
|
278
|
+
implementations = " implements #{interfaces.sort_by(&:name).map(&:to_s).join(", ")}"
|
279
279
|
else
|
280
280
|
implementations = nil
|
281
281
|
end
|
@@ -301,7 +301,7 @@ module GraphQL
|
|
301
301
|
def self.print(warden, type)
|
302
302
|
possible_types = warden.possible_types(type)
|
303
303
|
"#{print_description(type)}"\
|
304
|
-
"union #{type.name} = #{possible_types.map(&:to_s).join(" | ")}"
|
304
|
+
"union #{type.name} = #{possible_types.sort_by(&:name).map(&:to_s).join(" | ")}"
|
305
305
|
end
|
306
306
|
end
|
307
307
|
|
@@ -311,7 +311,7 @@ module GraphQL
|
|
311
311
|
def self.print(warden, type)
|
312
312
|
enum_values = warden.enum_values(type)
|
313
313
|
|
314
|
-
values = enum_values.map.with_index { |v, i|
|
314
|
+
values = enum_values.sort_by(&:name).map.with_index { |v, i|
|
315
315
|
"#{print_description(v, ' ', i == 0)}"\
|
316
316
|
" #{v.name}#{print_deprecated(v)}"
|
317
317
|
}.join("\n")
|
@@ -326,7 +326,7 @@ module GraphQL
|
|
326
326
|
extend DescriptionPrinter
|
327
327
|
def self.print(warden, type)
|
328
328
|
arguments = warden.arguments(type)
|
329
|
-
fields = arguments.map.with_index{ |field, i|
|
329
|
+
fields = arguments.sort_by(&:name).map.with_index{ |field, i|
|
330
330
|
"#{print_description(field, " ", i == 0)}"\
|
331
331
|
" #{print_input_value(field)}"
|
332
332
|
}.join("\n")
|
@@ -7,8 +7,8 @@ module GraphQL
|
|
7
7
|
#
|
8
8
|
# @example Validate a query
|
9
9
|
# validator = GraphQL::StaticValidation::Validator.new(schema: MySchema)
|
10
|
-
#
|
11
|
-
# errors = validator.validate(
|
10
|
+
# query = GraphQL::Query.new(MySchema, query_string)
|
11
|
+
# errors = validator.validate(query)[:errors]
|
12
12
|
#
|
13
13
|
class Validator
|
14
14
|
# @param schema [GraphQL::Schema]
|
@@ -21,14 +21,18 @@ module GraphQL
|
|
21
21
|
# Validate `query` against the schema. Returns an array of message hashes.
|
22
22
|
# @param query [GraphQL::Query]
|
23
23
|
# @return [Array<Hash>]
|
24
|
-
def validate(query)
|
24
|
+
def validate(query, validate: true)
|
25
25
|
context = GraphQL::StaticValidation::ValidationContext.new(query)
|
26
26
|
rewrite = GraphQL::InternalRepresentation::Rewrite.new
|
27
27
|
|
28
28
|
# Put this first so its enters and exits are always called
|
29
29
|
rewrite.validate(context)
|
30
|
-
|
31
|
-
|
30
|
+
|
31
|
+
# If the caller opted out of validation, don't attach these
|
32
|
+
if validate
|
33
|
+
@rules.each do |rules|
|
34
|
+
rules.new.validate(context)
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
38
|
context.visitor.visit
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -31,6 +31,8 @@ $ bundle install
|
|
31
31
|
$ rails generate graphql:install
|
32
32
|
```
|
33
33
|
|
34
|
+
After this, you may need to run `bundle install` again, as by default graphiql-rails is added on installation.
|
35
|
+
|
34
36
|
Or, see ["Getting Started"](https://rmosolgo.github.io/graphql-ruby/).
|
35
37
|
|
36
38
|
## Upgrade
|
@@ -3,20 +3,19 @@ require "spec_helper"
|
|
3
3
|
require "generators/graphql/install_generator"
|
4
4
|
|
5
5
|
class GraphQLGeneratorsInstallGeneratorTest < Rails::Generators::TestCase
|
6
|
-
|
7
6
|
tests Graphql::Generators::InstallGenerator
|
8
7
|
destination File.expand_path("../../../tmp/dummy", File.dirname(__FILE__))
|
9
8
|
|
10
9
|
setup do
|
11
10
|
prepare_destination
|
12
|
-
|
13
|
-
|
11
|
+
|
12
|
+
FileUtils.cd(File.join(destination_root, '..')) do
|
14
13
|
`rails new dummy --skip-active-record --skip-test-unit --skip-spring --skip-bundle`
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
test "it generates a folder structure" do
|
19
|
-
run_generator
|
18
|
+
run_generator
|
20
19
|
|
21
20
|
assert_file "app/graphql/types/.keep"
|
22
21
|
assert_file "app/graphql/mutations/.keep"
|
@@ -93,6 +92,18 @@ RUBY
|
|
93
92
|
assert_file "app/graphql/dummy_schema.rb", EXPECTED_RELAY_BATCH_SCHEMA
|
94
93
|
end
|
95
94
|
|
95
|
+
test "it doesn't install graphiql when API Only" do
|
96
|
+
run_generator(['--api'])
|
97
|
+
|
98
|
+
assert_file "Gemfile" do |contents|
|
99
|
+
refute_includes contents, "graphiql-rails"
|
100
|
+
end
|
101
|
+
|
102
|
+
assert_file "config/routes.rb" do |contents|
|
103
|
+
refute_includes contents, "GraphiQL::Rails"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
96
107
|
test "it can skip keeps, skip graphiql and customize schema name" do
|
97
108
|
run_generator(["--skip-keeps", "--skip-graphiql", "--schema=CustomSchema"])
|
98
109
|
assert_no_file "app/graphql/types/.keep"
|
@@ -116,11 +127,12 @@ class GraphqlController < ApplicationController
|
|
116
127
|
def execute
|
117
128
|
variables = ensure_hash(params[:variables])
|
118
129
|
query = params[:query]
|
130
|
+
operation_name = params[:operationName]
|
119
131
|
context = {
|
120
132
|
# Query context goes here, for example:
|
121
133
|
# current_user: current_user,
|
122
134
|
}
|
123
|
-
result = DummySchema.execute(query, variables: variables, context: context)
|
135
|
+
result = DummySchema.execute(query, variables: variables, context: context, operation_name: operation_name)
|
124
136
|
render json: result
|
125
137
|
end
|
126
138
|
|
@@ -20,6 +20,19 @@ describe GraphQL::Query::LiteralInput do
|
|
20
20
|
end
|
21
21
|
resolve ->(t, a, c) { a[:value] }
|
22
22
|
end
|
23
|
+
|
24
|
+
field :fieldWithArgumentThatIsBadByDefault do
|
25
|
+
type types.Int
|
26
|
+
argument :value do
|
27
|
+
type types.Int
|
28
|
+
default_value 7
|
29
|
+
prepare ->(arg, ctx) do
|
30
|
+
GraphQL::ExecutionError.new("Always bad")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
resolve ->(*args) { 42 }
|
35
|
+
end
|
23
36
|
end
|
24
37
|
|
25
38
|
GraphQL::Schema.define(query: query)
|
@@ -35,6 +48,11 @@ describe GraphQL::Query::LiteralInput do
|
|
35
48
|
assert_equal(7, result["data"]["addToArgumentValue"])
|
36
49
|
end
|
37
50
|
|
51
|
+
it "raises an execution error if the default value is bad" do
|
52
|
+
result = schema.execute("{ fieldWithArgumentThatIsBadByDefault }", context: { })
|
53
|
+
assert_equal(result["errors"], [{"message" => "Always bad"}])
|
54
|
+
end
|
55
|
+
|
38
56
|
it "prepares values from variables" do
|
39
57
|
result = schema.execute("query ($value: Int!) { addToArgumentValue(value: $value) }", variables: { "value" => 1}, context: { val: 2 } )
|
40
58
|
assert_equal(result["data"]["addToArgumentValue"], 3)
|
data/spec/graphql/query_spec.rb
CHANGED
@@ -518,6 +518,27 @@ describe GraphQL::Query do
|
|
518
518
|
end
|
519
519
|
end
|
520
520
|
|
521
|
+
describe "validate: false" do
|
522
|
+
it "doesn't validate the query" do
|
523
|
+
invalid_query_string = "{ nonExistantField }"
|
524
|
+
# Can assign attribute
|
525
|
+
query = GraphQL::Query.new(schema, invalid_query_string)
|
526
|
+
query.validate = false
|
527
|
+
assert_equal true, query.valid?
|
528
|
+
assert_equal 0, query.static_errors.length
|
529
|
+
|
530
|
+
# Can pass keyword argument
|
531
|
+
query = GraphQL::Query.new(schema, invalid_query_string, validate: false)
|
532
|
+
assert_equal true, query.valid?
|
533
|
+
assert_equal 0, query.static_errors.length
|
534
|
+
|
535
|
+
# Can pass `true`
|
536
|
+
query = GraphQL::Query.new(schema, invalid_query_string, validate: true)
|
537
|
+
assert_equal false, query.valid?
|
538
|
+
assert_equal 1, query.static_errors.length
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
521
542
|
describe 'NullValue type arguments' do
|
522
543
|
let(:schema_definition) {
|
523
544
|
<<-GRAPHQL
|
@@ -19,11 +19,11 @@ schema {
|
|
19
19
|
}
|
20
20
|
|
21
21
|
type HelloScalars {
|
22
|
-
|
23
|
-
int: Int
|
22
|
+
bool: Boolean
|
24
23
|
float: Float
|
25
24
|
id: ID
|
26
|
-
|
25
|
+
int: Int
|
26
|
+
str: String!
|
27
27
|
}
|
28
28
|
SCHEMA
|
29
29
|
|
@@ -60,11 +60,11 @@ directive @foo(
|
|
60
60
|
|
61
61
|
# With an enum
|
62
62
|
enum Color {
|
63
|
-
|
63
|
+
BLUE
|
64
64
|
|
65
65
|
# Not a creative color
|
66
66
|
GREEN
|
67
|
-
|
67
|
+
RED
|
68
68
|
}
|
69
69
|
|
70
70
|
# What a great type
|
@@ -142,11 +142,11 @@ schema {
|
|
142
142
|
}
|
143
143
|
|
144
144
|
type HelloScalars {
|
145
|
-
nonNullStr: String!
|
146
|
-
listOfStrs: [String]
|
147
145
|
listOfNonNullStrs: [String!]
|
148
|
-
|
146
|
+
listOfStrs: [String]
|
149
147
|
nonNullListOfNonNullStrs: [String!]!
|
148
|
+
nonNullListOfStrs: [String]!
|
149
|
+
nonNullStr: String!
|
150
150
|
}
|
151
151
|
SCHEMA
|
152
152
|
|
@@ -160,8 +160,8 @@ schema {
|
|
160
160
|
}
|
161
161
|
|
162
162
|
type Recurse {
|
163
|
-
str: String
|
164
163
|
recurse: Recurse
|
164
|
+
str: String
|
165
165
|
}
|
166
166
|
SCHEMA
|
167
167
|
|
@@ -195,10 +195,10 @@ schema {
|
|
195
195
|
}
|
196
196
|
|
197
197
|
type Hello {
|
198
|
-
|
198
|
+
booleanToStr(bool: Boolean): String
|
199
199
|
floatToStr(float: Float): String
|
200
200
|
idToStr(id: ID): String
|
201
|
-
|
201
|
+
str(int: Int): String
|
202
202
|
strToStr(bool: String): String
|
203
203
|
}
|
204
204
|
SCHEMA
|
@@ -281,8 +281,8 @@ schema {
|
|
281
281
|
}
|
282
282
|
|
283
283
|
enum Hello {
|
284
|
-
WO
|
285
284
|
RLD
|
285
|
+
WO
|
286
286
|
}
|
287
287
|
|
288
288
|
type OutputEnumRoot {
|
@@ -382,14 +382,14 @@ schema {
|
|
382
382
|
}
|
383
383
|
|
384
384
|
enum Color {
|
385
|
-
RED
|
386
385
|
BLUE
|
386
|
+
RED
|
387
387
|
}
|
388
388
|
|
389
389
|
type Hello {
|
390
|
-
str(int: Int = 2): String
|
391
390
|
hello(color: Color = RED): String
|
392
391
|
nullable(color: Color = null): String
|
392
|
+
str(int: Int = 2): String
|
393
393
|
}
|
394
394
|
SCHEMA
|
395
395
|
|
@@ -404,9 +404,9 @@ schema {
|
|
404
404
|
}
|
405
405
|
|
406
406
|
type HelloScalars {
|
407
|
-
str: String
|
408
|
-
int: Int
|
409
407
|
bool: Boolean
|
408
|
+
int: Int
|
409
|
+
str: String
|
410
410
|
}
|
411
411
|
|
412
412
|
type Mutation {
|
@@ -420,8 +420,8 @@ type Mutation {
|
|
420
420
|
it 'supports simple type with mutation and default values' do
|
421
421
|
schema = <<-SCHEMA
|
422
422
|
enum Color {
|
423
|
-
RED
|
424
423
|
BLUE
|
424
|
+
RED
|
425
425
|
}
|
426
426
|
|
427
427
|
type Mutation {
|
@@ -444,9 +444,9 @@ schema {
|
|
444
444
|
}
|
445
445
|
|
446
446
|
type HelloScalars {
|
447
|
-
str: String
|
448
|
-
int: Int
|
449
447
|
bool: Boolean
|
448
|
+
int: Int
|
449
|
+
str: String
|
450
450
|
}
|
451
451
|
|
452
452
|
type Subscription {
|
@@ -494,15 +494,15 @@ union Union = Concrete
|
|
494
494
|
it 'supports @deprecated' do
|
495
495
|
schema = <<-SCHEMA
|
496
496
|
enum MyEnum {
|
497
|
-
VALUE
|
498
497
|
OLD_VALUE @deprecated
|
499
498
|
OTHER_VALUE @deprecated(reason: "Terrible reasons")
|
499
|
+
VALUE
|
500
500
|
}
|
501
501
|
|
502
502
|
type Query {
|
503
|
+
enum: MyEnum
|
503
504
|
field1: String @deprecated
|
504
505
|
field2: Int @deprecated(reason: "Because I said so")
|
505
|
-
enum: MyEnum
|
506
506
|
}
|
507
507
|
SCHEMA
|
508
508
|
|
@@ -136,13 +136,13 @@ schema {
|
|
136
136
|
query: Root
|
137
137
|
}
|
138
138
|
|
139
|
-
# Directs the executor to include this field or fragment only when the
|
139
|
+
# Directs the executor to include this field or fragment only when the `if` argument is true.
|
140
140
|
directive @include(
|
141
141
|
# Included when true.
|
142
142
|
if: Boolean!
|
143
143
|
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
144
144
|
|
145
|
-
# Directs the executor to skip this field or fragment when the
|
145
|
+
# Directs the executor to skip this field or fragment when the `if` argument is true.
|
146
146
|
directive @skip(
|
147
147
|
# Skipped when true.
|
148
148
|
if: Boolean!
|
@@ -163,30 +163,33 @@ directive @deprecated(
|
|
163
163
|
# skipping a field. Directives provide this by describing additional information
|
164
164
|
# to the executor.
|
165
165
|
type __Directive {
|
166
|
-
|
166
|
+
args: [__InputValue!]!
|
167
167
|
description: String
|
168
168
|
locations: [__DirectiveLocation!]!
|
169
|
-
|
170
|
-
|
171
|
-
onFragment: Boolean! @deprecated(reason: "Use
|
172
|
-
|
169
|
+
name: String!
|
170
|
+
onField: Boolean! @deprecated(reason: "Use `locations`.")
|
171
|
+
onFragment: Boolean! @deprecated(reason: "Use `locations`.")
|
172
|
+
onOperation: Boolean! @deprecated(reason: "Use `locations`.")
|
173
173
|
}
|
174
174
|
|
175
175
|
# A Directive can be adjacent to many parts of the GraphQL language, a
|
176
176
|
# __DirectiveLocation describes one such possible adjacencies.
|
177
177
|
enum __DirectiveLocation {
|
178
|
-
# Location adjacent to
|
179
|
-
|
178
|
+
# Location adjacent to an argument definition.
|
179
|
+
ARGUMENT_DEFINITION
|
180
180
|
|
181
|
-
# Location adjacent to
|
182
|
-
|
181
|
+
# Location adjacent to an enum definition.
|
182
|
+
ENUM
|
183
183
|
|
184
|
-
# Location adjacent to
|
185
|
-
|
184
|
+
# Location adjacent to an enum value definition.
|
185
|
+
ENUM_VALUE
|
186
186
|
|
187
187
|
# Location adjacent to a field.
|
188
188
|
FIELD
|
189
189
|
|
190
|
+
# Location adjacent to a field definition.
|
191
|
+
FIELD_DEFINITION
|
192
|
+
|
190
193
|
# Location adjacent to a fragment definition.
|
191
194
|
FRAGMENT_DEFINITION
|
192
195
|
|
@@ -196,95 +199,91 @@ enum __DirectiveLocation {
|
|
196
199
|
# Location adjacent to an inline fragment.
|
197
200
|
INLINE_FRAGMENT
|
198
201
|
|
199
|
-
# Location adjacent to
|
200
|
-
|
202
|
+
# Location adjacent to an input object field definition.
|
203
|
+
INPUT_FIELD_DEFINITION
|
201
204
|
|
202
|
-
# Location adjacent to
|
203
|
-
|
205
|
+
# Location adjacent to an input object type definition.
|
206
|
+
INPUT_OBJECT
|
207
|
+
|
208
|
+
# Location adjacent to an interface definition.
|
209
|
+
INTERFACE
|
210
|
+
|
211
|
+
# Location adjacent to a mutation operation.
|
212
|
+
MUTATION
|
204
213
|
|
205
214
|
# Location adjacent to an object type definition.
|
206
215
|
OBJECT
|
207
216
|
|
208
|
-
# Location adjacent to a
|
209
|
-
|
217
|
+
# Location adjacent to a query operation.
|
218
|
+
QUERY
|
210
219
|
|
211
|
-
# Location adjacent to
|
212
|
-
|
220
|
+
# Location adjacent to a scalar definition.
|
221
|
+
SCALAR
|
213
222
|
|
214
|
-
# Location adjacent to
|
215
|
-
|
223
|
+
# Location adjacent to a schema definition.
|
224
|
+
SCHEMA
|
225
|
+
|
226
|
+
# Location adjacent to a subscription operation.
|
227
|
+
SUBSCRIPTION
|
216
228
|
|
217
229
|
# Location adjacent to a union definition.
|
218
230
|
UNION
|
219
|
-
|
220
|
-
# Location adjacent to an enum definition.
|
221
|
-
ENUM
|
222
|
-
|
223
|
-
# Location adjacent to an enum value definition.
|
224
|
-
ENUM_VALUE
|
225
|
-
|
226
|
-
# Location adjacent to an input object type definition.
|
227
|
-
INPUT_OBJECT
|
228
|
-
|
229
|
-
# Location adjacent to an input object field definition.
|
230
|
-
INPUT_FIELD_DEFINITION
|
231
231
|
}
|
232
232
|
|
233
233
|
# One possible value for a given Enum. Enum values are unique values, not a
|
234
234
|
# placeholder for a string or numeric value. However an Enum value is returned in
|
235
235
|
# a JSON response as a string.
|
236
236
|
type __EnumValue {
|
237
|
-
|
237
|
+
deprecationReason: String
|
238
238
|
description: String
|
239
239
|
isDeprecated: Boolean!
|
240
|
-
|
240
|
+
name: String!
|
241
241
|
}
|
242
242
|
|
243
243
|
# Object and Interface types are described by a list of Fields, each of which has
|
244
244
|
# a name, potentially a list of arguments, and a return type.
|
245
245
|
type __Field {
|
246
|
-
name: String!
|
247
|
-
description: String
|
248
246
|
args: [__InputValue!]!
|
249
|
-
type: __Type!
|
250
|
-
isDeprecated: Boolean!
|
251
247
|
deprecationReason: String
|
248
|
+
description: String
|
249
|
+
isDeprecated: Boolean!
|
250
|
+
name: String!
|
251
|
+
type: __Type!
|
252
252
|
}
|
253
253
|
|
254
254
|
# Arguments provided to Fields or Directives and the input fields of an
|
255
255
|
# InputObject are represented as Input Values which describe their type and
|
256
256
|
# optionally a default value.
|
257
257
|
type __InputValue {
|
258
|
-
name: String!
|
259
|
-
description: String
|
260
|
-
type: __Type!
|
261
|
-
|
262
258
|
# A GraphQL-formatted string representing the default value for this input value.
|
263
259
|
defaultValue: String
|
260
|
+
description: String
|
261
|
+
name: String!
|
262
|
+
type: __Type!
|
264
263
|
}
|
265
264
|
|
266
265
|
# A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
|
267
266
|
# available types and directives on the server, as well as the entry points for
|
268
267
|
# query, mutation, and subscription operations.
|
269
268
|
type __Schema {
|
270
|
-
# A list of all
|
271
|
-
|
272
|
-
|
273
|
-
# The type that query operations will be rooted at.
|
274
|
-
queryType: __Type!
|
269
|
+
# A list of all directives supported by this server.
|
270
|
+
directives: [__Directive!]!
|
275
271
|
|
276
272
|
# If this server supports mutation, the type that mutation operations will be rooted at.
|
277
273
|
mutationType: __Type
|
278
274
|
|
275
|
+
# The type that query operations will be rooted at.
|
276
|
+
queryType: __Type!
|
277
|
+
|
279
278
|
# If this server support subscription, the type that subscription operations will be rooted at.
|
280
279
|
subscriptionType: __Type
|
281
280
|
|
282
|
-
# A list of all
|
283
|
-
|
281
|
+
# A list of all types supported by this server.
|
282
|
+
types: [__Type!]!
|
284
283
|
}
|
285
284
|
|
286
285
|
# The fundamental unit of any GraphQL Schema is the type. There are many kinds of
|
287
|
-
# types in GraphQL as represented by the
|
286
|
+
# types in GraphQL as represented by the `__TypeKind` enum.
|
288
287
|
#
|
289
288
|
# Depending on the kind of a type, certain fields describe information about that
|
290
289
|
# type. Scalar types provide no information beyond a name and description, while
|
@@ -292,42 +291,42 @@ type __Schema {
|
|
292
291
|
# they describe. Abstract types, Union and Interface, provide the Object types
|
293
292
|
# possible at runtime. List and NonNull types compose other types.
|
294
293
|
type __Type {
|
295
|
-
kind: __TypeKind!
|
296
|
-
name: String
|
297
294
|
description: String
|
298
|
-
fields(includeDeprecated: Boolean = false): [__Field!]
|
299
|
-
interfaces: [__Type!]
|
300
|
-
possibleTypes: [__Type!]
|
301
295
|
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
|
296
|
+
fields(includeDeprecated: Boolean = false): [__Field!]
|
302
297
|
inputFields: [__InputValue!]
|
298
|
+
interfaces: [__Type!]
|
299
|
+
kind: __TypeKind!
|
300
|
+
name: String
|
303
301
|
ofType: __Type
|
302
|
+
possibleTypes: [__Type!]
|
304
303
|
}
|
305
304
|
|
306
|
-
# An enum describing what kind of type a given
|
305
|
+
# An enum describing what kind of type a given `__Type` is.
|
307
306
|
enum __TypeKind {
|
308
|
-
# Indicates this type is a
|
309
|
-
|
307
|
+
# Indicates this type is an enum. `enumValues` is a valid field.
|
308
|
+
ENUM
|
310
309
|
|
311
|
-
# Indicates this type is an object.
|
312
|
-
|
310
|
+
# Indicates this type is an input object. `inputFields` is a valid field.
|
311
|
+
INPUT_OBJECT
|
313
312
|
|
314
|
-
# Indicates this type is an interface.
|
313
|
+
# Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
|
315
314
|
INTERFACE
|
316
315
|
|
317
|
-
# Indicates this type is a
|
318
|
-
|
316
|
+
# Indicates this type is a list. `ofType` is a valid field.
|
317
|
+
LIST
|
319
318
|
|
320
|
-
# Indicates this type is
|
321
|
-
|
319
|
+
# Indicates this type is a non-null. `ofType` is a valid field.
|
320
|
+
NON_NULL
|
322
321
|
|
323
|
-
# Indicates this type is an
|
324
|
-
|
322
|
+
# Indicates this type is an object. `fields` and `interfaces` are valid fields.
|
323
|
+
OBJECT
|
325
324
|
|
326
|
-
# Indicates this type is a
|
327
|
-
|
325
|
+
# Indicates this type is a scalar.
|
326
|
+
SCALAR
|
328
327
|
|
329
|
-
# Indicates this type is a
|
330
|
-
|
328
|
+
# Indicates this type is a union. `possibleTypes` is a valid field.
|
329
|
+
UNION
|
331
330
|
}
|
332
331
|
SCHEMA
|
333
332
|
assert_equal expected.chomp, GraphQL::Schema::Printer.print_introspection_schema
|
@@ -384,15 +383,15 @@ SCHEMA
|
|
384
383
|
it "returns the schema as a string for the defined types" do
|
385
384
|
expected = <<SCHEMA
|
386
385
|
type Audio {
|
386
|
+
duration: Int!
|
387
387
|
id: ID!
|
388
388
|
name: String!
|
389
|
-
duration: Int!
|
390
389
|
}
|
391
390
|
|
392
391
|
enum Choice {
|
393
|
-
FOO
|
394
392
|
BAR
|
395
393
|
BAZ @deprecated(reason: "Use \\\"BAR\\\".")
|
394
|
+
FOO
|
396
395
|
WOZ @deprecated
|
397
396
|
}
|
398
397
|
|
@@ -403,10 +402,11 @@ type Comment implements Node {
|
|
403
402
|
|
404
403
|
# Autogenerated input type of CreatePost
|
405
404
|
input CreatePostInput {
|
405
|
+
body: String!
|
406
|
+
|
406
407
|
# A unique identifier for the client performing the mutation.
|
407
408
|
clientMutationId: String
|
408
409
|
title: String!
|
409
|
-
body: String!
|
410
410
|
}
|
411
411
|
|
412
412
|
# Autogenerated return type of CreatePost
|
@@ -417,14 +417,14 @@ type CreatePostPayload {
|
|
417
417
|
}
|
418
418
|
|
419
419
|
type Image {
|
420
|
+
height: Int!
|
420
421
|
id: ID!
|
421
422
|
name: String!
|
422
423
|
width: Int!
|
423
|
-
height: Int!
|
424
424
|
}
|
425
425
|
|
426
426
|
# Media objects
|
427
|
-
union Media =
|
427
|
+
union Media = Audio | Image
|
428
428
|
|
429
429
|
type Mutation {
|
430
430
|
# Create a blog post
|
@@ -437,11 +437,11 @@ interface Node {
|
|
437
437
|
|
438
438
|
# A blog post
|
439
439
|
type Post {
|
440
|
-
id: ID!
|
441
|
-
title: String!
|
442
440
|
body: String!
|
443
441
|
comments: [Comment!]
|
444
|
-
comments_count: Int! @deprecated(reason:
|
442
|
+
comments_count: Int! @deprecated(reason: "Use \\\"comments\\\".")
|
443
|
+
id: ID!
|
444
|
+
title: String!
|
445
445
|
}
|
446
446
|
|
447
447
|
# The query root of this schema
|
@@ -449,7 +449,7 @@ type Query {
|
|
449
449
|
post(
|
450
450
|
# Post ID
|
451
451
|
id: ID!
|
452
|
-
varied: Varied = {id:
|
452
|
+
varied: Varied = {id: "123", int: 234, float: 2.3, enum: FOO, sub: [{string: "str"}]}
|
453
453
|
variedWithNulls: Varied = {id: null, int: null, float: null, enum: null, sub: null}
|
454
454
|
): Post
|
455
455
|
}
|
@@ -457,10 +457,10 @@ type Query {
|
|
457
457
|
# Test
|
458
458
|
input Sub {
|
459
459
|
# Something
|
460
|
-
|
460
|
+
int: Int
|
461
461
|
|
462
462
|
# Something
|
463
|
-
|
463
|
+
string: String
|
464
464
|
}
|
465
465
|
|
466
466
|
type Subscription {
|
@@ -468,14 +468,15 @@ type Subscription {
|
|
468
468
|
}
|
469
469
|
|
470
470
|
input Varied {
|
471
|
-
id: ID
|
472
|
-
int: Int
|
473
|
-
float: Float
|
474
471
|
bool: Boolean
|
475
472
|
enum: Choice = FOO
|
473
|
+
float: Float
|
474
|
+
id: ID
|
475
|
+
int: Int
|
476
476
|
sub: [Sub]
|
477
477
|
}
|
478
478
|
SCHEMA
|
479
|
+
|
479
480
|
assert_equal expected.chomp, GraphQL::Schema::Printer.print_schema(schema)
|
480
481
|
end
|
481
482
|
end
|
@@ -483,8 +484,8 @@ SCHEMA
|
|
483
484
|
it "applies an `only` filter" do
|
484
485
|
expected = <<SCHEMA
|
485
486
|
enum Choice {
|
486
|
-
FOO
|
487
487
|
BAR
|
488
|
+
FOO
|
488
489
|
}
|
489
490
|
|
490
491
|
type Subscription {
|
@@ -492,10 +493,10 @@ type Subscription {
|
|
492
493
|
}
|
493
494
|
|
494
495
|
input Varied {
|
495
|
-
int: Int
|
496
|
-
float: Float
|
497
496
|
bool: Boolean
|
498
497
|
enum: Choice = FOO
|
498
|
+
float: Float
|
499
|
+
int: Int
|
499
500
|
}
|
500
501
|
SCHEMA
|
501
502
|
|
@@ -520,14 +521,14 @@ SCHEMA
|
|
520
521
|
it "applies an `except` filter" do
|
521
522
|
expected = <<SCHEMA
|
522
523
|
type Audio {
|
524
|
+
duration: Int!
|
523
525
|
id: ID!
|
524
526
|
name: String!
|
525
|
-
duration: Int!
|
526
527
|
}
|
527
528
|
|
528
529
|
enum Choice {
|
529
|
-
FOO
|
530
530
|
BAR
|
531
|
+
FOO
|
531
532
|
}
|
532
533
|
|
533
534
|
# A blog comment
|
@@ -537,10 +538,11 @@ type Comment implements Node {
|
|
537
538
|
|
538
539
|
# Autogenerated input type of CreatePost
|
539
540
|
input CreatePostInput {
|
541
|
+
body: String!
|
542
|
+
|
540
543
|
# A unique identifier for the client performing the mutation.
|
541
544
|
clientMutationId: String
|
542
545
|
title: String!
|
543
|
-
body: String!
|
544
546
|
}
|
545
547
|
|
546
548
|
# Autogenerated return type of CreatePost
|
@@ -564,10 +566,10 @@ interface Node {
|
|
564
566
|
|
565
567
|
# A blog post
|
566
568
|
type Post {
|
567
|
-
id: ID!
|
568
|
-
title: String!
|
569
569
|
body: String!
|
570
570
|
comments: [Comment!]
|
571
|
+
id: ID!
|
572
|
+
title: String!
|
571
573
|
}
|
572
574
|
|
573
575
|
# The query root of this schema
|
@@ -596,11 +598,11 @@ SCHEMA
|
|
596
598
|
expected = <<SCHEMA
|
597
599
|
# A blog post
|
598
600
|
type Post {
|
599
|
-
id: ID!
|
600
|
-
title: String!
|
601
601
|
body: String!
|
602
602
|
comments: [Comment!]
|
603
603
|
comments_count: Int! @deprecated(reason: \"Use \\\"comments\\\".\")
|
604
|
+
id: ID!
|
605
|
+
title: String!
|
604
606
|
}
|
605
607
|
SCHEMA
|
606
608
|
assert_equal expected.chomp, GraphQL::Schema::Printer.new(schema).print_type(schema.types['Post'])
|
@@ -4,7 +4,8 @@ require "spec_helper"
|
|
4
4
|
describe GraphQL::StaticValidation::Validator do
|
5
5
|
let(:validator) { GraphQL::StaticValidation::Validator.new(schema: Dummy::Schema) }
|
6
6
|
let(:query) { GraphQL::Query.new(Dummy::Schema, query_string) }
|
7
|
-
let(:
|
7
|
+
let(:validate) { true }
|
8
|
+
let(:errors) { validator.validate(query, validate: validate)[:errors].map(&:to_h) }
|
8
9
|
|
9
10
|
|
10
11
|
describe "validation order" do
|
@@ -30,6 +31,14 @@ describe GraphQL::StaticValidation::Validator do
|
|
30
31
|
# nonsenseField, nonsenseArg, bogusField, bogusArg, undefinedVar
|
31
32
|
assert_equal(5, errors.length)
|
32
33
|
end
|
34
|
+
|
35
|
+
describe "when validate: false" do
|
36
|
+
let(:validate) { false }
|
37
|
+
|
38
|
+
it "skips validation" do
|
39
|
+
assert_equal 0, errors.length
|
40
|
+
end
|
41
|
+
end
|
33
42
|
end
|
34
43
|
|
35
44
|
describe "infinite fragments" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|