graphql 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/define/assign_argument.rb +3 -5
- data/lib/graphql/field.rb +1 -3
- data/lib/graphql/input_object_type.rb +4 -1
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/generation.rb +94 -0
- data/lib/graphql/language/lexer.rb +229 -201
- data/lib/graphql/language/lexer.rl +24 -7
- data/lib/graphql/language/nodes.rb +4 -0
- data/lib/graphql/language/parser.rb +195 -187
- data/lib/graphql/language/parser.y +11 -4
- data/lib/graphql/object_type.rb +21 -0
- data/lib/graphql/query.rb +8 -3
- data/lib/graphql/query/serial_execution/operation_resolution.rb +2 -2
- data/lib/graphql/query/serial_execution/value_resolution.rb +5 -0
- data/lib/graphql/schema.rb +11 -19
- data/lib/graphql/schema/invalid_type_error.rb +6 -0
- data/lib/graphql/schema/reduce_types.rb +68 -0
- data/lib/graphql/schema/type_expression.rb +6 -16
- data/lib/graphql/schema/type_map.rb +1 -5
- data/lib/graphql/schema/validation.rb +164 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +3 -4
- data/spec/graphql/argument_spec.rb +20 -0
- data/spec/graphql/field_spec.rb +16 -0
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/language/generation_spec.rb +42 -0
- data/spec/graphql/language/parser_spec.rb +136 -26
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +23 -0
- data/spec/graphql/query_spec.rb +51 -0
- data/spec/graphql/schema/{type_reducer_spec.rb → reduce_types_spec.rb} +16 -14
- data/spec/graphql/schema/type_expression_spec.rb +4 -4
- data/spec/graphql/schema/validation_spec.rb +219 -0
- data/spec/support/dairy_app.rb +3 -0
- metadata +14 -13
- data/lib/graphql/schema/each_item_validator.rb +0 -21
- data/lib/graphql/schema/field_validator.rb +0 -17
- data/lib/graphql/schema/implementation_validator.rb +0 -31
- data/lib/graphql/schema/type_reducer.rb +0 -79
- data/lib/graphql/schema/type_validator.rb +0 -58
- data/spec/graphql/schema/field_validator_spec.rb +0 -21
- data/spec/graphql/schema/type_validator_spec.rb +0 -81
@@ -108,11 +108,14 @@ rule
|
|
108
108
|
}
|
109
109
|
|
110
110
|
name:
|
111
|
+
name_without_on
|
112
|
+
| ON
|
113
|
+
|
114
|
+
name_without_on:
|
111
115
|
IDENTIFIER
|
112
116
|
| FRAGMENT
|
113
117
|
| TRUE
|
114
118
|
| FALSE
|
115
|
-
| ON
|
116
119
|
|
117
120
|
arguments_opt:
|
118
121
|
/* none */ { return [] }
|
@@ -171,7 +174,7 @@ rule
|
|
171
174
|
directive: DIR_SIGN name arguments_opt { return make_node(:Directive, name: val[1], arguments: val[2], position_source: val[0]) }
|
172
175
|
|
173
176
|
fragment_spread:
|
174
|
-
ELLIPSIS
|
177
|
+
ELLIPSIS name_without_on directives_list_opt { return make_node(:FragmentSpread, name: val[1], directives: val[2], position_source: val[0]) }
|
175
178
|
|
176
179
|
inline_fragment:
|
177
180
|
ELLIPSIS ON name directives_list_opt selection_set {
|
@@ -192,7 +195,7 @@ rule
|
|
192
195
|
}
|
193
196
|
|
194
197
|
fragment_definition:
|
195
|
-
FRAGMENT name ON
|
198
|
+
FRAGMENT name ON name_without_on directives_list_opt selection_set {
|
196
199
|
return make_node(:FragmentDefinition, {
|
197
200
|
name: val[1],
|
198
201
|
type: val[3],
|
@@ -248,7 +251,11 @@ def on_error(parser_token_id, lexer_token, vstack)
|
|
248
251
|
raise GraphQL::ParseError.new("Parse Error on unknown token: {token_id: #{parser_token_id}, lexer_token: #{lexer_token}} from #{@query_string}", nil, nil, @query_string)
|
249
252
|
else
|
250
253
|
line, col = lexer_token.line_and_column
|
251
|
-
|
254
|
+
if lexer_token.name == :BAD_UNICODE_ESCAPE
|
255
|
+
raise GraphQL::ParseError.new("Parse error on bad Unicode escape sequence: #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string)
|
256
|
+
else
|
257
|
+
raise GraphQL::ParseError.new("Parse error on #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string)
|
258
|
+
end
|
252
259
|
end
|
253
260
|
end
|
254
261
|
end
|
data/lib/graphql/object_type.rb
CHANGED
@@ -59,5 +59,26 @@ module GraphQL
|
|
59
59
|
memo.merge!(iface.fields)
|
60
60
|
end
|
61
61
|
end
|
62
|
+
|
63
|
+
|
64
|
+
# Error raised when the value provided for a field can't be resolved to one of the possible types
|
65
|
+
# for the field.
|
66
|
+
class UnresolvedTypeError < GraphQL::Error
|
67
|
+
attr_reader :field_name, :field_type, :parent_type
|
68
|
+
|
69
|
+
def initialize(field_name, field_type, parent_type)
|
70
|
+
@field_name = field_name
|
71
|
+
@field_type = field_type
|
72
|
+
@parent_type = parent_type
|
73
|
+
super(exception_message)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def exception_message
|
79
|
+
"The value returned for field #{field_name} on #{parent_type} could not be resolved "\
|
80
|
+
"to one of the possible types for #{field_type}."
|
81
|
+
end
|
82
|
+
end
|
62
83
|
end
|
63
84
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -8,7 +8,7 @@ module GraphQL
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
attr_reader :schema, :document, :context, :fragments, :operations, :debug, :max_depth
|
11
|
+
attr_reader :schema, :document, :context, :fragments, :operations, :debug, :root_value, :max_depth
|
12
12
|
|
13
13
|
# Prepare query `query_string` on `schema`
|
14
14
|
# @param schema [GraphQL::Schema]
|
@@ -18,17 +18,22 @@ module GraphQL
|
|
18
18
|
# @param debug [Boolean] if true, errors are raised, if false, errors are put in the `errors` key
|
19
19
|
# @param validate [Boolean] if true, `query_string` will be validated with {StaticValidation::Validator}
|
20
20
|
# @param operation_name [String] if the query string contains many operations, this is the one which should be executed
|
21
|
-
|
21
|
+
# @param root_value [Object] the object used to resolve fields on the root type
|
22
|
+
def initialize(schema, query_string = nil, document: nil, context: nil, variables: {}, debug: false, validate: true, operation_name: nil, root_value: nil, max_depth: nil)
|
23
|
+
fail ArgumentError, "a query string or document is required" unless query_string || document
|
24
|
+
|
22
25
|
@schema = schema
|
23
26
|
@debug = debug
|
24
27
|
@max_depth = max_depth || schema.max_depth
|
25
28
|
@context = Context.new(query: self, values: context)
|
29
|
+
@root_value = root_value
|
26
30
|
@validate = validate
|
27
31
|
@operation_name = operation_name
|
28
32
|
@fragments = {}
|
29
33
|
@operations = {}
|
30
34
|
@provided_variables = variables
|
31
|
-
|
35
|
+
|
36
|
+
@document = document || GraphQL.parse(query_string)
|
32
37
|
@document.definitions.each do |part|
|
33
38
|
if part.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
34
39
|
@fragments[part.name] = part
|
@@ -2,7 +2,7 @@ module GraphQL
|
|
2
2
|
class Query
|
3
3
|
class SerialExecution
|
4
4
|
class OperationResolution
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :target, :ast_operation_definition, :execution_context
|
6
6
|
|
7
7
|
def initialize(ast_operation_definition, target, execution_context)
|
8
8
|
@ast_operation_definition = ast_operation_definition
|
@@ -13,7 +13,7 @@ module GraphQL
|
|
13
13
|
def result
|
14
14
|
selections = ast_operation_definition.selections
|
15
15
|
execution_context.strategy.selection_resolution.new(
|
16
|
-
|
16
|
+
execution_context.query.root_value,
|
17
17
|
target,
|
18
18
|
selections,
|
19
19
|
execution_context
|
@@ -55,6 +55,11 @@ module GraphQL
|
|
55
55
|
class HasPossibleTypeResolution < BaseResolution
|
56
56
|
def non_null_result
|
57
57
|
resolved_type = field_type.resolve_type(value, execution_context)
|
58
|
+
|
59
|
+
unless resolved_type.is_a?(GraphQL::ObjectType)
|
60
|
+
raise GraphQL::ObjectType::UnresolvedTypeError.new(ast_field.name, field_type, parent_type)
|
61
|
+
end
|
62
|
+
|
58
63
|
strategy_class = get_strategy_for_kind(resolved_type.kind)
|
59
64
|
inner_strategy = strategy_class.new(value, resolved_type, target, parent_type, ast_field, execution_context)
|
60
65
|
inner_strategy.result
|
data/lib/graphql/schema.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
require "graphql/schema/invalid_type_error"
|
2
|
+
require "graphql/schema/middleware_chain"
|
3
|
+
require "graphql/schema/rescue_middleware"
|
4
|
+
require "graphql/schema/possible_types"
|
5
|
+
require "graphql/schema/reduce_types"
|
6
|
+
require "graphql/schema/type_expression"
|
7
|
+
require "graphql/schema/type_map"
|
8
|
+
require "graphql/schema/validation"
|
9
|
+
|
1
10
|
module GraphQL
|
2
11
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
3
12
|
class Schema
|
@@ -43,7 +52,7 @@ module GraphQL
|
|
43
52
|
def types
|
44
53
|
@types ||= begin
|
45
54
|
all_types = @orphan_types + [query, mutation, GraphQL::Introspection::SchemaType]
|
46
|
-
|
55
|
+
GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
@@ -73,7 +82,7 @@ module GraphQL
|
|
73
82
|
end
|
74
83
|
|
75
84
|
def type_from_ast(ast_node)
|
76
|
-
GraphQL::Schema::TypeExpression.
|
85
|
+
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
77
86
|
end
|
78
87
|
|
79
88
|
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
@@ -82,22 +91,5 @@ module GraphQL
|
|
82
91
|
@interface_possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
83
92
|
@interface_possible_types.possible_types(type_defn)
|
84
93
|
end
|
85
|
-
|
86
|
-
class InvalidTypeError < GraphQL::Error
|
87
|
-
def initialize(type, name)
|
88
|
-
super("#{name} has an invalid type: must be an instance of GraphQL::BaseType, not #{type.class.inspect} (#{type.inspect})")
|
89
|
-
end
|
90
|
-
end
|
91
94
|
end
|
92
95
|
end
|
93
|
-
|
94
|
-
require "graphql/schema/each_item_validator"
|
95
|
-
require "graphql/schema/field_validator"
|
96
|
-
require "graphql/schema/implementation_validator"
|
97
|
-
require "graphql/schema/middleware_chain"
|
98
|
-
require "graphql/schema/rescue_middleware"
|
99
|
-
require "graphql/schema/possible_types"
|
100
|
-
require "graphql/schema/type_expression"
|
101
|
-
require "graphql/schema/type_reducer"
|
102
|
-
require "graphql/schema/type_map"
|
103
|
-
require "graphql/schema/type_validator"
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Schema
|
3
|
+
module ReduceTypes
|
4
|
+
# @param types [Array<GraphQL::BaseType>] members of a schema to crawl for all member types
|
5
|
+
# @return [GraphQL::Schema::TypeMap] `{name => Type}` pairs derived from `types`
|
6
|
+
def self.reduce(types)
|
7
|
+
type_map = GraphQL::Schema::TypeMap.new
|
8
|
+
types.each do |type|
|
9
|
+
reduce_type(type, type_map, type.name)
|
10
|
+
end
|
11
|
+
type_map
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Based on `type`, add members to `type_hash`.
|
17
|
+
# If `type` has already been visited, just return the `type_hash` as-is
|
18
|
+
def self.reduce_type(type, type_hash, context_description)
|
19
|
+
if !type.is_a?(GraphQL::BaseType)
|
20
|
+
message = "#{context_description} has an invalid type: must be an instance of GraphQL::BaseType, not #{type.class.inspect} (#{type.inspect})"
|
21
|
+
raise GraphQL::Schema::InvalidTypeError.new(message)
|
22
|
+
end
|
23
|
+
|
24
|
+
type = type.unwrap
|
25
|
+
|
26
|
+
# Don't re-visit a type
|
27
|
+
if !type_hash.fetch(type.name, nil).equal?(type)
|
28
|
+
validate_type(type, context_description)
|
29
|
+
type_hash[type.name] = type
|
30
|
+
crawl_type(type, type_hash, context_description)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.crawl_type(type, type_hash, context_description)
|
35
|
+
if type.kind.fields?
|
36
|
+
type.all_fields.each do |field|
|
37
|
+
reduce_type(field.type, type_hash, "Field #{type.name}.#{field.name}")
|
38
|
+
field.arguments.each do |name, argument|
|
39
|
+
reduce_type(argument.type, type_hash, "Argument #{name} on #{type.name}.#{field.name}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
if type.kind.object?
|
44
|
+
type.interfaces.each do |interface|
|
45
|
+
reduce_type(interface, type_hash, "Interface on #{type.name}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
if type.kind.union?
|
49
|
+
type.possible_types.each do |possible_type|
|
50
|
+
reduce_type(possible_type, type_hash, "Possible type for #{type.name}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if type.kind.input_object?
|
54
|
+
type.arguments.each do |argument_name, argument|
|
55
|
+
reduce_type(argument.type, type_hash, "Input field #{type.name}.#{argument_name}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.validate_type(type, context_description)
|
61
|
+
error_message = GraphQL::Schema::Validation.validate(type)
|
62
|
+
if error_message
|
63
|
+
raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -1,25 +1,15 @@
|
|
1
1
|
module GraphQL
|
2
2
|
class Schema
|
3
|
-
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
def type
|
10
|
-
@type ||= build_type(@schema, @ast_node)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def build_type(schema, ast_node)
|
16
|
-
if ast_node.is_a?(GraphQL::Language::Nodes::TypeName)
|
3
|
+
module TypeExpression
|
4
|
+
def self.build_type(schema, ast_node)
|
5
|
+
case ast_node
|
6
|
+
when GraphQL::Language::Nodes::TypeName
|
17
7
|
type_name = ast_node.name
|
18
8
|
schema.types[type_name]
|
19
|
-
|
9
|
+
when GraphQL::Language::Nodes::NonNullType
|
20
10
|
ast_inner_type = ast_node.of_type
|
21
11
|
build_type(schema, ast_inner_type).to_non_null_type
|
22
|
-
|
12
|
+
when GraphQL::Language::Nodes::ListType
|
23
13
|
ast_inner_type = ast_node.of_type
|
24
14
|
build_type(schema, ast_inner_type).to_list_type
|
25
15
|
end
|
@@ -8,7 +8,7 @@ module GraphQL
|
|
8
8
|
# If you want a type, but want to handle the undefined case, use {#fetch}.
|
9
9
|
class TypeMap
|
10
10
|
extend Forwardable
|
11
|
-
def_delegators :@storage, :key?, :keys, :values
|
11
|
+
def_delegators :@storage, :key?, :keys, :values, :to_h, :fetch
|
12
12
|
|
13
13
|
def initialize
|
14
14
|
@storage = {}
|
@@ -25,10 +25,6 @@ module GraphQL
|
|
25
25
|
@storage[key] = value
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
def fetch(key, fallback_value)
|
30
|
-
@storage.key?(key) ? @storage[key] : fallback_value
|
31
|
-
end
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Schema
|
3
|
+
# This module provides a function for validating GraphQL types.
|
4
|
+
#
|
5
|
+
# Its {RULES} contain objects that respond to `#call(type)`. Rules are
|
6
|
+
# looked up for given types (by class ancestry), then applied to
|
7
|
+
# the object until an error is returned.
|
8
|
+
class Validation
|
9
|
+
# Lookup the rules for `object` based on its class,
|
10
|
+
# Then returns an error message or `nil`
|
11
|
+
# @param object [Object] something to be validated
|
12
|
+
# @return [String, Nil] error message, if there was one
|
13
|
+
def self.validate(object)
|
14
|
+
rules = RULES.reduce([]) do |memo, (parent_class, validations)|
|
15
|
+
memo + (object.is_a?(parent_class) ? validations : [])
|
16
|
+
end
|
17
|
+
# Stops after the first error
|
18
|
+
rules.reduce(nil) { |memo, rule| memo || rule.call(object) }
|
19
|
+
end
|
20
|
+
|
21
|
+
module Rules
|
22
|
+
# @param property_name [Symbol] The method to validate
|
23
|
+
# @param allowed_classes [Class] Classes which the return value may be an instance of
|
24
|
+
# @return [Proc] A proc which will validate the input by calling `property_name` and asserting it is an instance of one of `allowed_classes`
|
25
|
+
def self.assert_property(property_name, *allowed_classes)
|
26
|
+
allowed_classes_message = allowed_classes.map(&:name).join(" or ")
|
27
|
+
-> (obj) {
|
28
|
+
property_value = obj.public_send(property_name)
|
29
|
+
is_valid_value = allowed_classes.any? { |allowed_class| property_value.is_a?(allowed_class) }
|
30
|
+
is_valid_value ? nil : "#{property_name} must return #{allowed_classes_message}, not #{property_value.class.name} (#{property_value.inspect})"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param property_name [Symbol] The method whose return value will be validated
|
35
|
+
# @param from_class [Class] The class for keys in the return value
|
36
|
+
# @param to_class [Class] The class for values in the return value
|
37
|
+
# @return [Proc] A proc to validate that validates the input by calling `property_name` and asserting that the return value is a Hash of `{from_class => to_class}` pairs
|
38
|
+
def self.assert_property_mapping(property_name, from_class, to_class)
|
39
|
+
-> (obj) {
|
40
|
+
property_value = obj.public_send(property_name)
|
41
|
+
error_message = nil
|
42
|
+
if !property_value.is_a?(Hash)
|
43
|
+
"#{property_name} must be a hash of {#{from_class.name} => #{to_class.name}}, not a #{property_value.class.name} (#{property_value.inspect})"
|
44
|
+
else
|
45
|
+
invalid_key, invalid_value = property_value.find { |key, value| !key.is_a?(from_class) || !value.is_a?(to_class) }
|
46
|
+
if invalid_key
|
47
|
+
"#{property_name} must map #{from_class} => #{to_class}, not #{invalid_key.class.name} => #{invalid_value.class.name} (#{invalid_key.inspect} => #{invalid_value.inspect})"
|
48
|
+
else
|
49
|
+
nil # OK
|
50
|
+
end
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param property_name [Symbol] The method whose return value will be validated
|
56
|
+
# @param list_member_class [Class] The class which each member of the returned array should be an instance of
|
57
|
+
# @return [Proc] A proc to validate the input by calling `property_name` and asserting that the return is an Array of `list_member_class` instances
|
58
|
+
def self.assert_property_list_of(property_name, list_member_class)
|
59
|
+
-> (obj) {
|
60
|
+
property_value = obj.public_send(property_name)
|
61
|
+
if !property_value.is_a?(Array)
|
62
|
+
"#{property_name} must be an Array of #{list_member_class.name}, not a #{property_value.class.name} (#{property_value.inspect})"
|
63
|
+
else
|
64
|
+
invalid_member = property_value.find { |value| !value.is_a?(list_member_class) }
|
65
|
+
if invalid_member
|
66
|
+
"#{property_name} must contain #{list_member_class.name}, not #{invalid_member.class.name} (#{invalid_member.inspect})"
|
67
|
+
else
|
68
|
+
nil # OK
|
69
|
+
end
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.assert_named_items_are_valid(item_name, get_items_proc)
|
75
|
+
-> (type) {
|
76
|
+
items = get_items_proc.call(type)
|
77
|
+
error_message = nil
|
78
|
+
items.each do |item|
|
79
|
+
item_message = GraphQL::Schema::Validation.validate(item)
|
80
|
+
if item_message
|
81
|
+
error_message = "#{item_name} #{item.name.inspect} #{item_message}"
|
82
|
+
break
|
83
|
+
end
|
84
|
+
end
|
85
|
+
error_message
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
FIELDS_ARE_VALID = Rules.assert_named_items_are_valid("field", -> (type) { type.all_fields })
|
91
|
+
|
92
|
+
HAS_ONE_OR_MORE_POSSIBLE_TYPES = -> (type) {
|
93
|
+
type.possible_types.length > 1 ? nil : "must have at least one possible type"
|
94
|
+
}
|
95
|
+
|
96
|
+
NAME_IS_STRING = Rules.assert_property(:name, String)
|
97
|
+
DESCRIPTION_IS_STRING_OR_NIL = Rules.assert_property(:description, String, NilClass)
|
98
|
+
ARGUMENTS_ARE_STRING_TO_ARGUMENT = Rules.assert_property_mapping(:arguments, String, GraphQL::Argument)
|
99
|
+
ARGUMENTS_ARE_VALID = Rules.assert_named_items_are_valid("argument", -> (type) { type.arguments.values })
|
100
|
+
|
101
|
+
DEFAULT_VALUE_IS_VALID_FOR_TYPE = -> (type) {
|
102
|
+
if !type.default_value.nil?
|
103
|
+
coerced_value = type.type.coerce_input(type.default_value)
|
104
|
+
if coerced_value.nil?
|
105
|
+
"default value #{type.default_value.inspect} is not valid for type #{type.type}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
}
|
109
|
+
|
110
|
+
TYPE_IS_VALID_INPUT_TYPE = -> (type) {
|
111
|
+
outer_type = type.type
|
112
|
+
inner_type = outer_type.is_a?(GraphQL::BaseType) ? outer_type.unwrap : nil
|
113
|
+
|
114
|
+
case inner_type
|
115
|
+
when GraphQL::ScalarType, GraphQL::InputObjectType, GraphQL::EnumType
|
116
|
+
# OK
|
117
|
+
else
|
118
|
+
"type must be a valid input type (Scalar or InputObject), not #{outer_type.class} (#{outer_type})"
|
119
|
+
end
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
# A mapping of `{Class => [Proc, Proc...]}` pairs.
|
124
|
+
# To validate an instance, find entries where `object.is_a?(key)` is true.
|
125
|
+
# Then apply each rule from the matching values.
|
126
|
+
RULES = {
|
127
|
+
GraphQL::Field => [
|
128
|
+
Rules::NAME_IS_STRING,
|
129
|
+
Rules::DESCRIPTION_IS_STRING_OR_NIL,
|
130
|
+
Rules.assert_property(:deprecation_reason, String, NilClass),
|
131
|
+
Rules.assert_property(:type, GraphQL::BaseType),
|
132
|
+
Rules.assert_property(:property, Symbol, NilClass),
|
133
|
+
Rules::ARGUMENTS_ARE_STRING_TO_ARGUMENT,
|
134
|
+
Rules::ARGUMENTS_ARE_VALID,
|
135
|
+
],
|
136
|
+
GraphQL::Argument => [
|
137
|
+
Rules::NAME_IS_STRING,
|
138
|
+
Rules::DESCRIPTION_IS_STRING_OR_NIL,
|
139
|
+
Rules::TYPE_IS_VALID_INPUT_TYPE,
|
140
|
+
Rules::DEFAULT_VALUE_IS_VALID_FOR_TYPE,
|
141
|
+
],
|
142
|
+
GraphQL::BaseType => [
|
143
|
+
Rules::NAME_IS_STRING,
|
144
|
+
Rules::DESCRIPTION_IS_STRING_OR_NIL,
|
145
|
+
],
|
146
|
+
GraphQL::ObjectType => [
|
147
|
+
Rules.assert_property_list_of(:interfaces, GraphQL::InterfaceType),
|
148
|
+
Rules::FIELDS_ARE_VALID,
|
149
|
+
],
|
150
|
+
GraphQL::InputObjectType => [
|
151
|
+
Rules::ARGUMENTS_ARE_STRING_TO_ARGUMENT,
|
152
|
+
Rules::ARGUMENTS_ARE_VALID,
|
153
|
+
],
|
154
|
+
GraphQL::UnionType => [
|
155
|
+
Rules.assert_property_list_of(:possible_types, GraphQL::ObjectType),
|
156
|
+
Rules::HAS_ONE_OR_MORE_POSSIBLE_TYPES,
|
157
|
+
],
|
158
|
+
GraphQL::InterfaceType => [
|
159
|
+
Rules::FIELDS_ARE_VALID,
|
160
|
+
],
|
161
|
+
}
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|