graphql 0.10.9 → 0.11.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 +8 -5
- data/lib/graphql/definition_helpers/defined_by_config.rb +2 -1
- data/lib/graphql/field.rb +34 -7
- data/lib/graphql/input_object_type.rb +4 -3
- data/lib/graphql/invalid_null_error.rb +22 -0
- data/lib/graphql/language/nodes.rb +165 -58
- data/lib/graphql/language/transform.rb +5 -6
- data/lib/graphql/non_null_type.rb +0 -4
- data/lib/graphql/query.rb +1 -2
- data/lib/graphql/query/arguments.rb +39 -7
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/serial_execution.rb +30 -1
- data/lib/graphql/query/serial_execution/execution_context.rb +30 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +27 -21
- data/lib/graphql/query/serial_execution/operation_resolution.rb +9 -6
- data/lib/graphql/query/serial_execution/selection_resolution.rb +49 -56
- data/lib/graphql/query/{base_execution → serial_execution}/value_resolution.rb +35 -24
- data/lib/graphql/static_validation/complexity_validator.rb +27 -0
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +8 -4
- data/spec/graphql/execution_error_spec.rb +7 -1
- data/spec/graphql/field_spec.rb +53 -0
- data/spec/graphql/input_object_type_spec.rb +8 -1
- data/spec/graphql/introspection/schema_type_spec.rb +2 -1
- data/spec/graphql/language/transform_spec.rb +14 -14
- data/spec/graphql/object_type_spec.rb +7 -0
- data/spec/graphql/query/arguments_spec.rb +5 -5
- data/spec/graphql/query/executor_spec.rb +31 -0
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +55 -0
- data/spec/graphql/query/{base_execution → serial_execution}/value_resolution_spec.rb +1 -1
- data/spec/graphql/query/variables_spec.rb +1 -1
- data/spec/graphql/static_validation/complexity_validator.rb +15 -0
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +2 -1
- data/spec/graphql/static_validation/validator_spec.rb +1 -1
- data/spec/support/dairy_app.rb +15 -0
- data/spec/support/minimum_input_object.rb +13 -0
- metadata +14 -6
- data/lib/graphql/query/base_execution.rb +0 -32
@@ -1,6 +1,6 @@
|
|
1
1
|
module GraphQL
|
2
2
|
class Query
|
3
|
-
class
|
3
|
+
class SerialExecution
|
4
4
|
module ValueResolution
|
5
5
|
def self.get_strategy_for_kind(kind)
|
6
6
|
TYPE_KIND_STRATEGIES[kind] || raise("No value resolution strategy for #{kind}!")
|
@@ -8,29 +8,33 @@ module GraphQL
|
|
8
8
|
|
9
9
|
class BaseResolution
|
10
10
|
attr_reader :value, :field_type, :target, :parent_type,
|
11
|
-
:ast_field, :
|
12
|
-
def initialize(value, field_type, target, parent_type, ast_field,
|
11
|
+
:ast_field, :execution_context
|
12
|
+
def initialize(value, field_type, target, parent_type, ast_field, execution_context)
|
13
13
|
@value = value
|
14
14
|
@field_type = field_type
|
15
15
|
@target = target
|
16
16
|
@parent_type = parent_type
|
17
17
|
@ast_field = ast_field
|
18
|
-
@
|
19
|
-
@execution_strategy = execution_strategy
|
18
|
+
@execution_context = execution_context
|
20
19
|
end
|
21
20
|
|
22
21
|
def result
|
22
|
+
return nil if value.nil? || value.is_a?(GraphQL::ExecutionError)
|
23
|
+
non_null_result
|
24
|
+
end
|
25
|
+
|
26
|
+
def non_null_result
|
23
27
|
raise NotImplementedError, "Should return a value based on initialization params"
|
24
28
|
end
|
25
29
|
|
26
30
|
def get_strategy_for_kind(*args)
|
27
|
-
GraphQL::Query::
|
31
|
+
GraphQL::Query::SerialExecution::ValueResolution.get_strategy_for_kind(*args)
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
35
|
class ScalarResolution < BaseResolution
|
32
36
|
# Apply the scalar's defined `coerce_result` method to the value
|
33
|
-
def
|
37
|
+
def non_null_result
|
34
38
|
field_type.coerce_result(value)
|
35
39
|
end
|
36
40
|
end
|
@@ -38,39 +42,44 @@ module GraphQL
|
|
38
42
|
class ListResolution < BaseResolution
|
39
43
|
# For each item in the list,
|
40
44
|
# Resolve it with the "wrapped" type of this list
|
41
|
-
def
|
45
|
+
def non_null_result
|
42
46
|
wrapped_type = field_type.of_type
|
47
|
+
strategy_class = get_strategy_for_kind(wrapped_type.kind)
|
43
48
|
value.map do |item|
|
44
|
-
|
45
|
-
strategy_class = get_strategy_for_kind(resolved_type.kind)
|
46
|
-
inner_strategy = strategy_class.new(item, resolved_type, target, parent_type, ast_field, query, execution_strategy)
|
49
|
+
inner_strategy = strategy_class.new(item, wrapped_type, target, parent_type, ast_field, execution_context)
|
47
50
|
inner_strategy.result
|
48
51
|
end
|
49
52
|
end
|
50
53
|
end
|
51
54
|
|
52
|
-
class
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
class HasPossibleTypeResolution < BaseResolution
|
56
|
+
def non_null_result
|
57
|
+
resolved_type = field_type.resolve_type(value)
|
58
|
+
strategy_class = get_strategy_for_kind(resolved_type.kind)
|
59
|
+
inner_strategy = strategy_class.new(value, resolved_type, target, parent_type, ast_field, execution_context)
|
60
|
+
inner_strategy.result
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
60
|
-
class
|
61
|
-
#
|
62
|
-
def
|
63
|
-
|
64
|
+
class ObjectResolution < BaseResolution
|
65
|
+
# Resolve the selections on this object
|
66
|
+
def non_null_result
|
67
|
+
execution_context.strategy.selection_resolution.new(
|
68
|
+
value,
|
69
|
+
field_type,
|
70
|
+
ast_field.selections,
|
71
|
+
execution_context
|
72
|
+
).result
|
64
73
|
end
|
65
74
|
end
|
66
75
|
|
67
76
|
class NonNullResolution < BaseResolution
|
68
77
|
# Get the "wrapped" type and resolve the value according to that type
|
69
78
|
def result
|
79
|
+
raise GraphQL::InvalidNullError.new(ast_field.name, value) if value.nil? || value.is_a?(GraphQL::ExecutionError)
|
70
80
|
wrapped_type = field_type.of_type
|
71
|
-
|
72
|
-
|
73
|
-
inner_strategy = strategy_class.new(value, resolved_type, target, parent_type, ast_field, query, execution_strategy)
|
81
|
+
strategy_class = get_strategy_for_kind(wrapped_type.kind)
|
82
|
+
inner_strategy = strategy_class.new(value, wrapped_type, target, parent_type, ast_field, execution_context)
|
74
83
|
inner_strategy.result
|
75
84
|
end
|
76
85
|
end
|
@@ -79,8 +88,10 @@ module GraphQL
|
|
79
88
|
GraphQL::TypeKinds::SCALAR => ScalarResolution,
|
80
89
|
GraphQL::TypeKinds::LIST => ListResolution,
|
81
90
|
GraphQL::TypeKinds::OBJECT => ObjectResolution,
|
82
|
-
GraphQL::TypeKinds::ENUM =>
|
91
|
+
GraphQL::TypeKinds::ENUM => ScalarResolution,
|
83
92
|
GraphQL::TypeKinds::NON_NULL => NonNullResolution,
|
93
|
+
GraphQL::TypeKinds::INTERFACE => HasPossibleTypeResolution,
|
94
|
+
GraphQL::TypeKinds::UNION => HasPossibleTypeResolution,
|
84
95
|
}
|
85
96
|
end
|
86
97
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class GraphQL::StaticValidation::ComplexityValidator
|
2
|
+
include GraphQL::StaticValidation::Message::MessageHelper
|
3
|
+
|
4
|
+
def initialize(max_fields:, list_multiplier:)
|
5
|
+
@max_fields = max_fields
|
6
|
+
@list_multiplier = list_multiplier
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate(context)
|
10
|
+
visitor = context.visitor
|
11
|
+
complexity = 0
|
12
|
+
visitor[GraphQL::Language::Nodes::Field] << -> (node, parent) {
|
13
|
+
field_type = field_definition.type
|
14
|
+
if field_type.kind.list?
|
15
|
+
complexity += list_multiplier
|
16
|
+
else
|
17
|
+
complexity += 1
|
18
|
+
end
|
19
|
+
}
|
20
|
+
|
21
|
+
visitor[GraphQL::Language::Nodes::Document].exit << -> (node, parent) {
|
22
|
+
if complexity > @max_fields
|
23
|
+
context.errors << message("This query is too complex. Request fewer fields.", node)
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
@@ -29,16 +29,16 @@ class GraphQL::StaticValidation::LiteralValidator
|
|
29
29
|
.values
|
30
30
|
.select { |f| f.type.kind.non_null? }
|
31
31
|
.map(&:name)
|
32
|
-
present_field_names = ast_node.
|
32
|
+
present_field_names = ast_node.arguments.map(&:name)
|
33
33
|
missing_required_field_names = required_field_names - present_field_names
|
34
34
|
missing_required_field_names.none?
|
35
35
|
end
|
36
36
|
|
37
37
|
def present_input_field_values_are_valid(type, ast_node)
|
38
38
|
fields = type.input_fields
|
39
|
-
ast_node.
|
40
|
-
|
41
|
-
|
39
|
+
ast_node.arguments.all? do |value|
|
40
|
+
field = fields[value.name]
|
41
|
+
field ? validate(value.value, field.type) : true
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -3,6 +3,7 @@ class GraphQL::StaticValidation::ArgumentLiteralsAreCompatible < GraphQL::Static
|
|
3
3
|
return if node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
4
4
|
validator = GraphQL::StaticValidation::LiteralValidator.new
|
5
5
|
arg_defn = defn.arguments[node.name]
|
6
|
+
return unless arg_defn
|
6
7
|
valid = validator.validate(node.value, arg_defn.type)
|
7
8
|
if !valid
|
8
9
|
kind_of_node = node_type(parent)
|
@@ -3,7 +3,7 @@ class GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped
|
|
3
3
|
|
4
4
|
def validate(context)
|
5
5
|
literal_validator = GraphQL::StaticValidation::LiteralValidator.new
|
6
|
-
context.visitor[GraphQL::Language::Nodes::
|
6
|
+
context.visitor[GraphQL::Language::Nodes::VariableDefinition] << -> (node, parent) {
|
7
7
|
if !node.default_value.nil?
|
8
8
|
validate_default_value(node, literal_validator, context)
|
9
9
|
end
|
@@ -2,7 +2,7 @@ class GraphQL::StaticValidation::VariablesAreInputTypes
|
|
2
2
|
include GraphQL::StaticValidation::Message::MessageHelper
|
3
3
|
|
4
4
|
def validate(context)
|
5
|
-
context.visitor[GraphQL::Language::Nodes::
|
5
|
+
context.visitor[GraphQL::Language::Nodes::VariableDefinition] << -> (node, parent) {
|
6
6
|
validate_is_input_type(node, context)
|
7
7
|
}
|
8
8
|
end
|
@@ -42,7 +42,7 @@ class GraphQL::StaticValidation::Validator
|
|
42
42
|
def initialize(schema, document)
|
43
43
|
@schema = schema
|
44
44
|
@document = document
|
45
|
-
@fragments = document.
|
45
|
+
@fragments = document.definitions.each_with_object({}) do |part, memo|
|
46
46
|
part.is_a?(GraphQL::Language::Nodes::FragmentDefinition) && memo[part.name] = part
|
47
47
|
end
|
48
48
|
@errors = []
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -102,6 +102,7 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
102
102
|
https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-first-relay-powered-react-component-cb3f9ee95eca
|
103
103
|
|
104
104
|
#### Tutorials
|
105
|
+
|
105
106
|
1. https://medium.com/@khor/relay-facebook-on-rails-8b4af2057152
|
106
107
|
2. https://blog.jacobwgillespie.com/from-rest-to-graphql-b4e95e94c26b#.4cjtklrwt
|
107
108
|
3. http://mgiroux.me/2015/getting-started-with-rails-graphql-relay/
|
@@ -111,12 +112,15 @@ https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-first-relay-powered-
|
|
111
112
|
|
112
113
|
- Code clean-up
|
113
114
|
- Raise if you try to configure an attribute which doesn't suit the type (ie, if you try to define `resolve` on an ObjectType, it should somehow raise)
|
114
|
-
-
|
115
|
-
- Accept strings for circular type references
|
115
|
+
- make `DefinitionHelpers` more friendly for extension
|
116
116
|
- Interface's possible types should be a property of the schema, not the interface
|
117
|
-
-
|
117
|
+
- Type lookup should be by type name (to support reloaded constants in Rails code)
|
118
|
+
- Add a complexity validator (reject queries if they're too big)
|
119
|
+
- Add a custom dump for Relay (it expects default value strings to be double-quoted)
|
120
|
+
- Make variable validation provide a specific, useful message
|
121
|
+
- Add docs for shared behaviors & DRY code
|
122
|
+
- After releasing the next version, use it for [graphql-libgraphqlparser](https://github.com/rmosolgo/graphql-libgraphqlparser-ruby)
|
118
123
|
- Big ideas:
|
119
|
-
- Use [graphql-parser](https://github.com/shopify/graphql-parser) (Ruby bindings for [libgraphqlparser](https://github.com/graphql/libgraphqlparser)) instead of Parslet ([underway-ish](https://github.com/rmosolgo/graphql-libgraphqlparser-ruby))
|
120
124
|
- Revamp the fixture Schema to be more useful (better names, more extensible)
|
121
125
|
- __Subscriptions__
|
122
126
|
- This is a good chance to make an `Operation` abstraction of which `query`, `mutation` and `subscription` are members
|
@@ -18,6 +18,7 @@ describe GraphQL::ExecutionError do
|
|
18
18
|
}
|
19
19
|
flavor
|
20
20
|
}
|
21
|
+
executionError
|
21
22
|
}
|
22
23
|
|
23
24
|
fragment similarCheeseFields on Cheese {
|
@@ -36,7 +37,8 @@ describe GraphQL::ExecutionError do
|
|
36
37
|
"flavor" => "Manchego",
|
37
38
|
},
|
38
39
|
"flavor" => "Brie",
|
39
|
-
}
|
40
|
+
},
|
41
|
+
"executionError" => nil,
|
40
42
|
},
|
41
43
|
"errors"=>[
|
42
44
|
{
|
@@ -47,6 +49,10 @@ describe GraphQL::ExecutionError do
|
|
47
49
|
"message"=>"No cheeses are made from Yak milk!",
|
48
50
|
"locations"=>[{"line"=>8, "column"=>9}]
|
49
51
|
},
|
52
|
+
{
|
53
|
+
"message"=>"There was an execution error",
|
54
|
+
"locations"=>[{"line"=>16, "column"=>7}]
|
55
|
+
},
|
50
56
|
]
|
51
57
|
}
|
52
58
|
assert_equal(expected_result, result)
|
data/spec/graphql/field_spec.rb
CHANGED
@@ -5,6 +5,59 @@ describe GraphQL::Field do
|
|
5
5
|
field = GraphQL::Field.define do
|
6
6
|
type(-> { DairyProductUnion })
|
7
7
|
end
|
8
|
+
|
8
9
|
assert_equal(DairyProductUnion, field.type)
|
9
10
|
end
|
11
|
+
|
12
|
+
it "accepts a string as a type" do
|
13
|
+
field = GraphQL::Field.define do
|
14
|
+
type("DairyProductUnion")
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_equal(DairyProductUnion, field.type)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe '.property ' do
|
22
|
+
let(:field) do
|
23
|
+
GraphQL::Field.define do
|
24
|
+
# satisfies 'can define by config' below
|
25
|
+
property :internal_prop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can define by config' do
|
30
|
+
assert_equal(field.property, :internal_prop)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'has nil property if not defined' do
|
34
|
+
no_prop_field = GraphQL::Field.define { }
|
35
|
+
assert_equal(no_prop_field.property, nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'default resolver' do
|
39
|
+
def acts_like_default_resolver(field, old_prop, new_prop)
|
40
|
+
object = OpenStruct.new(old_prop => 'old value', new_prop => 'new value')
|
41
|
+
|
42
|
+
old_result = field.resolve(object, nil, nil)
|
43
|
+
field.property = new_prop
|
44
|
+
new_result = field.resolve(object, nil, nil)
|
45
|
+
field.property = nil
|
46
|
+
unset_result = field.resolve(object, nil, nil)
|
47
|
+
|
48
|
+
assert_equal(old_result, 'old value')
|
49
|
+
assert_equal(new_result, 'new value')
|
50
|
+
assert_equal(unset_result, GraphQL::Query::DEFAULT_RESOLVE)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'responds to changes in property' do
|
54
|
+
acts_like_default_resolver(field, :internal_prop, :new_prop)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'is reassigned if resolve is set to nil' do
|
58
|
+
field.resolve = nil
|
59
|
+
acts_like_default_resolver(field, :internal_prop, :new_prop)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
10
63
|
end
|
@@ -10,12 +10,19 @@ describe GraphQL::InputObjectType do
|
|
10
10
|
assert(DairyProductInputType.input_fields["fatContent"])
|
11
11
|
end
|
12
12
|
|
13
|
+
describe "input validation" do
|
14
|
+
it "Accepts anything that yields key-value pairs to #all?" do
|
15
|
+
values_obj = MinimumInputObject.new
|
16
|
+
assert DairyProductInputType.valid_non_null_input?(values_obj)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
13
20
|
describe "when sent into a query" do
|
14
21
|
let(:variables) { {} }
|
15
22
|
let(:result) { DummySchema.execute(query_string, variables: variables) }
|
16
23
|
|
17
24
|
describe "list inputs" do
|
18
|
-
let(:variables) { {"search" => [
|
25
|
+
let(:variables) { {"search" => [MinimumInputObject.new]} }
|
19
26
|
let(:query_string) {%|
|
20
27
|
query getCheeses($search: [DairyProductInput]!){
|
21
28
|
sheep: searchDairy(product: [{source: SHEEP, fatContent: 0.1}]) {
|
@@ -45,11 +45,11 @@ describe GraphQL::Language::Transform do
|
|
45
45
|
}
|
46
46
|
|
|
47
47
|
res = get_result(query, debug: false)
|
48
|
-
assert_equal(4, res.
|
48
|
+
assert_equal(4, res.definitions.length)
|
49
49
|
|
50
50
|
res = get_result("{ me {id, birthdate} } # query shorthand")
|
51
|
-
assert_equal(1, res.
|
52
|
-
assert_equal("me", res.
|
51
|
+
assert_equal(1, res.definitions.length)
|
52
|
+
assert_equal("me", res.definitions.first.selections.first.name)
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'transforms operation definitions' do
|
@@ -117,16 +117,16 @@ describe GraphQL::Language::Transform do
|
|
117
117
|
res_empty = get_result(%q|{}|, parse: :value_input_object)
|
118
118
|
res_empty_space = get_result(%q|{ }|, parse: :value_input_object)
|
119
119
|
|
120
|
-
assert_equal('one', res_one_pair.
|
121
|
-
assert_equal(1 , res_one_pair.
|
120
|
+
assert_equal('one', res_one_pair.arguments[0].name)
|
121
|
+
assert_equal(1 , res_one_pair.arguments[0].value)
|
122
122
|
|
123
|
-
assert_equal('first' , res_two_pair.
|
124
|
-
assert_equal('Apple' , res_two_pair.
|
125
|
-
assert_equal('second', res_two_pair.
|
126
|
-
assert_equal('Banana', res_two_pair.
|
123
|
+
assert_equal('first' , res_two_pair.arguments[0].name)
|
124
|
+
assert_equal('Apple' , res_two_pair.arguments[0].value)
|
125
|
+
assert_equal('second', res_two_pair.arguments[1].name)
|
126
|
+
assert_equal('Banana', res_two_pair.arguments[1].value)
|
127
127
|
|
128
|
-
assert_equal([], res_empty.
|
129
|
-
assert_equal([], res_empty_space.
|
128
|
+
assert_equal([], res_empty.arguments)
|
129
|
+
assert_equal([], res_empty_space.arguments)
|
130
130
|
end
|
131
131
|
|
132
132
|
it 'transforms directives' do
|
@@ -141,12 +141,12 @@ describe GraphQL::Language::Transform do
|
|
141
141
|
end
|
142
142
|
|
143
143
|
it 'transforms unnamed operations' do
|
144
|
-
assert_equal(1, get_result("query { me }").
|
145
|
-
assert_equal(1, get_result("mutation { touch }").
|
144
|
+
assert_equal(1, get_result("query { me }").definitions.length)
|
145
|
+
assert_equal(1, get_result("mutation { touch }").definitions.length)
|
146
146
|
end
|
147
147
|
|
148
148
|
it 'transforms escaped characters' do
|
149
149
|
res = get_result("{quoted: \"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"}", parse: :value_input_object)
|
150
|
-
assert_equal("\" \\ / \b \f \n \r \t", res.
|
150
|
+
assert_equal("\" \\ / \b \f \n \r \t", res.arguments[0].value)
|
151
151
|
end
|
152
152
|
end
|
@@ -24,5 +24,12 @@ describe GraphQL::ObjectType do
|
|
24
24
|
assert_equal(GraphQL::TypeKinds::NON_NULL, field.type.kind)
|
25
25
|
assert_equal(GraphQL::TypeKinds::SCALAR, field.type.of_type.kind)
|
26
26
|
end
|
27
|
+
|
28
|
+
it 'exposes defined field property' do
|
29
|
+
field_without_prop = CheeseType.fields['flavor']
|
30
|
+
field_with_prop = CheeseType.fields['fatContent']
|
31
|
+
assert_equal(field_without_prop.property, nil)
|
32
|
+
assert_equal(field_with_prop.property, :fat_content)
|
33
|
+
end
|
27
34
|
end
|
28
35
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe GraphQL::Query::Arguments do
|
4
|
-
let(:arguments) { GraphQL::Query::Arguments.new({ a: 1, b: 2 }) }
|
4
|
+
let(:arguments) { GraphQL::Query::Arguments.new({ a: 1, b: 2, c: GraphQL::Query::Arguments.new({ d: 3, e: 4}) }) }
|
5
5
|
|
6
6
|
it 'returns keys as strings' do
|
7
|
-
assert_equal(['a', 'b'], arguments.keys)
|
7
|
+
assert_equal(['a', 'b', 'c'], arguments.keys)
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'delegates values to values hash' do
|
11
|
-
assert_equal([1, 2], arguments.values)
|
11
|
+
assert_equal([1, 2, {'d' => 3, 'e' => 4}], arguments.values)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'delegates each to values hash' do
|
@@ -16,10 +16,10 @@ describe GraphQL::Query::Arguments do
|
|
16
16
|
arguments.each do |key, value|
|
17
17
|
pairs << [key, value]
|
18
18
|
end
|
19
|
-
assert_equal([['a', 1], ['b', 2]], pairs)
|
19
|
+
assert_equal([['a', 1], ['b', 2], ['c', {'d' => 3, 'e' => 4}]], pairs)
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'returns original Ruby hash values with to_h' do
|
23
|
-
assert_equal({ a: 1, b: 2 }, arguments.to_h)
|
23
|
+
assert_equal({ a: 1, b: 2, c: { d: 3, e: 4 } }, arguments.to_h)
|
24
24
|
end
|
25
25
|
end
|