graphql 1.0.0 → 1.1.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +10 -0
  3. data/lib/graphql/base_type.rb +8 -5
  4. data/lib/graphql/compatibility.rb +3 -0
  5. data/lib/graphql/compatibility/execution_specification.rb +414 -0
  6. data/lib/graphql/compatibility/query_parser_specification.rb +117 -0
  7. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +81 -0
  8. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +78 -0
  9. data/lib/graphql/compatibility/schema_parser_specification.rb +239 -0
  10. data/lib/graphql/define/instance_definable.rb +53 -21
  11. data/lib/graphql/directive.rb +1 -1
  12. data/lib/graphql/enum_type.rb +31 -8
  13. data/lib/graphql/execution/directive_checks.rb +0 -6
  14. data/lib/graphql/input_object_type.rb +6 -4
  15. data/lib/graphql/introspection/arguments_field.rb +3 -1
  16. data/lib/graphql/introspection/enum_values_field.rb +10 -5
  17. data/lib/graphql/introspection/fields_field.rb +1 -1
  18. data/lib/graphql/introspection/input_fields_field.rb +2 -2
  19. data/lib/graphql/introspection/interfaces_field.rb +7 -1
  20. data/lib/graphql/introspection/possible_types_field.rb +1 -1
  21. data/lib/graphql/introspection/schema_type.rb +1 -1
  22. data/lib/graphql/introspection/type_by_name_field.rb +4 -2
  23. data/lib/graphql/introspection/type_type.rb +7 -6
  24. data/lib/graphql/language/lexer.rl +0 -4
  25. data/lib/graphql/language/parser.rb +1 -1
  26. data/lib/graphql/language/parser.y +1 -1
  27. data/lib/graphql/list_type.rb +3 -4
  28. data/lib/graphql/non_null_type.rb +4 -8
  29. data/lib/graphql/object_type.rb +5 -3
  30. data/lib/graphql/query.rb +48 -12
  31. data/lib/graphql/query/context.rb +7 -1
  32. data/lib/graphql/query/serial_execution/execution_context.rb +8 -3
  33. data/lib/graphql/query/serial_execution/field_resolution.rb +8 -5
  34. data/lib/graphql/query/serial_execution/operation_resolution.rb +2 -2
  35. data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -21
  36. data/lib/graphql/query/serial_execution/value_resolution.rb +59 -99
  37. data/lib/graphql/query/variables.rb +7 -2
  38. data/lib/graphql/scalar_type.rb +1 -1
  39. data/lib/graphql/schema.rb +49 -18
  40. data/lib/graphql/schema/build_from_definition.rb +248 -0
  41. data/lib/graphql/schema/instrumented_field_map.rb +23 -0
  42. data/lib/graphql/schema/loader.rb +4 -11
  43. data/lib/graphql/schema/possible_types.rb +4 -2
  44. data/lib/graphql/schema/printer.rb +1 -1
  45. data/lib/graphql/schema/type_expression.rb +4 -4
  46. data/lib/graphql/schema/type_map.rb +1 -1
  47. data/lib/graphql/schema/validation.rb +4 -0
  48. data/lib/graphql/schema/warden.rb +114 -0
  49. data/lib/graphql/static_validation/literal_validator.rb +10 -7
  50. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -3
  51. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  52. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  53. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -14
  54. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  55. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  56. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -4
  57. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +2 -1
  58. data/lib/graphql/static_validation/validation_context.rb +7 -1
  59. data/lib/graphql/union_type.rb +6 -3
  60. data/lib/graphql/unresolved_type_error.rb +1 -2
  61. data/lib/graphql/version.rb +1 -1
  62. data/readme.md +1 -5
  63. data/spec/graphql/compatibility/execution_specification_spec.rb +3 -0
  64. data/spec/graphql/compatibility/query_parser_specification_spec.rb +5 -0
  65. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +5 -0
  66. data/spec/graphql/define/instance_definable_spec.rb +20 -0
  67. data/spec/graphql/directive_spec.rb +11 -0
  68. data/spec/graphql/enum_type_spec.rb +20 -1
  69. data/spec/graphql/input_object_type_spec.rb +9 -9
  70. data/spec/graphql/introspection/directive_type_spec.rb +4 -4
  71. data/spec/graphql/introspection/input_value_type_spec.rb +6 -6
  72. data/spec/graphql/introspection/type_type_spec.rb +28 -26
  73. data/spec/graphql/language/parser_spec.rb +27 -17
  74. data/spec/graphql/list_type_spec.rb +2 -2
  75. data/spec/graphql/query/variables_spec.rb +1 -0
  76. data/spec/graphql/scalar_type_spec.rb +3 -3
  77. data/spec/graphql/schema/build_from_definition_spec.rb +693 -0
  78. data/spec/graphql/schema/type_expression_spec.rb +3 -3
  79. data/spec/graphql/schema/validation_spec.rb +7 -3
  80. data/spec/graphql/schema/warden_spec.rb +510 -0
  81. data/spec/graphql/schema_spec.rb +129 -0
  82. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -1
  83. data/spec/graphql/static_validation/type_stack_spec.rb +3 -3
  84. data/spec/spec_helper.rb +27 -1
  85. data/spec/support/dairy_app.rb +8 -5
  86. metadata +21 -3
  87. data/lib/graphql/language/parser_tests.rb +0 -809
@@ -14,7 +14,7 @@ module GraphQL
14
14
  def initialize(schema)
15
15
  @object_types = schema.types.values.select { |type| type.kind.object? }
16
16
 
17
- @storage = Hash.new do |hash, key|
17
+ @interface_implementers = Hash.new do |hash, key|
18
18
  hash[key] = @object_types.select { |type| type.interfaces.include?(key) }.sort_by(&:name)
19
19
  end
20
20
  end
@@ -24,7 +24,9 @@ module GraphQL
24
24
  when GraphQL::UnionType
25
25
  type_defn.possible_types
26
26
  when GraphQL::InterfaceType
27
- @storage[type_defn]
27
+ @interface_implementers[type_defn]
28
+ when GraphQL::ObjectType
29
+ [type_defn]
28
30
  else
29
31
  raise "#{type_defn} doesn't have possible types"
30
32
  end
@@ -162,7 +162,7 @@ module GraphQL
162
162
  include ArgsPrinter
163
163
  include DescriptionPrinter
164
164
  def print_fields(type)
165
- type.all_fields.map.with_index{ |field, i|
165
+ type.all_fields.map.with_index { |field, i|
166
166
  "#{print_description(field, ' ', i == 0)}"\
167
167
  " #{field.name}#{print_args(field, ' ')}: #{field.type}#{print_deprecated(field)}"
168
168
  }.join("\n")
@@ -1,17 +1,17 @@
1
1
  module GraphQL
2
2
  class Schema
3
3
  module TypeExpression
4
- def self.build_type(schema, ast_node)
4
+ def self.build_type(types, ast_node)
5
5
  case ast_node
6
6
  when GraphQL::Language::Nodes::TypeName
7
7
  type_name = ast_node.name
8
- schema.types[type_name]
8
+ types[type_name]
9
9
  when GraphQL::Language::Nodes::NonNullType
10
10
  ast_inner_type = ast_node.of_type
11
- build_type(schema, ast_inner_type).to_non_null_type
11
+ build_type(types, ast_inner_type).to_non_null_type
12
12
  when GraphQL::Language::Nodes::ListType
13
13
  ast_inner_type = ast_node.of_type
14
- build_type(schema, ast_inner_type).to_list_type
14
+ build_type(types, ast_inner_type).to_list_type
15
15
  end
16
16
  end
17
17
  end
@@ -8,7 +8,7 @@ module GraphQL
8
8
  # If you want a type, but want to handle the undefined case, use {#fetch}.
9
9
  class TypeMap
10
10
  extend Forwardable
11
- def_delegators :@storage, :key?, :keys, :values, :to_h, :fetch
11
+ def_delegators :@storage, :key?, :keys, :values, :to_h, :fetch, :each, :each_value
12
12
 
13
13
  def initialize
14
14
  @storage = {}
@@ -99,6 +99,10 @@ module GraphQL
99
99
  ARGUMENTS_ARE_VALID = Rules.assert_named_items_are_valid("argument", ->(type) { type.arguments.values })
100
100
 
101
101
  DEFAULT_VALUE_IS_VALID_FOR_TYPE = ->(type) {
102
+ if !type.default_value.nil? && type.type.is_a?(NonNullType)
103
+ return %Q(Variable #{type.name} of type "#{type.type}" is required and will not use the default value. Perhaps you meant to use type "#{type.type.of_type}".)
104
+ end
105
+
102
106
  if !type.default_value.nil?
103
107
  coerced_value = begin
104
108
  type.type.coerce_result(type.default_value)
@@ -0,0 +1,114 @@
1
+ module GraphQL
2
+ class Schema
3
+ # Restrict access to a {GraphQL::Schema} with a user-defined mask.
4
+ #
5
+ # The mask is object that responds to `#visible?(schema_member)`.
6
+ #
7
+ # When validating and executing a query, all access to schema members
8
+ # should go through a warden. If you access the schema directly,
9
+ # you may show a client something that it shouldn't be allowed to see.
10
+ #
11
+ # Masks can be provided in {Schema#execute} (or {Query#initialize}) with the `mask:` keyword.
12
+ #
13
+ # @example Hidding private fields
14
+ # private_members = -> (member) { member.metadata[:private] }
15
+ # result = Schema.execute(query_string, except: private_members)
16
+ #
17
+ # @example Custom mask implementation
18
+ # # It must respond to `#call(member)`.
19
+ # class MissingRequiredFlags
20
+ # def initialize(user)
21
+ # @user = user
22
+ # end
23
+ #
24
+ # # Return `false` if any required flags are missing
25
+ # def call(member)
26
+ # member.metadata[:required_flags].any? do |flag|
27
+ # !@user.has_flag?(flag)
28
+ # end
29
+ # end
30
+ # end
31
+ #
32
+ # # Then, use the custom filter in query:
33
+ # missing_required_flags = MissingRequiredFlags.new(current_user)
34
+ #
35
+ # # This query can only access members which match the user's flags
36
+ # result = Schema.execute(query_string, except: missing_required_flags)
37
+ #
38
+ class Warden
39
+ # @param schema [GraphQL::Schema]
40
+ # @param mask [<#call(member)>] Objects are hidden when `.call(member)` returns true
41
+ def initialize(schema, mask)
42
+ @mask = mask
43
+ @schema = schema
44
+ end
45
+
46
+ # @return [Array<GraphQL::BaseType>] Visible types in the schema
47
+ def types
48
+ @schema.types.each_value.select { |t| visible?(t) }
49
+ end
50
+
51
+ # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
52
+ def get_type(type_name)
53
+ type_defn = @schema.types.fetch(type_name, nil)
54
+ if type_defn && visible?(type_defn)
55
+ type_defn
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ # @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`, if it exists
62
+ def get_field(parent_type, field_name)
63
+ field_defn = @schema.get_field(parent_type, field_name)
64
+ if field_defn && visible_field?(field_defn)
65
+ field_defn
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ # @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
72
+ def possible_types(type_defn)
73
+ @schema.possible_types(type_defn).select { |t| visible?(t) }
74
+ end
75
+
76
+ # @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
77
+ # @return [Array<GraphQL::Field>] Fields on `type_defn`
78
+ def fields(type_defn)
79
+ type_defn.all_fields.select { |f| visible_field?(f) }
80
+ end
81
+
82
+ # @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
83
+ # @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
84
+ def arguments(argument_owner)
85
+ argument_owner.arguments.each_value.select { |a| visible_field?(a) }
86
+ end
87
+
88
+ # @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
89
+ def enum_values(enum_defn)
90
+ enum_defn.values.each_value.select { |enum_value_defn| visible?(enum_value_defn) }
91
+ end
92
+
93
+ # @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
94
+ def interfaces(obj_type)
95
+ obj_type.interfaces.select { |t| visible?(t) }
96
+ end
97
+
98
+ # @return [Array<GraphQL::Field>] Visible input fields on `input_obj_type`
99
+ def input_fields(input_obj_type)
100
+ input_obj_type.arguments.each_value.select { |f| visible_field?(f) }
101
+ end
102
+
103
+ private
104
+
105
+ def visible_field?(field_defn)
106
+ visible?(field_defn) && visible?(field_defn.type.unwrap)
107
+ end
108
+
109
+ def visible?(member)
110
+ !@mask.call(member)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -2,6 +2,10 @@ module GraphQL
2
2
  module StaticValidation
3
3
  # Test whether `ast_value` is a valid input for `type`
4
4
  class LiteralValidator
5
+ def initialize(warden:)
6
+ @warden = warden
7
+ end
8
+
5
9
  def validate(ast_value, type)
6
10
  if type.kind.non_null?
7
11
  (!ast_value.nil?) && validate(ast_value, type.of_type)
@@ -9,9 +13,9 @@ module GraphQL
9
13
  item_type = type.of_type
10
14
  ensure_array(ast_value).all? { |val| validate(val, item_type) }
11
15
  elsif type.kind.scalar? && !ast_value.is_a?(GraphQL::Language::Nodes::AbstractNode) && !ast_value.is_a?(Array)
12
- type.valid_input?(ast_value)
16
+ type.valid_input?(ast_value, @warden)
13
17
  elsif type.kind.enum? && ast_value.is_a?(GraphQL::Language::Nodes::Enum)
14
- type.valid_input?(ast_value.name)
18
+ type.valid_input?(ast_value.name, @warden)
15
19
  elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
16
20
  required_input_fields_are_present(type, ast_value) &&
17
21
  present_input_field_values_are_valid(type, ast_value)
@@ -27,8 +31,7 @@ module GraphQL
27
31
 
28
32
 
29
33
  def required_input_fields_are_present(type, ast_node)
30
- required_field_names = type.input_fields
31
- .values
34
+ required_field_names = @warden.input_fields(type)
32
35
  .select { |f| f.type.kind.non_null? }
33
36
  .map(&:name)
34
37
  present_field_names = ast_node.arguments.map(&:name)
@@ -37,10 +40,10 @@ module GraphQL
37
40
  end
38
41
 
39
42
  def present_input_field_values_are_valid(type, ast_node)
40
- fields = type.input_fields
43
+ field_map = @warden.input_fields(type).reduce({}) { |m, f| m[f.name] = f; m}
41
44
  ast_node.arguments.all? do |value|
42
- field = fields[value.name]
43
- field ? validate(value.value, field.type) : true
45
+ field = field_map[value.name]
46
+ field && validate(value.value, field.type)
44
47
  end
45
48
  end
46
49
 
@@ -3,11 +3,9 @@ module GraphQL
3
3
  class ArgumentLiteralsAreCompatible < GraphQL::StaticValidation::ArgumentsValidator
4
4
  def validate_node(parent, node, defn, context)
5
5
  return if node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
6
- validator = GraphQL::StaticValidation::LiteralValidator.new
7
6
  arg_defn = defn.arguments[node.name]
8
7
  return unless arg_defn
9
- valid = validator.validate(node.value, arg_defn.type)
10
- if !valid
8
+ if !context.valid_literal?(node.value, arg_defn.type)
11
9
  kind_of_node = node_type(parent)
12
10
  error_arg_name = parent_name(parent, defn)
13
11
  context.errors << message("Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'.", parent, context: context)
@@ -2,7 +2,7 @@ module GraphQL
2
2
  module StaticValidation
3
3
  class ArgumentsAreDefined < GraphQL::StaticValidation::ArgumentsValidator
4
4
  def validate_node(parent, node, defn, context)
5
- argument_defn = defn.arguments[node.name]
5
+ argument_defn = context.warden.arguments(defn).find { |arg| arg.name == node.name }
6
6
  if argument_defn.nil?
7
7
  kind_of_node = node_type(parent)
8
8
  error_arg_name = parent_name(parent, defn)
@@ -21,7 +21,7 @@ module GraphQL
21
21
  return GraphQL::Language::Visitor::SKIP
22
22
  end
23
23
 
24
- field = context.schema.get_field(parent_type, ast_field.name)
24
+ field = context.warden.get_field(parent_type, ast_field.name)
25
25
  if field.nil?
26
26
  context.errors << message("Field '#{ast_field.name}' doesn't exist on type '#{parent_type.name}'", ast_field, context: context)
27
27
  return GraphQL::Language::Visitor::SKIP
@@ -23,7 +23,8 @@ module GraphQL
23
23
  context.visitor[GraphQL::Language::Nodes::Document].leave << ->(doc_node, parent) {
24
24
  spreads_to_validate.each do |frag_spread|
25
25
  fragment_child_name = context.fragments[frag_spread.node.name].type.name
26
- fragment_child = context.schema.types.fetch(fragment_child_name, nil) # Might be non-existent type name
26
+ fragment_child = context.warden.get_type(fragment_child_name)
27
+ # Might be non-existent type name
27
28
  if fragment_child
28
29
  validate_fragment_in_scope(frag_spread.parent_type, fragment_child, frag_spread.node, context, frag_spread.path)
29
30
  end
@@ -38,25 +39,13 @@ module GraphQL
38
39
  # It's not a valid fragment type, this error was handled someplace else
39
40
  return
40
41
  end
41
- intersecting_types = get_possible_types(parent_type, context.schema) & get_possible_types(child_type, context.schema)
42
+ intersecting_types = context.warden.possible_types(parent_type.unwrap) & context.warden.possible_types(child_type.unwrap)
42
43
  if intersecting_types.none?
43
44
  name = node.respond_to?(:name) ? " #{node.name}" : ""
44
45
  context.errors << message("Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}", node, path: path)
45
46
  end
46
47
  end
47
48
 
48
- def get_possible_types(type, schema)
49
- if type.kind.wraps?
50
- get_possible_types(type.of_type, schema)
51
- elsif type.kind.object?
52
- [type]
53
- elsif type.kind.resolves?
54
- schema.possible_types(type)
55
- else
56
- []
57
- end
58
- end
59
-
60
49
  class FragmentSpread
61
50
  attr_reader :node, :parent_type, :path
62
51
  def initialize(node:, parent_type:, path:)
@@ -19,7 +19,7 @@ module GraphQL
19
19
  def validate_type_exists(node, context)
20
20
  return unless node.type
21
21
  type_name = node.type.name
22
- type = context.schema.types.fetch(type_name, nil)
22
+ type = context.warden.get_type(type_name)
23
23
  if type.nil?
24
24
  context.errors << message("No such type #{type_name}, so it can't be a fragment condition", node, context: context)
25
25
  GraphQL::Language::Visitor::SKIP
@@ -24,7 +24,7 @@ module GraphQL
24
24
  # Inline fragment on the same type
25
25
  else
26
26
  type_name = node_type.to_query_string
27
- type_def = context.schema.types.fetch(type_name, nil)
27
+ type_def = context.warden.get_type(type_name)
28
28
  if type_def.nil? || !type_def.kind.composite?
29
29
  context.errors << message("Invalid fragment on type #{type_name} (must be Union, Interface or Object)", node, context: context)
30
30
  GraphQL::Language::Visitor::SKIP
@@ -4,21 +4,20 @@ module GraphQL
4
4
  include GraphQL::StaticValidation::Message::MessageHelper
5
5
 
6
6
  def validate(context)
7
- literal_validator = GraphQL::StaticValidation::LiteralValidator.new
8
7
  context.visitor[GraphQL::Language::Nodes::VariableDefinition] << ->(node, parent) {
9
8
  if !node.default_value.nil?
10
- validate_default_value(node, literal_validator, context)
9
+ validate_default_value(node, context)
11
10
  end
12
11
  }
13
12
  end
14
13
 
15
- def validate_default_value(node, literal_validator, context)
14
+ def validate_default_value(node, context)
16
15
  value = node.default_value
17
16
  if node.type.is_a?(GraphQL::Language::Nodes::NonNullType)
18
17
  context.errors << message("Non-null variable $#{node.name} can't have a default value", node, context: context)
19
18
  else
20
19
  type = context.schema.type_from_ast(node.type)
21
- if !literal_validator.validate(value, type)
20
+ if !context.valid_literal?(value, type)
22
21
  context.errors << message("Default value for $#{node.name} doesn't match type #{type}", node, context: context)
23
22
  end
24
23
  end
@@ -13,7 +13,8 @@ module GraphQL
13
13
 
14
14
  def validate_is_input_type(node, context)
15
15
  type_name = get_type_name(node.type)
16
- type = context.schema.types.fetch(type_name, nil)
16
+ type = context.warden.get_type(type_name)
17
+
17
18
  if type.nil?
18
19
  context.errors << message("#{type_name} isn't a defined input type (on $#{node.name})", node, context: context)
19
20
  elsif !type.kind.input?
@@ -11,13 +11,14 @@ module GraphQL
11
11
  # It also provides limited access to the {TypeStack} instance,
12
12
  # which tracks state as you climb in and out of different fields.
13
13
  class ValidationContext
14
- attr_reader :query, :schema, :document, :errors, :visitor, :fragments, :operations
14
+ attr_reader :query, :schema, :document, :errors, :visitor, :fragments, :operations, :warden
15
15
  def initialize(query)
16
16
  @query = query
17
17
  @schema = query.schema
18
18
  @document = query.document
19
19
  @fragments = {}
20
20
  @operations = {}
21
+ @warden = query.warden
21
22
 
22
23
  document.definitions.each do |definition|
23
24
  case definition
@@ -69,6 +70,11 @@ module GraphQL
69
70
  @type_stack.argument_definitions[-2]
70
71
  end
71
72
 
73
+ def valid_literal?(ast_value, type)
74
+ @literal_validator ||= LiteralValidator.new(warden: @warden)
75
+ @literal_validator.validate(ast_value, type)
76
+ end
77
+
72
78
  # Don't try to validate dynamic fields
73
79
  # since they aren't defined by the type system
74
80
  def skip_field?(field_name)
@@ -41,9 +41,12 @@ module GraphQL
41
41
  def possible_types
42
42
  @clean_possible_types ||= begin
43
43
  ensure_defined
44
- @dirty_possible_types.map { |type| GraphQL::BaseType.resolve_related_type(type) }
45
- rescue
46
- @dirty_possible_types
44
+
45
+ if @dirty_possible_types.respond_to?(:map)
46
+ @dirty_possible_types.map { |type| GraphQL::BaseType.resolve_related_type(type) }
47
+ else
48
+ @dirty_possible_types
49
+ end
47
50
  end
48
51
  end
49
52
  end
@@ -2,8 +2,7 @@ module GraphQL
2
2
  # Error raised when the value provided for a field can't be resolved to one of the possible types
3
3
  # for the field.
4
4
  class UnresolvedTypeError < GraphQL::Error
5
- def initialize(field_name, schema, field_type, parent_type, received_type)
6
- possible_types = field_type.kind.resolves? ? schema.possible_types(field_type) : [field_type]
5
+ def initialize(field_name, field_type, parent_type, received_type, possible_types)
7
6
  message = %|The value from "#{field_name}" on "#{parent_type}" could not be resolved to "#{field_type}". (Received: #{received_type.inspect}, Expected: [#{possible_types.map(&:inspect).join(", ")}])|
8
7
  super(message)
9
8
  end
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/readme.md CHANGED
@@ -50,13 +50,10 @@ See "Getting Started" on the [website](https://rmosolgo.github.io/graphql-ruby/)
50
50
  - Validators are order-dependent, is this a smell?
51
51
  - Tests for interference between validators are poor
52
52
  - Maybe this is a candidate for a rewrite?
53
- - Add Rails-y argument validations, eg `less_than: 100`, `max_length: 255`, `one_of: [...]`
54
- - Must be customizable
55
53
  - Relay:
56
54
  - Reduce duplication in ArrayConnection / RelationConnection
57
55
  - Improve API for creating edges (better RANGE_ADD support)
58
56
  - If the new edge isn't a member of the connection's objects, raise a nice error
59
- - Missing Enum value should raise a descriptive error, not "key not found"
60
57
  - `args` should whitelist keys -- if you request a key that isn't defined for the field, it should 💥
61
58
  - Fix middleware ([discussion](https://github.com/rmosolgo/graphql-ruby/issues/186))
62
59
  - Handle out-of-bounds lookup, eg `graphql-batch`
@@ -69,6 +66,5 @@ See "Getting Started" on the [website](https://rmosolgo.github.io/graphql-ruby/)
69
66
  - Support working with AST as data
70
67
  - Adding fields to selections (`__typename` can go anywhere, others are type-specific)
71
68
  - Renaming fragments from local names to unique names
72
- - Support AST subclasses? This would be hard, I think classes are used as hash keys in many places.
73
- - Support object deep-copy (schema, type, field, argument)? To support multiple schemas based on the same types. ([discussion](https://github.com/rmosolgo/graphql-ruby/issues/269))
74
69
  - Document encrypted & versioned cursors
70
+ - Make it faster
@@ -0,0 +1,3 @@
1
+ require "spec_helper"
2
+
3
+ SerialExecutionSuite = GraphQL::Compatibility::ExecutionSpecification.build_suite(GraphQL::Query::SerialExecution)