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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90c4327894852ac5fa30563c6f75585be564033d
4
- data.tar.gz: b5ea5c2c7710196f76bb2773f55cda6380075336
3
+ metadata.gz: c7a6017d64f6fd507c50ac439cd6509e2fb163cd
4
+ data.tar.gz: 43f4acf1bd7a7b7bf43b9b0df7e87d34cea37339
5
5
  SHA512:
6
- metadata.gz: f939c511550ce296668dd3154863cb5401ef7d8710b5dd6a165387555ebce6f769ea587d1a798b9ce39b8b69f39ca1120adff150579e892c84fed22d0f26e7be
7
- data.tar.gz: b12940f1e651fe6de8fa33ac0ee1a68ed8041e4120a5c48b52a53d4e239f5470d547b616639876d8c6f01b194ea7ab59b0796a2dd5d3c1d98bd06ef79b4b77d9
6
+ metadata.gz: 313db517b3541bbf8f21a7d1fba1eb257d4be306e44e33f9f6f511d0d3fbfb034cfeca667a2025038bc85b88513fa329db7003922948dd64a78633c44231eb2c
7
+ data.tar.gz: 2a86be1427279e98dfb940ac59f2b8669c6d9638ad8a414a34ba80ee87a9d32bcde0a5ccef2d9c660d033b8d6a7be7ad0c1902869a33c5fe711b24d4cf9512b8
@@ -58,6 +58,7 @@ require 'graphql/schema'
58
58
 
59
59
  # Order does not matter for these:
60
60
 
61
+ require 'graphql/execution_error'
61
62
  require 'graphql/query'
62
63
  require 'graphql/repl'
63
64
  require 'graphql/static_validation'
@@ -53,6 +53,10 @@ module GraphQL
53
53
  def resolve_type=(new_proc)
54
54
  @resolve_type_proc = new_proc || DEFAULT_RESOLVE_TYPE
55
55
  end
56
+
57
+ def include?(type)
58
+ possible_types.include?(type)
59
+ end
56
60
  end
57
61
 
58
62
  # Print the human-readable name of this type
@@ -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
- get_class :FieldResolution
20
+ self.class::FieldResolution
22
21
  end
23
22
 
24
23
  def operation_resolution
25
- get_class :OperationResolution
24
+ self.class::OperationResolution
26
25
  end
27
26
 
28
27
  def selection_resolution
29
- get_class :SelectionResolution
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, :ast_node
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
- attr_reader :query, :operation_name
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
- {"data" => execute }
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
- result = execution_strategy.execute(operation, root_type, query)
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 < GraphQL::Query::BaseExecution::SelectedObjectResolution
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
- super
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)
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.9.3"
2
+ VERSION = "0.9.4"
3
3
  end
data/readme.md CHANGED
@@ -6,6 +6,8 @@
6
6
  [![Test Coverage](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/coverage.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
7
7
  [![built with love](https://cloud.githubusercontent.com/assets/2231765/6766607/d07992c6-cfc9-11e4-813f-d9240714dd50.png)](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
- - Write Ruby bindings for [libgraphqlparser](https://github.com/graphql/libgraphqlparser) and use that instead of Parslet
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
- ## Other Resources
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
- - [GraphQL Slack](https://graphql-slack.herokuapp.com/)
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
@@ -23,6 +23,7 @@ describe GraphQL::Introspection::SchemaType do
23
23
  {"name"=>"dairy"},
24
24
  {"name"=>"fromSource"},
25
25
  {"name"=>"favoriteEdible"},
26
+ {"name"=>"cow"},
26
27
  {"name"=>"searchDairy"},
27
28
  {"name"=>"error"},
28
29
  {"name"=>"maybeNull"},
@@ -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"=>"similarCheeses", "isDeprecated"=>false, "type"=>{"name"=>"Cheese", "ofType"=>nil}},
18
+ {"name"=>"similarCheese", "isDeprecated"=>false, "type"=>{"name"=>"Cheese", "ofType"=>nil}},
19
19
  ]}
20
20
 
21
21
  let(:dairy_animals) {[
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe GraphQL::Query::TypeResolver do
4
+ it 'resolves correcty when child_type is UnionType' do
5
+ type = GraphQL::Query::TypeResolver.new(MILKS[1], DairyProductUnion, MilkType).type
6
+ assert_equal(MilkType, type)
7
+ end
8
+ end
@@ -63,7 +63,7 @@ describe GraphQL::Query do
63
63
  maybeNull {
64
64
  cheese {
65
65
  flavor,
66
- similarCheeses(source: [SHEEP]) { flavor }
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({"data"=> {}}, result)
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({"data"=> {}}, result)
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
- similarCheeses(source: 4.5)
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 'similarCheeses' has an invalid value",
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
- similarCheeses(source: SHEEP, nonsense: 1)
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 'similarCheeses' doesn't accept argument nonsense",
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, similarCheeses(source: YAK) { source } }
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
- similarCheeses(source: $sourceVar)
12
+ similarCheese(source: $sourceVar)
13
13
 
14
- similarCow: similarCheeses(source: COW) {
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
- similarCheeses(source: SHEEP)
21
+ similarCheese(source: SHEEP)
22
22
  }
23
23
  }
24
24
  }
25
25
  fragment cheeseFields on Cheese {
26
26
  fatContent,
27
- similarCow: similarCheeses(source: COW) { similarCowSource: id, id }
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 'similarCheeses' has an argument conflict: {\"source\":\"sourceVar\"} or {\"source\":\"SHEEP\"}?", # different arguments
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
- similarCheeses(id: 1)
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 'similarCheeses' is missing required arguments: source",
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
- similarCheeses(source: $goodAnimals)
20
- other: similarCheeses(source: $badAnimals)
21
- tooDeep: similarCheeses(source: $deepAnimals)
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"=>31}]
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"=>33}]
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
@@ -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 :similarCheeses do
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
- CHEESES.values.find { |c| c.source == a["source"] }
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 += args[:input][:values]
214
+ GLOBAL_VALUES.push(*args[:input][:values])
196
215
  GLOBAL_VALUES
197
216
  }
198
217
  end
@@ -15,3 +15,9 @@ DAIRY = OpenStruct.new(
15
15
  cheese: CHEESES[1],
16
16
  milks: [MILKS[1]]
17
17
  )
18
+
19
+ COW = OpenStruct.new(
20
+ id: 1,
21
+ name: 'Billy',
22
+ last_produced_dairy: MILKS[1]
23
+ )
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.3
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-15 00:00:00.000000000 Z
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