graphql 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graph_ql/directive.rb +9 -5
- data/lib/graph_ql/directives/include_directive.rb +2 -2
- data/lib/graph_ql/directives/skip_directive.rb +2 -2
- data/lib/graph_ql/enum.rb +5 -8
- data/lib/graph_ql/field.rb +50 -0
- data/lib/graph_ql/interface.rb +4 -0
- data/lib/graph_ql/introspection/arguments_field.rb +2 -2
- data/lib/graph_ql/introspection/directive_type.rb +10 -10
- data/lib/graph_ql/introspection/enum_value_type.rb +11 -8
- data/lib/graph_ql/introspection/enum_values_field.rb +5 -5
- data/lib/graph_ql/introspection/field_type.rb +14 -10
- data/lib/graph_ql/introspection/fields_field.rb +4 -4
- data/lib/graph_ql/introspection/input_fields_field.rb +3 -3
- data/lib/graph_ql/introspection/input_value_type.rb +8 -8
- data/lib/graph_ql/introspection/interfaces_field.rb +5 -0
- data/lib/graph_ql/introspection/of_type_field.rb +3 -9
- data/lib/graph_ql/introspection/possible_types_field.rb +3 -10
- data/lib/graph_ql/introspection/schema_type.rb +8 -14
- data/lib/graph_ql/introspection/type_kind_enum.rb +1 -1
- data/lib/graph_ql/introspection/type_type.rb +17 -19
- data/lib/graph_ql/introspection/typename_field.rb +15 -0
- data/lib/graph_ql/parser.rb +9 -0
- data/lib/graph_ql/parser/nodes.rb +17 -7
- data/lib/graph_ql/parser/parser.rb +7 -7
- data/lib/graph_ql/parser/transform.rb +23 -20
- data/lib/graph_ql/parser/visitor.rb +29 -13
- data/lib/graph_ql/query.rb +39 -16
- data/lib/graph_ql/query/field_resolution_strategy.rb +15 -11
- data/lib/graph_ql/query/type_resolver.rb +4 -2
- data/lib/graph_ql/repl.rb +1 -1
- data/lib/graph_ql/schema.rb +19 -7
- data/lib/graph_ql/schema/each_item_validator.rb +12 -0
- data/lib/graph_ql/schema/field_validator.rb +13 -0
- data/lib/graph_ql/schema/implementation_validator.rb +21 -0
- data/lib/graph_ql/schema/schema_validator.rb +10 -0
- data/lib/graph_ql/schema/type_reducer.rb +6 -6
- data/lib/graph_ql/schema/type_validator.rb +47 -0
- data/lib/graph_ql/static_validation.rb +18 -0
- data/lib/graph_ql/static_validation/argument_literals_are_compatible.rb +13 -0
- data/lib/graph_ql/static_validation/arguments_are_defined.rb +10 -0
- data/lib/graph_ql/static_validation/arguments_validator.rb +16 -0
- data/lib/graph_ql/static_validation/directives_are_defined.rb +18 -0
- data/lib/graph_ql/static_validation/fields_are_defined_on_type.rb +29 -0
- data/lib/graph_ql/static_validation/fields_have_appropriate_selections.rb +31 -0
- data/lib/graph_ql/static_validation/fields_will_merge.rb +93 -0
- data/lib/graph_ql/static_validation/fragment_types_exist.rb +24 -0
- data/lib/graph_ql/static_validation/fragments_are_used.rb +30 -0
- data/lib/graph_ql/static_validation/literal_validator.rb +27 -0
- data/lib/graph_ql/static_validation/message.rb +29 -0
- data/lib/graph_ql/static_validation/required_arguments_are_present.rb +13 -0
- data/lib/graph_ql/static_validation/type_stack.rb +87 -0
- data/lib/graph_ql/static_validation/validator.rb +48 -0
- data/lib/graph_ql/type_kinds.rb +50 -12
- data/lib/graph_ql/types/argument_definer.rb +7 -0
- data/lib/graph_ql/types/boolean_type.rb +3 -3
- data/lib/graph_ql/types/field_definer.rb +19 -0
- data/lib/graph_ql/types/float_type.rb +3 -3
- data/lib/graph_ql/types/input_object_type.rb +4 -0
- data/lib/graph_ql/types/input_value.rb +1 -1
- data/lib/graph_ql/types/int_type.rb +4 -4
- data/lib/graph_ql/types/list_type.rb +5 -1
- data/lib/graph_ql/types/non_null_type.rb +4 -0
- data/lib/graph_ql/types/object_type.rb +9 -20
- data/lib/graph_ql/types/scalar_type.rb +4 -0
- data/lib/graph_ql/types/string_type.rb +3 -3
- data/lib/graph_ql/types/type_definer.rb +5 -9
- data/lib/graph_ql/union.rb +6 -17
- data/lib/graph_ql/version.rb +1 -1
- data/lib/graphql.rb +58 -78
- data/readme.md +80 -7
- data/spec/graph_ql/interface_spec.rb +15 -1
- data/spec/graph_ql/introspection/directive_type_spec.rb +2 -2
- data/spec/graph_ql/introspection/schema_type_spec.rb +2 -1
- data/spec/graph_ql/introspection/type_type_spec.rb +16 -1
- data/spec/graph_ql/parser/parser_spec.rb +3 -1
- data/spec/graph_ql/parser/transform_spec.rb +12 -2
- data/spec/graph_ql/parser/visitor_spec.rb +13 -5
- data/spec/graph_ql/query_spec.rb +25 -13
- data/spec/graph_ql/schema/field_validator_spec.rb +21 -0
- data/spec/graph_ql/schema/type_reducer_spec.rb +2 -2
- data/spec/graph_ql/schema/type_validator_spec.rb +54 -0
- data/spec/graph_ql/static_validation/argument_literals_are_compatible_spec.rb +41 -0
- data/spec/graph_ql/static_validation/arguments_are_defined_spec.rb +40 -0
- data/spec/graph_ql/static_validation/directives_are_defined_spec.rb +33 -0
- data/spec/graph_ql/static_validation/fields_are_defined_on_type_spec.rb +59 -0
- data/spec/graph_ql/static_validation/fields_have_appropriate_selections_spec.rb +30 -0
- data/spec/graph_ql/{validations → static_validation}/fields_will_merge_spec.rb +24 -17
- data/spec/graph_ql/static_validation/fragment_types_exist_spec.rb +38 -0
- data/spec/graph_ql/static_validation/fragments_are_used_spec.rb +24 -0
- data/spec/graph_ql/static_validation/required_arguments_are_present_spec.rb +41 -0
- data/spec/graph_ql/static_validation/type_stack_spec.rb +35 -0
- data/spec/graph_ql/static_validation/validator_spec.rb +28 -0
- data/spec/graph_ql/types/object_type_spec.rb +1 -1
- data/spec/graph_ql/union_spec.rb +1 -14
- data/spec/support/dummy_app.rb +75 -53
- metadata +53 -31
- data/lib/graph_ql/fields/abstract_field.rb +0 -37
- data/lib/graph_ql/fields/access_field.rb +0 -24
- data/lib/graph_ql/fields/field.rb +0 -34
- data/lib/graph_ql/types/abstract_type.rb +0 -14
- data/lib/graph_ql/validations/fields_are_defined_on_type.rb +0 -44
- data/lib/graph_ql/validations/fields_will_merge.rb +0 -80
- data/lib/graph_ql/validations/fragments_are_used.rb +0 -24
- data/lib/graph_ql/validator.rb +0 -29
- data/spec/graph_ql/validations/fields_are_defined_on_type_spec.rb +0 -28
- data/spec/graph_ql/validations/fragments_are_used_spec.rb +0 -28
- data/spec/graph_ql/validator_spec.rb +0 -24
@@ -1,37 +0,0 @@
|
|
1
|
-
# Anything can be a Field as long as it responds to:
|
2
|
-
# - #name: String the name to access this field in a query
|
3
|
-
# - #type: Type returned by this field's resolve function
|
4
|
-
# - #description: String
|
5
|
-
# - #resolve(object, arguments, context): Object of Type `type`
|
6
|
-
# - #arguments: ???
|
7
|
-
# - #deprecation_reason
|
8
|
-
class GraphQL::AbstractField
|
9
|
-
def name
|
10
|
-
raise NotImplementedError, "#{self.class.name}#name should return the name for accessing this field"
|
11
|
-
end
|
12
|
-
|
13
|
-
def type
|
14
|
-
raise NotImplementedError, "#{self.class.name}#type should return the type class which this field returns"
|
15
|
-
end
|
16
|
-
|
17
|
-
def description
|
18
|
-
raise NotImplementedError, "#{self.class.name}#description should return this field's description"
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
def resolve(object, arguments, context)
|
23
|
-
raise NotImplementedError, "#{self.class.name}#resolve(object, arguments, context) should execute this field for object"
|
24
|
-
end
|
25
|
-
|
26
|
-
def arguments
|
27
|
-
{}
|
28
|
-
end
|
29
|
-
|
30
|
-
def deprecated?
|
31
|
-
!!deprecation_reason
|
32
|
-
end
|
33
|
-
|
34
|
-
def deprecation_reason
|
35
|
-
nil
|
36
|
-
end
|
37
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# Implement {AbstractField} by calling the field name on its object
|
2
|
-
# and returning the result.
|
3
|
-
class GraphQL::AccessField < GraphQL::AbstractField
|
4
|
-
attr_accessor :name, :type
|
5
|
-
attr_reader :description, :arguments, :deprecation_reason
|
6
|
-
def initialize(type:, arguments:, description:, property: nil, deprecation_reason: nil)
|
7
|
-
@type = type
|
8
|
-
@arguments = arguments
|
9
|
-
@description = description
|
10
|
-
@property = property
|
11
|
-
@deprecation_reason = deprecation_reason
|
12
|
-
end
|
13
|
-
|
14
|
-
def resolve(object, args, context)
|
15
|
-
@property.nil? ? GraphQL::Query::DEFAULT_RESOLVE : object.send(@property)
|
16
|
-
end
|
17
|
-
|
18
|
-
def type
|
19
|
-
if @type.is_a?(Proc)
|
20
|
-
@type = @type.call
|
21
|
-
end
|
22
|
-
@type
|
23
|
-
end
|
24
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
class GraphQL::Field < GraphQL::AbstractField
|
2
|
-
extend GraphQL::Definable
|
3
|
-
REQUIRED_DEFINITIONS = [:name, :description, :type]
|
4
|
-
attr_definable(:arguments, :deprecation_reason, *REQUIRED_DEFINITIONS)
|
5
|
-
|
6
|
-
def initialize(&block)
|
7
|
-
@arguments = {}
|
8
|
-
@resolve_proc = -> (o, a, c) { GraphQL::Query::DEFAULT_RESOLVE }
|
9
|
-
yield(self) if block_given?
|
10
|
-
end
|
11
|
-
|
12
|
-
# Used when defining:
|
13
|
-
# resolve -> (obj, args, ctx) { obj.get_value }
|
14
|
-
# Also used when executing queries:
|
15
|
-
# field.resolve(obj, args, ctx)
|
16
|
-
def resolve(proc_or_object, arguments=nil, ctx=nil)
|
17
|
-
if arguments.nil? && ctx.nil?
|
18
|
-
@resolve_proc = proc_or_object
|
19
|
-
else
|
20
|
-
@resolve_proc.call(proc_or_object, arguments, ctx)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def type(type_or_proc=nil)
|
25
|
-
if type_or_proc.nil?
|
26
|
-
if @type.is_a?(Proc)
|
27
|
-
@type = @type.call
|
28
|
-
end
|
29
|
-
@type
|
30
|
-
else
|
31
|
-
@type = type_or_proc
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# Any object can be a type as long as it implements:
|
2
|
-
# - #fields: Hash of { String => Field } pairs
|
3
|
-
# - #kind: one of GraphQL::TypeKinds
|
4
|
-
# - #interfaces: Array of Interfaces
|
5
|
-
# - #name: String
|
6
|
-
# - #description: String
|
7
|
-
#
|
8
|
-
class GraphQL::AbstractType
|
9
|
-
def fields; raise NotImplementedError; end
|
10
|
-
def kind; raise NotImplementedError; end
|
11
|
-
def interfaces; raise NotImplementedError; end
|
12
|
-
def name; raise NotImplementedError; end
|
13
|
-
def description; raise NotImplementedError; end
|
14
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
class GraphQL::Validations::FieldsAreDefinedOnType
|
2
|
-
TYPE_INFERRENCE_ROOTS = [GraphQL::Nodes::OperationDefinition, GraphQL::Nodes::FragmentDefinition]
|
3
|
-
FIELD_MODIFIERS = [GraphQL::TypeKinds::LIST]
|
4
|
-
|
5
|
-
def validate(context)
|
6
|
-
visitor = context.visitor
|
7
|
-
TYPE_INFERRENCE_ROOTS.each do |node_class|
|
8
|
-
visitor[node_class] << -> (node){ validate_document_part(node, context) }
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
def validate_document_part(part, context)
|
14
|
-
if part.is_a?(GraphQL::Nodes::FragmentDefinition)
|
15
|
-
type = context.schema.types[part.type]
|
16
|
-
validate_selections(type, part.selections, context)
|
17
|
-
elsif part.is_a?(GraphQL::Nodes::OperationDefinition)
|
18
|
-
type = context.schema.public_send(part.operation_type) # mutation root or query root
|
19
|
-
validate_selections(type, part.selections, context)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def validate_selections(type, selections, context)
|
24
|
-
selections
|
25
|
-
.select {|f| f.is_a?(GraphQL::Nodes::Field) } # don't worry about fragments
|
26
|
-
.each do |ast_field|
|
27
|
-
field = type.fields[ast_field.name]
|
28
|
-
if field.nil?
|
29
|
-
context.errors << "Field '#{ast_field.name}' doesn't exist on type '#{type.name}'"
|
30
|
-
else
|
31
|
-
field_type = get_field_type(field)
|
32
|
-
validate_selections(field_type, ast_field.selections, context)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def get_field_type(field)
|
38
|
-
if FIELD_MODIFIERS.include?(field.type.kind)
|
39
|
-
field.type.of_type
|
40
|
-
else
|
41
|
-
field.type
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
class GraphQL::Validations::FieldsWillMerge
|
2
|
-
HAS_SELECTIONS = [GraphQL::Nodes::OperationDefinition, GraphQL::Nodes::InlineFragment]
|
3
|
-
|
4
|
-
def validate(context)
|
5
|
-
fragments = {}
|
6
|
-
has_selections = []
|
7
|
-
visitor = context.visitor
|
8
|
-
HAS_SELECTIONS.each do |node_class|
|
9
|
-
visitor[node_class] << -> (node) { has_selections << node }
|
10
|
-
end
|
11
|
-
visitor[GraphQL::Nodes::FragmentDefinition] << -> (node) { fragments[node.name] = node }
|
12
|
-
visitor[GraphQL::Nodes::Document].leave << -> (node) {
|
13
|
-
has_selections.each { |node| validate_selections(node.selections, {}, fragments, context.errors)}
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def validate_selections(selections, name_to_field, fragments, errors)
|
20
|
-
selections.each do |field|
|
21
|
-
if field.is_a?(GraphQL::Nodes::InlineFragment)
|
22
|
-
validate_selections(field.selections, name_to_field, fragments, errors)
|
23
|
-
elsif field.is_a?(GraphQL::Nodes::FragmentSpread)
|
24
|
-
fragment = fragments[field.name]
|
25
|
-
validate_selections(fragment.selections, name_to_field, fragments, errors)
|
26
|
-
else
|
27
|
-
field_errors = validate_field(field, name_to_field)
|
28
|
-
errors.push(*field_errors)
|
29
|
-
validate_selections(field.selections, name_to_field, fragments, errors)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def validate_field(field, name_to_field)
|
35
|
-
name_in_selection = field.alias || field.name
|
36
|
-
name_to_field[name_in_selection] ||= field
|
37
|
-
first_field_def = name_to_field[name_in_selection]
|
38
|
-
comparison = FieldDefinitionComparison.new(name_in_selection, first_field_def, field)
|
39
|
-
comparison.errors
|
40
|
-
end
|
41
|
-
|
42
|
-
# Compare two field definitions, add errors to the list if there are any
|
43
|
-
class FieldDefinitionComparison
|
44
|
-
NAMED_VALUES = [GraphQL::Nodes::Enum, GraphQL::Nodes::VariableIdentifier]
|
45
|
-
attr_reader :errors
|
46
|
-
def initialize(name, prev_def, next_def)
|
47
|
-
errors = []
|
48
|
-
if prev_def.name != next_def.name
|
49
|
-
errors << "Field '#{name}' has a field conflict: #{prev_def.name} or #{next_def.name}?"
|
50
|
-
end
|
51
|
-
prev_arguments = reduce_list(prev_def.arguments)
|
52
|
-
next_arguments = reduce_list(next_def.arguments)
|
53
|
-
if prev_arguments != next_arguments
|
54
|
-
errors << "Field '#{name}' has an argument conflict: #{JSON.dump(prev_arguments)} or #{JSON.dump(next_arguments)}?"
|
55
|
-
end
|
56
|
-
prev_directive_names = prev_def.directives.map(&:name)
|
57
|
-
next_directive_names = next_def.directives.map(&:name)
|
58
|
-
if prev_directive_names != next_directive_names
|
59
|
-
errors << "Field '#{name}' has a directive conflict: [#{prev_directive_names.join(", ")}] or [#{next_directive_names.join(", ")}]?"
|
60
|
-
end
|
61
|
-
prev_directive_args = prev_def.directives.map {|d| reduce_list(d.arguments) }
|
62
|
-
next_directive_args = next_def.directives.map {|d| reduce_list(d.arguments) }
|
63
|
-
if prev_directive_args != next_directive_args
|
64
|
-
errors << "Field '#{name}' has a directive argument conflict: #{JSON.dump(prev_directive_args)} or #{JSON.dump(next_directive_args)}?"
|
65
|
-
end
|
66
|
-
@errors = errors
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
# Turn AST tree into a hash
|
72
|
-
# can't look up args, the names just have to match
|
73
|
-
def reduce_list(args)
|
74
|
-
args.reduce({}) do |memo, a|
|
75
|
-
memo[a.name] = NAMED_VALUES.include?(a.value.class) ? a.value.name : a.value
|
76
|
-
memo
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
class GraphQL::Validations::FragmentsAreUsed
|
2
|
-
def validate(context)
|
3
|
-
v = context.visitor
|
4
|
-
used_fragment_names = []
|
5
|
-
defined_fragment_names = []
|
6
|
-
v[GraphQL::Nodes::FragmentSpread] << -> (node) { used_fragment_names << node.name }
|
7
|
-
v[GraphQL::Nodes::FragmentDefinition] << -> (node) { defined_fragment_names << node.name}
|
8
|
-
v[GraphQL::Nodes::Document].leave << -> (node) { add_errors(context.errors, used_fragment_names, defined_fragment_names) }
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def add_errors(errors, used_fragment_names, defined_fragment_names)
|
14
|
-
undefined_fragment_names = used_fragment_names - defined_fragment_names
|
15
|
-
if undefined_fragment_names.any?
|
16
|
-
errors << "Some fragments were used but not defined: #{undefined_fragment_names.join(", ")}"
|
17
|
-
end
|
18
|
-
|
19
|
-
unused_fragment_names = defined_fragment_names - used_fragment_names
|
20
|
-
if unused_fragment_names.any?
|
21
|
-
errors << "Some fragments were defined but not used: #{unused_fragment_names.join(", ")}"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/graph_ql/validator.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
class GraphQL::Validator
|
2
|
-
VALIDATORS = [
|
3
|
-
GraphQL::Validations::FragmentsAreUsed,
|
4
|
-
]
|
5
|
-
|
6
|
-
def initialize(schema:, validators: VALIDATORS)
|
7
|
-
@schema = schema
|
8
|
-
@validators = validators
|
9
|
-
end
|
10
|
-
|
11
|
-
def validate(document)
|
12
|
-
context = Context.new(@schema, document)
|
13
|
-
@validators.each do |validator|
|
14
|
-
validator.new.validate(context)
|
15
|
-
end
|
16
|
-
context.visitor.visit(document)
|
17
|
-
context.errors
|
18
|
-
end
|
19
|
-
|
20
|
-
class Context
|
21
|
-
attr_reader :schema, :document, :errors, :visitor
|
22
|
-
def initialize(schema, document)
|
23
|
-
@schema = schema
|
24
|
-
@document = document
|
25
|
-
@visitor = GraphQL::Visitor.new
|
26
|
-
@errors = []
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe GraphQL::Validations::FieldsAreDefinedOnType do
|
4
|
-
let(:document) { GraphQL.parse("
|
5
|
-
query getCheese($sourceVar: DairyAnimal!) {
|
6
|
-
notDefinedField { name }
|
7
|
-
cheese(id: 1) { nonsenseField, flavor }
|
8
|
-
fromSource(source: COW) { bogusField }
|
9
|
-
}
|
10
|
-
|
11
|
-
fragment cheeseFields on Cheese { fatContent, hogwashField }
|
12
|
-
")}
|
13
|
-
|
14
|
-
let(:validator) { GraphQL::Validator.new(schema: DummySchema, validators: [GraphQL::Validations::FieldsAreDefinedOnType]) }
|
15
|
-
let(:errors) { validator.validate(document) }
|
16
|
-
it "finds fields that are requested on types that don't have that field" do
|
17
|
-
expected_errors = [
|
18
|
-
"Field 'notDefinedField' doesn't exist on type 'Query'", # from query root
|
19
|
-
"Field 'nonsenseField' doesn't exist on type 'Cheese'", # from another field
|
20
|
-
"Field 'bogusField' doesn't exist on type 'Cheese'", # from a list
|
21
|
-
"Field 'hogwashField' doesn't exist on type 'Cheese'", # from a fragment
|
22
|
-
]
|
23
|
-
assert_equal(expected_errors, errors)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'finds invalid fields on interfaces'
|
27
|
-
it 'finds invalid fields on unions'
|
28
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe GraphQL::Validations::FragmentsAreUsed do
|
4
|
-
let(:document) { GraphQL.parse("
|
5
|
-
query getCheese {
|
6
|
-
name,
|
7
|
-
...cheeseFields,
|
8
|
-
origin {
|
9
|
-
...originFields
|
10
|
-
...undefinedFields
|
11
|
-
}
|
12
|
-
}
|
13
|
-
fragment cheeseFields on Cheese { fatContent }
|
14
|
-
fragment originFields on Country { name, continent { ...continentFields }}
|
15
|
-
fragment continentFields on Continent { name }
|
16
|
-
fragment unusedFields on Cheese { is, not, used }
|
17
|
-
")}
|
18
|
-
|
19
|
-
let(:validator) { GraphQL::Validator.new(schema: nil, validators: [GraphQL::Validations::FragmentsAreUsed]) }
|
20
|
-
let(:errors) { validator.validate(document) }
|
21
|
-
|
22
|
-
it 'adds errors for unused fragment definitions' do
|
23
|
-
assert_includes(errors, 'Some fragments were defined but not used: unusedFields')
|
24
|
-
end
|
25
|
-
it 'adds errors for undefined fragment spreads' do
|
26
|
-
assert_includes(errors, 'Some fragments were used but not defined: undefinedFields')
|
27
|
-
end
|
28
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class SchemaErrorValidator
|
4
|
-
def validate(context)
|
5
|
-
context.errors << "Something is wrong: #{context.schema}"
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
class DocumentErrorValidator
|
10
|
-
def validate(context)
|
11
|
-
context.errors << "Something is wrong: #{context.document.name}"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe GraphQL::Validator do
|
16
|
-
let(:document) { OpenStruct.new(name: "This is not a document", children: []) }
|
17
|
-
let(:validator) { GraphQL::Validator.new(schema: "This is not a schema", validators: [SchemaErrorValidator, DocumentErrorValidator]) }
|
18
|
-
|
19
|
-
it 'uses validators' do
|
20
|
-
errors = validator.validate(document)
|
21
|
-
expected_errors = ["Something is wrong: This is not a schema", "Something is wrong: This is not a document"]
|
22
|
-
assert_equal(expected_errors, errors)
|
23
|
-
end
|
24
|
-
end
|