graphql 0.1.0 → 0.2.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/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
|