graphql 0.9.3 → 0.9.4
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 +1 -0
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/execution_error.rb +27 -0
- data/lib/graphql/query/base_execution.rb +3 -10
- data/lib/graphql/query/base_execution/value_resolution.rb +6 -0
- data/lib/graphql/query/context.rb +13 -1
- data/lib/graphql/query/executor.rb +20 -3
- data/lib/graphql/query/serial_execution/field_resolution.rb +11 -3
- data/lib/graphql/version.rb +1 -1
- data/readme.md +7 -7
- data/spec/graphql/execution_error_spec.rb +55 -0
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/query/type_resolver_spec.rb +8 -0
- data/spec/graphql/query_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +5 -5
- data/spec/graphql/union_type_spec.rb +9 -0
- data/spec/support/dairy_app.rb +24 -5
- data/spec/support/dairy_data.rb +6 -0
- metadata +7 -3
- data/lib/graphql/query/base_execution/selected_object_resolution.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7a6017d64f6fd507c50ac439cd6509e2fb163cd
|
4
|
+
data.tar.gz: 43f4acf1bd7a7b7bf43b9b0df7e87d34cea37339
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 313db517b3541bbf8f21a7d1fba1eb257d4be306e44e33f9f6f511d0d3fbfb034cfeca667a2025038bc85b88513fa329db7003922948dd64a78633c44231eb2c
|
7
|
+
data.tar.gz: 2a86be1427279e98dfb940ac59f2b8669c6d9638ad8a414a34ba80ee87a9d32bcde0a5ccef2d9c660d033b8d6a7be7ad0c1902869a33c5fe711b24d4cf9512b8
|
data/lib/graphql.rb
CHANGED
data/lib/graphql/base_type.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
module GraphQL
|
2
|
+
# If a field's resolve function returns a {ExecutionError},
|
3
|
+
# the error will be inserted into the response's `"errors"` key
|
4
|
+
# and the field will resolve to `nil`.
|
5
|
+
class ExecutionError < RuntimeError
|
6
|
+
# @return [GraphQL::Language::Nodes::Field] the field where the error occured
|
7
|
+
attr_accessor :ast_node
|
8
|
+
|
9
|
+
# @return [Hash] An entry for the response's "errors" key
|
10
|
+
def to_h
|
11
|
+
hash = {
|
12
|
+
"message" => message,
|
13
|
+
}
|
14
|
+
if ast_node.nil?
|
15
|
+
hash["locations"] = []
|
16
|
+
else
|
17
|
+
hash["locations"] = [
|
18
|
+
{
|
19
|
+
"line" => ast_node.line,
|
20
|
+
"column" => ast_node.col,
|
21
|
+
}
|
22
|
+
]
|
23
|
+
end
|
24
|
+
hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'graphql/query/base_execution/selected_object_resolution'
|
2
1
|
require 'graphql/query/base_execution/value_resolution'
|
3
2
|
|
4
3
|
module GraphQL
|
@@ -18,21 +17,15 @@ module GraphQL
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def field_resolution
|
21
|
-
|
20
|
+
self.class::FieldResolution
|
22
21
|
end
|
23
22
|
|
24
23
|
def operation_resolution
|
25
|
-
|
24
|
+
self.class::OperationResolution
|
26
25
|
end
|
27
26
|
|
28
27
|
def selection_resolution
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def get_class(class_name)
|
35
|
-
self.class.const_get(class_name)
|
28
|
+
self.class::SelectionResolution
|
36
29
|
end
|
37
30
|
end
|
38
31
|
end
|
@@ -29,12 +29,15 @@ module GraphQL
|
|
29
29
|
end
|
30
30
|
|
31
31
|
class ScalarResolution < BaseResolution
|
32
|
+
# Apply the scalar's defined `coerce` method to the value
|
32
33
|
def result
|
33
34
|
field_type.coerce(value)
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
class ListResolution < BaseResolution
|
39
|
+
# For each item in the list,
|
40
|
+
# Resolve it with the "wrapped" type of this list
|
38
41
|
def result
|
39
42
|
wrapped_type = field_type.of_type
|
40
43
|
value.map do |item|
|
@@ -47,6 +50,7 @@ module GraphQL
|
|
47
50
|
end
|
48
51
|
|
49
52
|
class ObjectResolution < BaseResolution
|
53
|
+
# Resolve the selections on this object
|
50
54
|
def result
|
51
55
|
resolver = execution_strategy.selection_resolution.new(value, field_type, ast_field.selections, query, execution_strategy)
|
52
56
|
resolver.result
|
@@ -54,12 +58,14 @@ module GraphQL
|
|
54
58
|
end
|
55
59
|
|
56
60
|
class EnumResolution < BaseResolution
|
61
|
+
# Get the string name for this enum value
|
57
62
|
def result
|
58
63
|
value.to_s
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
62
67
|
class NonNullResolution < BaseResolution
|
68
|
+
# Get the "wrapped" type and resolve the value according to that type
|
63
69
|
def result
|
64
70
|
wrapped_type = field_type.of_type
|
65
71
|
resolved_type = wrapped_type.resolve_type(value)
|
@@ -3,11 +3,23 @@ module GraphQL
|
|
3
3
|
# Expose some query-specific info to field resolve functions.
|
4
4
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
5
5
|
class Context
|
6
|
-
attr_accessor :execution_strategy
|
6
|
+
attr_accessor :execution_strategy
|
7
|
+
|
8
|
+
# The {GraphQL::Language::Nodes::Field} for the currently-executing field.
|
9
|
+
# @return [GraphQL::Language::Nodes::Field]
|
10
|
+
attr_accessor :ast_node
|
11
|
+
|
12
|
+
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
13
|
+
attr_reader :errors
|
14
|
+
|
15
|
+
# Make a new context which delegates key lookup to `values`
|
16
|
+
# @param [Hash] A hash of arbitrary values which will be accessible at query-time
|
7
17
|
def initialize(values:)
|
8
18
|
@values = values
|
19
|
+
@errors = []
|
9
20
|
end
|
10
21
|
|
22
|
+
# Lookup `key` from the hash passed to {Schema#execute} as `context`
|
11
23
|
def [](key)
|
12
24
|
@values[key]
|
13
25
|
end
|
@@ -8,14 +8,23 @@ module GraphQL
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
# @return [GraphQL::Query] the query being executed
|
12
|
+
attr_reader :query
|
13
|
+
|
14
|
+
# @return [String] the operation to run in {query}
|
15
|
+
attr_reader :operation_name
|
16
|
+
|
17
|
+
|
12
18
|
def initialize(query, operation_name)
|
13
19
|
@query = query
|
14
20
|
@operation_name = operation_name
|
15
21
|
end
|
16
22
|
|
23
|
+
# Evalute {operation_name} on {query}. Handle errors by putting them in the "errors" key.
|
24
|
+
# (Or, if `query.debug`, by re-raising them.)
|
25
|
+
# @return [Hash] A GraphQL response, with either a "data" key or an "errors" key
|
17
26
|
def result
|
18
|
-
|
27
|
+
execute
|
19
28
|
rescue OperationNameMissingError => err
|
20
29
|
{"errors" => [{"message" => err.message}]}
|
21
30
|
rescue StandardError => err
|
@@ -38,7 +47,15 @@ module GraphQL
|
|
38
47
|
end
|
39
48
|
execution_strategy = execution_strategy_class.new
|
40
49
|
query.context.execution_strategy = execution_strategy
|
41
|
-
|
50
|
+
data_result = execution_strategy.execute(operation, root_type, query)
|
51
|
+
result = { "data" => data_result }
|
52
|
+
error_result = query.context.errors.map(&:to_h)
|
53
|
+
|
54
|
+
if error_result.any?
|
55
|
+
result["errors"] = error_result
|
56
|
+
end
|
57
|
+
|
58
|
+
result
|
42
59
|
end
|
43
60
|
|
44
61
|
def find_operation(operation_name, operations)
|
@@ -1,11 +1,15 @@
|
|
1
1
|
module GraphQL
|
2
2
|
class Query
|
3
3
|
class SerialExecution
|
4
|
-
class FieldResolution
|
5
|
-
attr_reader :field, :arguments
|
4
|
+
class FieldResolution
|
5
|
+
attr_reader :ast_node, :parent_type, :target, :query, :execution_strategy, :field, :arguments
|
6
6
|
|
7
7
|
def initialize(ast_node, parent_type, target, query, execution_strategy)
|
8
|
-
|
8
|
+
@ast_node = ast_node
|
9
|
+
@parent_type = parent_type
|
10
|
+
@target = target
|
11
|
+
@query = query
|
12
|
+
@execution_strategy = execution_strategy
|
9
13
|
@field = query.schema.get_field(parent_type, ast_node.name) || raise("No field found on #{parent_type.name} '#{parent_type}' for '#{ast_node.name}'")
|
10
14
|
@arguments = GraphQL::Query::Arguments.new(ast_node.arguments, field.arguments, query.variables)
|
11
15
|
end
|
@@ -21,6 +25,10 @@ module GraphQL
|
|
21
25
|
def get_finished_value(raw_value)
|
22
26
|
if raw_value.nil?
|
23
27
|
nil
|
28
|
+
elsif raw_value.is_a?(GraphQL::ExecutionError)
|
29
|
+
raw_value.ast_node = ast_node
|
30
|
+
query.context.errors << raw_value
|
31
|
+
nil
|
24
32
|
else
|
25
33
|
resolved_type = field.type.resolve_type(raw_value)
|
26
34
|
strategy_class = GraphQL::Query::BaseExecution::ValueResolution.get_strategy_for_kind(resolved_type.kind)
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -6,6 +6,8 @@
|
|
6
6
|
[](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
7
7
|
[](http://rmosolgo.github.io/react-badges/)
|
8
8
|
|
9
|
+
A Ruby implementation of [GraphQL](http://graphql.org/).
|
10
|
+
|
9
11
|
- [Introduction](https://github.com/rmosolgo/graphql-ruby/blob/master/guides/introduction.md)
|
10
12
|
- [API Documentation](http://www.rubydoc.info/github/rmosolgo/graphql-ruby)
|
11
13
|
|
@@ -92,13 +94,13 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
92
94
|
- Code clean-up
|
93
95
|
- Raise if you try to configure an attribute which doesn't suit the type
|
94
96
|
- ie, if you try to define `resolve` on an ObjectType, it should somehow raise
|
97
|
+
- Incoming enums should be exposed as `EnumValue`s, not `Nodes::Enum`s
|
95
98
|
- Big ideas:
|
96
|
-
-
|
99
|
+
- Use [graphql-parser](https://github.com/shopify/graphql-parser) (Ruby bindings for [libgraphqlparser](https://github.com/graphql/libgraphqlparser)) instead of Parslet
|
97
100
|
- Add instrumentation
|
98
101
|
- Some way to expose what queries are run, what types & fields are accessed, how long things are taking, etc
|
99
102
|
- before-hooks for every field?
|
100
103
|
|
101
|
-
|
102
104
|
## Goals
|
103
105
|
|
104
106
|
- Implement the GraphQL spec & support a Relay front end
|
@@ -112,14 +114,12 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
112
114
|
- __Features & patches__ are welcome! Consider discussing it in an [issue](https://github.com/rmosolgo/graphql-ruby/issues) or in the [#ruby channel on Slack](https://graphql-slack.herokuapp.com/) to make sure we're on the same page.
|
113
115
|
- __Run the tests__ with `rake test` or start up guard with `bundle exec guard`.
|
114
116
|
|
115
|
-
##
|
117
|
+
## Related Projects
|
116
118
|
|
117
|
-
- [GraphQL Spec](http://facebook.github.io/graphql/)
|
118
|
-
- Other implementations: [graphql-links](https://github.com/emmenko/graphql-links)
|
119
119
|
- `graphql-ruby` + Rails demo ([src](https://github.com/rmosolgo/graphql-ruby-demo) / [heroku](http://graphql-ruby-demo.herokuapp.com))
|
120
|
-
- [
|
121
|
-
- [Example Relay support](https://github.com/rmosolgo/graphql-relay-ruby) in Ruby
|
120
|
+
- [`graphql-batch`](https://github.com/shopify/graphql-batch), a batched query execution strategy
|
122
121
|
- [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel), an asynchronous query execution strategy
|
122
|
+
- [Example Relay support](https://github.com/rmosolgo/graphql-relay-ruby) in Ruby
|
123
123
|
|
124
124
|
## P.S.
|
125
125
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::ExecutionError do
|
4
|
+
let(:result) { DummySchema.execute(query_string) }
|
5
|
+
describe "when returned from a field" do
|
6
|
+
let(:query_string) {%|
|
7
|
+
{
|
8
|
+
cheese(id: 1) {
|
9
|
+
id
|
10
|
+
error1: similarCheese(source: [YAK]) {
|
11
|
+
... similarCheeseFields
|
12
|
+
}
|
13
|
+
error2: similarCheese(source: [YAK]) {
|
14
|
+
... similarCheeseFields
|
15
|
+
}
|
16
|
+
nonError: similarCheese(source: [SHEEP]) {
|
17
|
+
... similarCheeseFields
|
18
|
+
}
|
19
|
+
flavor
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
fragment similarCheeseFields on Cheese {
|
24
|
+
id, flavor
|
25
|
+
}
|
26
|
+
|}
|
27
|
+
it "the error is inserted into the errors key and the rest of the query is fulfilled" do
|
28
|
+
expected_result = {
|
29
|
+
"data"=>{
|
30
|
+
"cheese"=>{
|
31
|
+
"id" => 1,
|
32
|
+
"error1"=> nil,
|
33
|
+
"error2"=> nil,
|
34
|
+
"nonError"=> {
|
35
|
+
"id" => 3,
|
36
|
+
"flavor" => "Manchego",
|
37
|
+
},
|
38
|
+
"flavor" => "Brie",
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"errors"=>[
|
42
|
+
{
|
43
|
+
"message"=>"No cheeses are made from Yak milk!",
|
44
|
+
"locations"=>[{"line"=>5, "column"=>9}]
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"message"=>"No cheeses are made from Yak milk!",
|
48
|
+
"locations"=>[{"line"=>8, "column"=>9}]
|
49
|
+
},
|
50
|
+
]
|
51
|
+
}
|
52
|
+
assert_equal(expected_result, result)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -15,7 +15,7 @@ describe GraphQL::Introspection::TypeType do
|
|
15
15
|
{"name"=>"id", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "Int"}}},
|
16
16
|
{"name"=>"flavor", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "String"}}},
|
17
17
|
{"name"=>"source", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "DairyAnimal"}}},
|
18
|
-
{"name"=>"
|
18
|
+
{"name"=>"similarCheese", "isDeprecated"=>false, "type"=>{"name"=>"Cheese", "ofType"=>nil}},
|
19
19
|
]}
|
20
20
|
|
21
21
|
let(:dairy_animals) {[
|
data/spec/graphql/query_spec.rb
CHANGED
@@ -63,7 +63,7 @@ describe GraphQL::Query do
|
|
63
63
|
maybeNull {
|
64
64
|
cheese {
|
65
65
|
flavor,
|
66
|
-
|
66
|
+
similarCheese(source: [SHEEP]) { flavor }
|
67
67
|
}
|
68
68
|
}
|
69
69
|
}
|
@@ -147,14 +147,14 @@ describe GraphQL::Query do
|
|
147
147
|
describe "whitespace-only" do
|
148
148
|
let(:query_string) { " " }
|
149
149
|
it "doesn't blow up" do
|
150
|
-
assert_equal({
|
150
|
+
assert_equal({}, result)
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
154
|
describe "empty string" do
|
155
155
|
let(:query_string) { "" }
|
156
156
|
it "doesn't blow up" do
|
157
|
-
assert_equal({
|
157
|
+
assert_equal({}, result)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
end
|
@@ -10,7 +10,7 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
|
|
10
10
|
}
|
11
11
|
|
12
12
|
fragment cheeseFields on Cheese {
|
13
|
-
|
13
|
+
similarCheese(source: 4.5)
|
14
14
|
}
|
15
15
|
|)}
|
16
16
|
|
@@ -33,7 +33,7 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
|
|
33
33
|
assert_includes(errors, input_object_error)
|
34
34
|
|
35
35
|
fragment_error = {
|
36
|
-
"message"=>"Argument source on Field '
|
36
|
+
"message"=>"Argument source on Field 'similarCheese' has an invalid value",
|
37
37
|
"locations"=>[{"line"=>10, "column"=>7}]
|
38
38
|
}
|
39
39
|
assert_includes(errors, fragment_error)
|
@@ -8,7 +8,7 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
|
|
8
8
|
}
|
9
9
|
|
10
10
|
fragment cheeseFields on Cheese {
|
11
|
-
|
11
|
+
similarCheese(source: SHEEP, nonsense: 1)
|
12
12
|
id @skip(something: 3.4)
|
13
13
|
}
|
14
14
|
")}
|
@@ -26,7 +26,7 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
|
|
26
26
|
assert_includes(errors, query_root_error)
|
27
27
|
|
28
28
|
fragment_error = {
|
29
|
-
"message"=>"Field '
|
29
|
+
"message"=>"Field 'similarCheese' doesn't accept argument nonsense",
|
30
30
|
"locations"=>[{"line"=>8, "column"=>7}]
|
31
31
|
}
|
32
32
|
assert_includes(errors, fragment_error)
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
|
4
4
|
let(:document) { GraphQL.parse("
|
5
5
|
query getCheese {
|
6
|
-
okCheese: cheese(id: 1) { fatContent,
|
6
|
+
okCheese: cheese(id: 1) { fatContent, similarCheese(source: YAK) { source } }
|
7
7
|
missingFieldsCheese: cheese(id: 1)
|
8
8
|
illegalSelectionCheese: cheese(id: 1) { id { something, ... someFields } }
|
9
9
|
}
|
@@ -9,22 +9,22 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
9
9
|
nickname: fatContent,
|
10
10
|
fatContent
|
11
11
|
differentLevel: fatContent
|
12
|
-
|
12
|
+
similarCheese(source: $sourceVar)
|
13
13
|
|
14
|
-
similarCow:
|
14
|
+
similarCow: similarCheese(source: COW) {
|
15
15
|
similarCowSource: source,
|
16
16
|
differentLevel: fatContent
|
17
17
|
}
|
18
18
|
...cheeseFields
|
19
19
|
... on Cheese {
|
20
20
|
fatContent: name
|
21
|
-
|
21
|
+
similarCheese(source: SHEEP)
|
22
22
|
}
|
23
23
|
}
|
24
24
|
}
|
25
25
|
fragment cheeseFields on Cheese {
|
26
26
|
fatContent,
|
27
|
-
similarCow:
|
27
|
+
similarCow: similarCheese(source: COW) { similarCowSource: id, id }
|
28
28
|
id @someFlag
|
29
29
|
}
|
30
30
|
")}
|
@@ -39,7 +39,7 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
39
39
|
"Field 'id' has a directive argument conflict: [] or [{}]?", # not sure this is a great way to handle it but here we are!
|
40
40
|
"Field 'nickname' has a field conflict: name or fatContent?", # alias conflict in query
|
41
41
|
"Field 'fatContent' has a field conflict: fatContent or name?", # alias/name conflict in query and fragment
|
42
|
-
"Field '
|
42
|
+
"Field 'similarCheese' has an argument conflict: {\"source\":\"sourceVar\"} or {\"source\":\"SHEEP\"}?", # different arguments
|
43
43
|
"Field 'similarCowSource' has a field conflict: source or id?", # nested conflict
|
44
44
|
]
|
45
45
|
assert_equal(expected_errors, error_messages)
|
@@ -8,7 +8,7 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
|
|
8
8
|
}
|
9
9
|
|
10
10
|
fragment cheeseFields on Cheese {
|
11
|
-
|
11
|
+
similarCheese(id: 1)
|
12
12
|
flavor @include(if: true)
|
13
13
|
id @skip
|
14
14
|
}
|
@@ -27,7 +27,7 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
|
|
27
27
|
assert_includes(errors, query_root_error)
|
28
28
|
|
29
29
|
fragment_error = {
|
30
|
-
"message"=>"Field '
|
30
|
+
"message"=>"Field 'similarCheese' is missing required arguments: source",
|
31
31
|
"locations"=>[{"line"=>8, "column"=>7}]
|
32
32
|
}
|
33
33
|
assert_includes(errors, fragment_error)
|
@@ -16,9 +16,9 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
|
|
16
16
|
badCheese: cheese(id: $badInt) { source }
|
17
17
|
badStrCheese: cheese(id: $badStr) { source }
|
18
18
|
cheese(id: 1) {
|
19
|
-
|
20
|
-
other:
|
21
|
-
tooDeep:
|
19
|
+
similarCheese(source: $goodAnimals)
|
20
|
+
other: similarCheese(source: $badAnimals)
|
21
|
+
tooDeep: similarCheese(source: $deepAnimals)
|
22
22
|
}
|
23
23
|
|
24
24
|
milk(id: 1) {
|
@@ -43,11 +43,11 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
|
|
43
43
|
},
|
44
44
|
{
|
45
45
|
"message"=>"Nullability mismatch on variable $badAnimals and argument source ([DairyAnimal]! / [DairyAnimal!]!)",
|
46
|
-
"locations"=>[{"line"=>17, "column"=>
|
46
|
+
"locations"=>[{"line"=>17, "column"=>30}]
|
47
47
|
},
|
48
48
|
{
|
49
49
|
"message"=>"List dimension mismatch on variable $deepAnimals and argument source ([[DairyAnimal!]!]! / [DairyAnimal!]!)",
|
50
|
-
"locations"=>[{"line"=>18, "column"=>
|
50
|
+
"locations"=>[{"line"=>18, "column"=>32}]
|
51
51
|
}
|
52
52
|
]
|
53
53
|
assert_equal(expected, errors)
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe GraphQL::UnionType do
|
4
4
|
let(:type_1) { OpenStruct.new(kind: GraphQL::TypeKinds::OBJECT)}
|
5
5
|
let(:type_2) { OpenStruct.new(kind: GraphQL::TypeKinds::OBJECT)}
|
6
|
+
let(:type_3) { OpenStruct.new(kind: GraphQL::TypeKinds::SCALAR)}
|
6
7
|
let(:union) {
|
7
8
|
types = [type_1, type_2]
|
8
9
|
GraphQL::UnionType.define {
|
@@ -18,4 +19,12 @@ describe GraphQL::UnionType do
|
|
18
19
|
it 'infers type from an object' do
|
19
20
|
assert_equal(CheeseType, DairyProductUnion.resolve_type(CHEESES[1]))
|
20
21
|
end
|
22
|
+
|
23
|
+
it '#include? returns true if type in in possible_types' do
|
24
|
+
assert union.include?(type_1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it '#include? returns false if type is not in possible_types' do
|
28
|
+
assert_equal(false, union.include?(type_3))
|
29
|
+
end
|
21
30
|
end
|
data/spec/support/dairy_app.rb
CHANGED
@@ -36,12 +36,16 @@ CheeseType = GraphQL::ObjectType.define do
|
|
36
36
|
description("Animal which produced the milk for this cheese")
|
37
37
|
end
|
38
38
|
|
39
|
-
field :
|
40
|
-
type -> { CheeseType }
|
41
|
-
description("Cheeses like this one")
|
39
|
+
field :similarCheese, -> { CheeseType }, "Cheeses like this one" do
|
42
40
|
argument :source, !types[!DairyAnimalEnum]
|
43
41
|
resolve -> (t, a, c) {
|
44
|
-
|
42
|
+
# get the strings out:
|
43
|
+
sources = a["source"].map(&:name)
|
44
|
+
if sources.include?("YAK")
|
45
|
+
GraphQL::ExecutionError.new("No cheeses are made from Yak milk!")
|
46
|
+
else
|
47
|
+
CHEESES.values.find { |c| sources.include?(c.source) }
|
48
|
+
end
|
45
49
|
}
|
46
50
|
end
|
47
51
|
|
@@ -84,6 +88,20 @@ DairyProductUnion = GraphQL::UnionType.define do
|
|
84
88
|
possible_types [MilkType, CheeseType]
|
85
89
|
end
|
86
90
|
|
91
|
+
CowType = GraphQL::ObjectType.define do
|
92
|
+
name 'Cow'
|
93
|
+
description 'A farm where milk is harvested and cheese is produced'
|
94
|
+
field :id, !types.ID
|
95
|
+
field :name, types.String
|
96
|
+
field :last_produced_dairy, DairyProductUnion
|
97
|
+
end
|
98
|
+
|
99
|
+
MaybeNullType = GraphQL::ObjectType.define do
|
100
|
+
name "MaybeNull"
|
101
|
+
description "An object whose fields return nil"
|
102
|
+
field :cheese, CheeseType
|
103
|
+
end
|
104
|
+
|
87
105
|
DairyProductInputType = GraphQL::InputObjectType.define {
|
88
106
|
name "DairyProductInput"
|
89
107
|
description "Properties for finding a dairy product"
|
@@ -142,6 +160,7 @@ QueryType = GraphQL::ObjectType.define do
|
|
142
160
|
field :dairy, field: SingletonField.create(type: DairyType, data: DAIRY)
|
143
161
|
field :fromSource, &SourceFieldDefn
|
144
162
|
field :favoriteEdible, &FavoriteFieldDefn
|
163
|
+
field :cow, field: SingletonField.create(type: CowType, data: COW)
|
145
164
|
field :searchDairy do
|
146
165
|
description "Find dairy products matching a description"
|
147
166
|
type !DairyProductUnion
|
@@ -192,7 +211,7 @@ MutationType = GraphQL::ObjectType.define do
|
|
192
211
|
argument :input, !ReplaceValuesInputType
|
193
212
|
resolve -> (o, args, ctx) {
|
194
213
|
GLOBAL_VALUES.clear
|
195
|
-
GLOBAL_VALUES
|
214
|
+
GLOBAL_VALUES.push(*args[:input][:values])
|
196
215
|
GLOBAL_VALUES
|
197
216
|
}
|
198
217
|
end
|
data/spec/support/dairy_data.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -172,6 +172,7 @@ files:
|
|
172
172
|
- lib/graphql/directive/include_directive.rb
|
173
173
|
- lib/graphql/directive/skip_directive.rb
|
174
174
|
- lib/graphql/enum_type.rb
|
175
|
+
- lib/graphql/execution_error.rb
|
175
176
|
- lib/graphql/field.rb
|
176
177
|
- lib/graphql/float_type.rb
|
177
178
|
- lib/graphql/id_type.rb
|
@@ -208,7 +209,6 @@ files:
|
|
208
209
|
- lib/graphql/query.rb
|
209
210
|
- lib/graphql/query/arguments.rb
|
210
211
|
- lib/graphql/query/base_execution.rb
|
211
|
-
- lib/graphql/query/base_execution/selected_object_resolution.rb
|
212
212
|
- lib/graphql/query/base_execution/value_resolution.rb
|
213
213
|
- lib/graphql/query/context.rb
|
214
214
|
- lib/graphql/query/directive_chain.rb
|
@@ -258,6 +258,7 @@ files:
|
|
258
258
|
- spec/graphql/base_type_spec.rb
|
259
259
|
- spec/graphql/directive_spec.rb
|
260
260
|
- spec/graphql/enum_type_spec.rb
|
261
|
+
- spec/graphql/execution_error_spec.rb
|
261
262
|
- spec/graphql/field_spec.rb
|
262
263
|
- spec/graphql/id_type_spec.rb
|
263
264
|
- spec/graphql/input_object_type_spec.rb
|
@@ -271,6 +272,7 @@ files:
|
|
271
272
|
- spec/graphql/language/visitor_spec.rb
|
272
273
|
- spec/graphql/object_type_spec.rb
|
273
274
|
- spec/graphql/query/executor_spec.rb
|
275
|
+
- spec/graphql/query/type_resolver_spec.rb
|
274
276
|
- spec/graphql/query_spec.rb
|
275
277
|
- spec/graphql/schema/field_validator_spec.rb
|
276
278
|
- spec/graphql/schema/type_reducer_spec.rb
|
@@ -327,6 +329,7 @@ test_files:
|
|
327
329
|
- spec/graphql/base_type_spec.rb
|
328
330
|
- spec/graphql/directive_spec.rb
|
329
331
|
- spec/graphql/enum_type_spec.rb
|
332
|
+
- spec/graphql/execution_error_spec.rb
|
330
333
|
- spec/graphql/field_spec.rb
|
331
334
|
- spec/graphql/id_type_spec.rb
|
332
335
|
- spec/graphql/input_object_type_spec.rb
|
@@ -340,6 +343,7 @@ test_files:
|
|
340
343
|
- spec/graphql/language/visitor_spec.rb
|
341
344
|
- spec/graphql/object_type_spec.rb
|
342
345
|
- spec/graphql/query/executor_spec.rb
|
346
|
+
- spec/graphql/query/type_resolver_spec.rb
|
343
347
|
- spec/graphql/query_spec.rb
|
344
348
|
- spec/graphql/schema/field_validator_spec.rb
|
345
349
|
- spec/graphql/schema/type_reducer_spec.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module GraphQL
|
2
|
-
class Query
|
3
|
-
class BaseExecution
|
4
|
-
class SelectedObjectResolution
|
5
|
-
attr_reader :ast_node, :parent_type, :target, :query, :execution_strategy
|
6
|
-
def initialize(ast_node, parent_type, target, query, execution_strategy)
|
7
|
-
@ast_node = ast_node
|
8
|
-
@parent_type = parent_type
|
9
|
-
@target = target
|
10
|
-
@query = query
|
11
|
-
@execution_strategy = execution_strategy
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|