graphql 0.7.1 → 0.8.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.rb +2 -0
- data/lib/graphql/base_type.rb +79 -0
- data/lib/graphql/enum_type.rb +1 -3
- data/lib/graphql/input_object_type.rb +2 -2
- data/lib/graphql/interface_type.rb +3 -22
- data/lib/graphql/list_type.rb +5 -3
- data/lib/graphql/non_null_type.rb +4 -2
- data/lib/graphql/object_type.rb +1 -34
- data/lib/graphql/query.rb +10 -5
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/base_execution.rb +21 -2
- data/lib/graphql/query/base_execution/value_resolution.rb +82 -0
- data/lib/graphql/query/executor.rb +7 -5
- data/lib/graphql/query/parallel_execution.rb +101 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +18 -9
- data/lib/graphql/scalar_type.rb +3 -3
- data/lib/graphql/schema.rb +4 -0
- data/lib/graphql/schema/type_map.rb +34 -0
- data/lib/graphql/schema/type_reducer.rb +14 -16
- data/lib/graphql/static_validation/arguments_validator.rb +8 -8
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +6 -8
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -11
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +25 -4
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/type_stack.rb +3 -3
- data/lib/graphql/type_kinds.rb +0 -19
- data/lib/graphql/union_type.rb +3 -13
- data/lib/graphql/version.rb +1 -1
- data/readme.md +0 -11
- data/spec/graphql/base_type_spec.rb +24 -0
- data/spec/graphql/object_type_spec.rb +0 -20
- data/spec/graphql/query/parallel_execution_spec.rb +29 -0
- data/spec/graphql/query_spec.rb +23 -6
- data/spec/graphql/schema/type_reducer_spec.rb +25 -0
- data/spec/graphql/static_validation/validator_spec.rb +4 -3
- data/spec/spec_helper.rb +1 -1
- data/spec/support/dairy_app.rb +6 -2
- data/spec/support/parallel_schema.rb +31 -0
- metadata +26 -3
- data/lib/graphql/query/value_resolution.rb +0 -76
@@ -12,13 +12,28 @@ module GraphQL
|
|
12
12
|
|
13
13
|
def result
|
14
14
|
result_name = ast_node.alias || ast_node.name
|
15
|
-
|
15
|
+
result_value = get_finished_value(get_raw_value)
|
16
|
+
{ result_name => result_value }
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
20
|
|
20
|
-
def
|
21
|
+
def get_finished_value(raw_value)
|
22
|
+
if raw_value.nil?
|
23
|
+
nil
|
24
|
+
else
|
25
|
+
resolved_type = field.type.resolve_type(raw_value)
|
26
|
+
strategy_class = GraphQL::Query::BaseExecution::ValueResolution.get_strategy_for_kind(resolved_type.kind)
|
27
|
+
result_strategy = strategy_class.new(raw_value, resolved_type, target, parent_type, ast_node, query, execution_strategy)
|
28
|
+
result_strategy.result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def get_raw_value
|
34
|
+
query.context.ast_node = ast_node
|
21
35
|
value = field.resolve(target, arguments, query.context)
|
36
|
+
query.context.ast_node = nil
|
22
37
|
|
23
38
|
if value == GraphQL::Query::DEFAULT_RESOLVE
|
24
39
|
begin
|
@@ -28,13 +43,7 @@ module GraphQL
|
|
28
43
|
end
|
29
44
|
end
|
30
45
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
resolved_type = field.type.kind.resolve(field.type, value)
|
35
|
-
strategy_class = GraphQL::Query::ValueResolution.get_strategy_for_kind(resolved_type.kind)
|
36
|
-
result_strategy = strategy_class.new(value, resolved_type, target, parent_type, ast_node, query, execution_strategy)
|
37
|
-
result_strategy.result
|
46
|
+
value
|
38
47
|
end
|
39
48
|
end
|
40
49
|
end
|
data/lib/graphql/scalar_type.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module GraphQL
|
2
2
|
# The parent type for scalars, eg {GraphQL::STRING_TYPE}, {GraphQL::INT_TYPE}
|
3
3
|
#
|
4
|
-
class ScalarType < GraphQL::
|
5
|
-
defined_by_config :name, :coerce
|
6
|
-
attr_accessor :name
|
4
|
+
class ScalarType < GraphQL::BaseType
|
5
|
+
defined_by_config :name, :coerce, :description
|
6
|
+
attr_accessor :name, :description
|
7
7
|
|
8
8
|
def coerce(value)
|
9
9
|
@coerce_proc.call(value)
|
data/lib/graphql/schema.rb
CHANGED
@@ -4,6 +4,9 @@ class GraphQL::Schema
|
|
4
4
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
|
5
5
|
|
6
6
|
attr_reader :query, :mutation, :directives, :static_validator
|
7
|
+
# Override these if you don't want the default executors:
|
8
|
+
attr_accessor :query_execution_strategy, :mutation_execution_strategy
|
9
|
+
|
7
10
|
|
8
11
|
# @param query [GraphQL::ObjectType] the query root for the schema
|
9
12
|
# @param mutation [GraphQL::ObjectType, nil] the mutation root for the schema
|
@@ -48,4 +51,5 @@ require 'graphql/schema/each_item_validator'
|
|
48
51
|
require 'graphql/schema/field_validator'
|
49
52
|
require 'graphql/schema/implementation_validator'
|
50
53
|
require 'graphql/schema/type_reducer'
|
54
|
+
require 'graphql/schema/type_map'
|
51
55
|
require 'graphql/schema/type_validator'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Schema
|
3
|
+
# Stores `{ name => type }` pairs for a given schema.
|
4
|
+
# It behaves like a hash except for a couple things:
|
5
|
+
# - if you use `[key]` and that key isn't defined, 💥!
|
6
|
+
# - if you try to define the same key twice, 💥!
|
7
|
+
#
|
8
|
+
# If you want a type, but want to handle the undefined case, use {#fetch}.
|
9
|
+
class TypeMap
|
10
|
+
extend Forwardable
|
11
|
+
def_delegators :@storage, :key?, :keys, :values
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@storage = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
@storage[key] || raise("No type found for '#{key}'")
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, value)
|
22
|
+
if @storage.key?(key)
|
23
|
+
raise("Duplicate type definition found for name '#{key}'")
|
24
|
+
else
|
25
|
+
@storage[key] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch(key, fallback_value)
|
30
|
+
@storage.key?(key) ? @storage[key] : fallback_value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -4,25 +4,24 @@ class GraphQL::Schema::TypeReducer
|
|
4
4
|
attr_reader :type, :existing_type_hash
|
5
5
|
|
6
6
|
def initialize(type, existing_type_hash)
|
7
|
-
|
7
|
+
type = type.nil? ? nil : type.unwrap
|
8
|
+
validate_type(type)
|
9
|
+
if type.respond_to?(:name) && existing_type_hash.fetch(type.name, nil).equal?(type)
|
10
|
+
@result = existing_type_hash
|
11
|
+
else
|
12
|
+
@type = type
|
13
|
+
end
|
8
14
|
@existing_type_hash = existing_type_hash
|
9
15
|
end
|
10
16
|
|
11
17
|
def result
|
12
|
-
@result ||=
|
13
|
-
reduce_type(type.of_type, existing_type_hash)
|
14
|
-
elsif type.respond_to?(:name) && existing_type_hash.has_key?(type.name)
|
15
|
-
# been here, done that
|
16
|
-
existing_type_hash
|
17
|
-
else
|
18
|
-
validate_type(type)
|
19
|
-
find_types(type, existing_type_hash.dup)
|
20
|
-
end
|
18
|
+
@result ||= find_types(type, existing_type_hash)
|
21
19
|
end
|
22
20
|
|
23
21
|
# Reduce all of `types` and return the combined result
|
24
22
|
def self.find_all(types)
|
25
|
-
|
23
|
+
type_map = GraphQL::Schema::TypeMap.new
|
24
|
+
types.reduce(type_map) do |memo, type|
|
26
25
|
self.new(type, memo).result
|
27
26
|
end
|
28
27
|
end
|
@@ -33,21 +32,20 @@ class GraphQL::Schema::TypeReducer
|
|
33
32
|
type_hash[type.name] = type
|
34
33
|
if type.kind.fields?
|
35
34
|
type.fields.each do |name, field|
|
36
|
-
|
37
|
-
type_hash.merge!(reduce_type(field.type, type_hash))
|
35
|
+
reduce_type(field.type, type_hash)
|
38
36
|
field.arguments.each do |name, argument|
|
39
|
-
|
37
|
+
reduce_type(argument.type, type_hash)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
43
41
|
if type.kind.object?
|
44
42
|
type.interfaces.each do |interface|
|
45
|
-
|
43
|
+
reduce_type(interface, type_hash)
|
46
44
|
end
|
47
45
|
end
|
48
46
|
if type.kind.resolves?
|
49
47
|
type.possible_types.each do |possible_type|
|
50
|
-
|
48
|
+
reduce_type(possible_type, type_hash)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
type_hash
|
@@ -4,14 +4,14 @@ class GraphQL::StaticValidation::ArgumentsValidator
|
|
4
4
|
|
5
5
|
def validate(context)
|
6
6
|
visitor = context.visitor
|
7
|
-
visitor[GraphQL::Language::Nodes::
|
8
|
-
return if context.skip_field?(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
validate_node(node,
|
7
|
+
visitor[GraphQL::Language::Nodes::Argument] << -> (node, parent) {
|
8
|
+
return if parent.is_a?(GraphQL::Language::Nodes::InputObject) || context.skip_field?(parent.name)
|
9
|
+
if parent.is_a?(GraphQL::Language::Nodes::Directive)
|
10
|
+
parent_defn = context.schema.directives[parent.name]
|
11
|
+
else
|
12
|
+
parent_defn = context.field_definition
|
13
|
+
end
|
14
|
+
validate_node(parent, node, parent_defn, context)
|
15
15
|
}
|
16
16
|
end
|
17
17
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
class GraphQL::StaticValidation::ArgumentLiteralsAreCompatible < GraphQL::StaticValidation::ArgumentsValidator
|
2
|
-
def validate_node(node, defn, context)
|
3
|
-
|
2
|
+
def validate_node(parent, node, defn, context)
|
3
|
+
return if node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
4
4
|
validator = GraphQL::StaticValidation::LiteralValidator.new
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
context.errors << message("Argument #{arg.name} on #{node.class.name.split("::").last} '#{node.name}' has an invalid value", node)
|
10
|
-
end
|
5
|
+
arg_defn = defn.arguments[node.name]
|
6
|
+
valid = validator.validate(node.value, arg_defn.type)
|
7
|
+
if !valid
|
8
|
+
context.errors << message("Argument #{node.name} on #{parent.class.name.split("::").last} '#{parent.name}' has an invalid value", parent)
|
11
9
|
end
|
12
10
|
end
|
13
11
|
end
|
@@ -1,15 +1,11 @@
|
|
1
1
|
class GraphQL::StaticValidation::ArgumentsAreDefined < GraphQL::StaticValidation::ArgumentsValidator
|
2
|
-
def validate_node(node, defn, context)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
skip = GraphQL::Language::Visitor::SKIP
|
10
|
-
end
|
2
|
+
def validate_node(parent, node, defn, context)
|
3
|
+
argument_defn = defn.arguments[node.name]
|
4
|
+
if argument_defn.nil?
|
5
|
+
context.errors << message("#{parent.class.name.split("::").last} '#{parent.name}' doesn't accept argument #{node.name}", parent)
|
6
|
+
GraphQL::Language::Visitor::SKIP
|
7
|
+
else
|
8
|
+
nil
|
11
9
|
end
|
12
|
-
|
13
|
-
skip
|
14
10
|
end
|
15
11
|
end
|
@@ -8,7 +8,7 @@ class GraphQL::StaticValidation::FieldsAreDefinedOnType
|
|
8
8
|
visitor[GraphQL::Language::Nodes::Field] << -> (node, parent) {
|
9
9
|
return if context.skip_field?(node.name)
|
10
10
|
parent_type = context.object_types[-2]
|
11
|
-
parent_type = parent_type.
|
11
|
+
parent_type = parent_type.unwrap
|
12
12
|
validate_field(context.errors, node, parent_type, parent)
|
13
13
|
}
|
14
14
|
end
|
@@ -14,7 +14,7 @@ class GraphQL::StaticValidation::FieldsHaveAppropriateSelections
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def validate_field_selections(ast_field, field_defn, errors)
|
17
|
-
resolved_type = field_defn.type.
|
17
|
+
resolved_type = field_defn.type.unwrap
|
18
18
|
|
19
19
|
if resolved_type.kind.scalar? && ast_field.selections.any?
|
20
20
|
error = message("Selections can't be made on scalars (field '#{ast_field.name}' returns #{resolved_type.name} but has selections [#{ast_field.selections.map(&:name).join(", ")}])", ast_field)
|
@@ -15,7 +15,7 @@ class GraphQL::StaticValidation::FragmentTypesExist
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def validate_type_exists(node, context)
|
18
|
-
type = context.schema.types
|
18
|
+
type = context.schema.types.fetch(node.type, nil)
|
19
19
|
if type.nil?
|
20
20
|
context.errors << message("No such type #{node.type}, so it can't be a fragment condition", node)
|
21
21
|
GraphQL::Language::Visitor::SKIP
|
@@ -1,13 +1,34 @@
|
|
1
|
-
class GraphQL::StaticValidation::RequiredArgumentsArePresent
|
2
|
-
|
3
|
-
|
1
|
+
class GraphQL::StaticValidation::RequiredArgumentsArePresent
|
2
|
+
include GraphQL::StaticValidation::Message::MessageHelper
|
3
|
+
|
4
|
+
def validate(context)
|
5
|
+
v = context.visitor
|
6
|
+
v[GraphQL::Language::Nodes::Field] << -> (node, parent) { validate_field(node, context) }
|
7
|
+
v[GraphQL::Language::Nodes::Directive] << -> (node, parent) { validate_directive(node, context) }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def validate_directive(ast_directive, context)
|
13
|
+
directive_defn = context.schema.directives[ast_directive.name]
|
14
|
+
assert_required_args(ast_directive, directive_defn, context)
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_field(ast_field, context)
|
18
|
+
return if context.skip_field?(ast_field.name)
|
19
|
+
defn = context.field_definition
|
20
|
+
assert_required_args(ast_field, defn, context)
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_required_args(ast_node, defn, context)
|
24
|
+
present_argument_names = ast_node.arguments.map(&:name)
|
4
25
|
required_argument_names = defn.arguments.values
|
5
26
|
.select { |a| a.type.kind.non_null? }
|
6
27
|
.map(&:name)
|
7
28
|
|
8
29
|
missing_names = required_argument_names - present_argument_names
|
9
30
|
if missing_names.any?
|
10
|
-
context.errors << message("#{
|
31
|
+
context.errors << message("#{ast_node.class.name.split("::").last} '#{ast_node.name}' is missing required arguments: #{missing_names.join(", ")}", ast_node)
|
11
32
|
end
|
12
33
|
end
|
13
34
|
end
|
@@ -32,8 +32,8 @@ class GraphQL::StaticValidation::VariableUsagesAreAllowed
|
|
32
32
|
arg_defn = arguments[arg_node.name]
|
33
33
|
arg_defn_type = arg_defn.type
|
34
34
|
|
35
|
-
var_inner_type = var_type.
|
36
|
-
arg_inner_type = arg_defn_type.
|
35
|
+
var_inner_type = var_type.unwrap
|
36
|
+
arg_inner_type = arg_defn_type.unwrap
|
37
37
|
|
38
38
|
if var_inner_type != arg_inner_type
|
39
39
|
context.errors << create_error("Type mismatch", var_type, ast_var, arg_defn, arg_node)
|
@@ -48,9 +48,9 @@ class GraphQL::StaticValidation::TypeStack
|
|
48
48
|
|
49
49
|
class FragmentWithTypeStrategy
|
50
50
|
def push(stack, node)
|
51
|
-
object_type = stack.schema.types
|
51
|
+
object_type = stack.schema.types.fetch(node.type, nil)
|
52
52
|
if !object_type.nil?
|
53
|
-
object_type = object_type.
|
53
|
+
object_type = object_type.unwrap
|
54
54
|
end
|
55
55
|
stack.object_types.push(object_type)
|
56
56
|
end
|
@@ -77,7 +77,7 @@ class GraphQL::StaticValidation::TypeStack
|
|
77
77
|
class FieldStrategy
|
78
78
|
def push(stack, node)
|
79
79
|
parent_type = stack.object_types.last
|
80
|
-
parent_type = parent_type.
|
80
|
+
parent_type = parent_type.unwrap
|
81
81
|
if parent_type.kind.fields?
|
82
82
|
field_class = stack.schema.get_field(parent_type, node.name)
|
83
83
|
stack.field_definitions.push(field_class)
|
data/lib/graphql/type_kinds.rb
CHANGED
@@ -23,25 +23,6 @@ module GraphQL::TypeKinds
|
|
23
23
|
def to_s; @name; end
|
24
24
|
# Is this TypeKind composed of many values?
|
25
25
|
def composite?; @composite; end
|
26
|
-
|
27
|
-
# Get the implementing type for `value` from `type` (no-op for TypeKinds which don't `resolves?`)
|
28
|
-
def resolve(type, value)
|
29
|
-
if resolves?
|
30
|
-
type.resolve_type(value)
|
31
|
-
else
|
32
|
-
type
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Get the modified type for `type` (no-op for TypeKinds which don't `wraps?`)
|
37
|
-
def unwrap(type)
|
38
|
-
if wraps?
|
39
|
-
wrapped_type = type.of_type
|
40
|
-
wrapped_type.kind.unwrap(wrapped_type)
|
41
|
-
else
|
42
|
-
type
|
43
|
-
end
|
44
|
-
end
|
45
26
|
end
|
46
27
|
|
47
28
|
TYPE_KINDS = [
|
data/lib/graphql/union_type.rb
CHANGED
@@ -8,22 +8,12 @@
|
|
8
8
|
# possible_types [DogType, CatType, FishType]
|
9
9
|
# end
|
10
10
|
#
|
11
|
-
class GraphQL::UnionType
|
12
|
-
include GraphQL::
|
13
|
-
|
14
|
-
attr_accessor :name, :description, :possible_types, :resolve_type
|
11
|
+
class GraphQL::UnionType < GraphQL::BaseType
|
12
|
+
include GraphQL::BaseType::HasPossibleTypes
|
13
|
+
attr_accessor :name, :description, :possible_types
|
15
14
|
defined_by_config :name, :description, :possible_types, :resolve_type
|
16
15
|
|
17
16
|
def kind
|
18
17
|
GraphQL::TypeKinds::UNION
|
19
18
|
end
|
20
|
-
|
21
|
-
# @see {InterfaceType#resolve_type}
|
22
|
-
def resolve_type(object)
|
23
|
-
instance_exec(object, &@resolve_type_proc)
|
24
|
-
end
|
25
|
-
|
26
|
-
def resolve_type=(new_proc)
|
27
|
-
@resolve_type_proc = new_proc || GraphQL::InterfaceType::DEFAULT_RESOLVE_TYPE
|
28
|
-
end
|
29
19
|
end
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -95,20 +95,9 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
95
95
|
- if you were to request a field, then request it in a fragment, it would get looked up twice
|
96
96
|
- https://github.com/graphql/graphql-js/issues/19#issuecomment-118515077
|
97
97
|
- Code clean-up
|
98
|
-
- Easier built-in type definition
|
99
|
-
- Make an object that accepts type objects, symbols, or corresponding Ruby classes and convertes them to GraphQL types
|
100
|
-
- Hook up that object to `DefinitionConfig`, so it can map from incoming values to GraphQL types
|
101
98
|
- Raise if you try to configure an attribute which doesn't suit the type
|
102
99
|
- ie, if you try to define `resolve` on an ObjectType, it should somehow raise
|
103
|
-
- Make better inheritance between types
|
104
|
-
- Implement a BaseType (?) and make all type classes extend that
|
105
|
-
- No more extending ObjectType!
|
106
|
-
- Move `TypeKind#unwrap` to BaseType & update all code
|
107
|
-
- Also move `TypeKind#resolve` ?
|
108
100
|
- Big ideas:
|
109
|
-
- Cook up some path other than "n+1s everywhere"
|
110
|
-
- See Sangria's `project` approach ([in progress](https://github.com/rmosolgo/graphql-ruby/pull/15))
|
111
|
-
- Try debounced approach?
|
112
101
|
- Write Ruby bindings for [libgraphqlparser](https://github.com/graphql/libgraphqlparser) and use that instead of Parslet
|
113
102
|
- Add instrumentation
|
114
103
|
- Some way to expose what queries are run, what types & fields are accessed, how long things are taking, etc
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::BaseType do
|
4
|
+
it 'becomes non-null with !' do
|
5
|
+
type = GraphQL::EnumType.new
|
6
|
+
non_null_type = !type
|
7
|
+
assert_equal(GraphQL::TypeKinds::NON_NULL, non_null_type.kind)
|
8
|
+
assert_equal(type, non_null_type.of_type)
|
9
|
+
assert_equal(GraphQL::TypeKinds::NON_NULL, (!GraphQL::STRING_TYPE).kind)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'can be compared' do
|
13
|
+
assert_equal(!GraphQL::INT_TYPE, !GraphQL::INT_TYPE)
|
14
|
+
refute_equal(!GraphQL::FLOAT_TYPE, GraphQL::FLOAT_TYPE)
|
15
|
+
assert_equal(
|
16
|
+
GraphQL::ListType.new(of_type: MilkType),
|
17
|
+
GraphQL::ListType.new(of_type: MilkType)
|
18
|
+
)
|
19
|
+
refute_equal(
|
20
|
+
GraphQL::ListType.new(of_type: MilkType),
|
21
|
+
GraphQL::ListType.new(of_type: !MilkType)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|