graphql 0.6.0 → 0.6.1

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: c92fe281f2beeab6fd1e4c6165f07c5156ccb09a
4
- data.tar.gz: 309513164d1b60381f7283592fb3f83f4105fb9b
3
+ metadata.gz: 16c0fb0de67cb50d74c16528abcccb26ad91b01f
4
+ data.tar.gz: 008d40ba5dca1c8fb2c8800f987f02981c64d6f9
5
5
  SHA512:
6
- metadata.gz: 0a7345b8975ac69de12cae806c9b0f72bb9ada248a6fedf0f948113573676c4c938b090ff37b8f7b4cc5a3bcc661aadb5239700a832ab5ad9746d911f69cf198
7
- data.tar.gz: dc45fdc6b9670f353fa37be7fe1a019d39874f78f89e33ec971dc61119e40e88a4837092bb1ecaa6861623c53c18e750a39d19006a8c5bc15edf1c2f5d18e47f
6
+ metadata.gz: 2573ce8d132b479472db3a680861289e996ad213c6173ad1fadac0ed3377219a7cc41cf7089149b60e81b2dc75fe5c50a38fc6af51e201744b129fc2bf934019
7
+ data.tar.gz: 79877bafa23685bedf218e78f9572a1795a30383433943586842ba7605696a71eb391fcf429cc66f6992a9ff29121fff6086d9b428d925541a0f655ef20c90f5
@@ -95,8 +95,17 @@ module GraphQL::Language
95
95
  rule(:value_input_object) { str("{") >> value_input_object_pair.repeat(1).as(:input_object) >> str("}") }
96
96
  rule(:value_input_object_pair) { space? >> name.as(:input_object_name) >> space? >> str(":") >> space? >> value.as(:input_object_value) >> separator? }
97
97
  rule(:value_int) { (value_sign? >> match('\d').repeat(1)).as(:int) }
98
- # TODO: support unicode, escaped chars (match the spec)
99
- rule(:value_string) { str('"') >> match('[^\"]').repeat(1).as(:string) >> str('"')}
98
+ rule(:value_string) { str('"') >> value_string_char.repeat.as(:string) >> str('"')}
99
+ rule(:value_string_char) { value_string_escaped_char | value_string_escaped_unicode | value_string_source_char}
100
+ rule(:value_string_escaped_char) { str("\\") >> match('["\/bfnrt]') }
101
+ rule(:value_string_escaped_unicode) { str("\\") >> match('u[\dA-Fa-f]{4}')}
102
+ rule(:value_string_source_char) { (str('"') | str("\\") | value_string_line_terminator).absent? >> any }
103
+ rule(:value_string_line_terminator) {
104
+ str('\u000A') | # new line
105
+ str('\u000D') | # carriage return
106
+ str('\u2028') | # line separator
107
+ str('\u2029') # paragraph separator
108
+ }
100
109
  rule(:value_enum) { name.as(:enum) }
101
110
  rule(:value_variable) { str("$") >> name.as(:variable) }
102
111
 
@@ -91,7 +91,17 @@ module GraphQL::Language
91
91
  rule(input_object_name: simple(:n), input_object_value: sequence(:v)) { create_node(:Argument, name: n.to_s, value: v, position_source: n)}
92
92
  rule(int: simple(:v)) { v.to_i }
93
93
  rule(float: simple(:v)) { v.to_f }
94
- rule(string: simple(:v)) { v.to_s }
94
+
95
+ ESCAPES = /\\(["\\\/bfnrt])/
96
+ UTF_8 = /\\u[\da-f]{4}/i
97
+ UTF_8_REPLACE = -> (m) { [m[-4..-1].to_i(16)].pack('U') }
98
+
99
+ rule(string: simple(:v)) {
100
+ string = v.to_s
101
+ string.gsub!(ESCAPES, '\1')
102
+ string.gsub!(UTF_8, &UTF_8_REPLACE)
103
+ string
104
+ }
95
105
  rule(variable: simple(:v)) { create_node(:VariableIdentifier, name: v.to_s, position_source: v) }
96
106
  rule(enum: simple(:v)) { create_node(:Enum, name: v.to_s, position_source: v)}
97
107
  end
@@ -13,7 +13,7 @@ class GraphQL::Query::Arguments
13
13
  end
14
14
  end
15
15
 
16
- def_delegators :@hash, :keys, :values
16
+ def_delegators :@hash, :keys, :values, :inspect, :to_h
17
17
 
18
18
  def [](key)
19
19
  @hash[key.to_s]
@@ -4,9 +4,14 @@ class GraphQL::Schema::EachItemValidator
4
4
  end
5
5
 
6
6
  def validate(items, as:, must_be:)
7
- invalid_items = items.select {|k| !yield(k) }
8
- if invalid_items.any?
9
- @errors << "#{as} must be #{must_be}, but some aren't: #{invalid_items.map(&:to_s).join(", ")}"
7
+ if !items.is_a?(Array)
8
+ @errors << "#{as} must be an Array, not #{items.inspect}"
9
+ return
10
+ else
11
+ invalid_items = items.select {|k| !yield(k) }
12
+ if invalid_items.any?
13
+ @errors << "#{as} must be #{must_be}, but some aren't: #{invalid_items.map(&:to_s).join(", ")}"
14
+ end
10
15
  end
11
16
  end
12
17
  end
@@ -11,11 +11,17 @@ class GraphQL::Schema::ImplementationValidator
11
11
  # If `block_given?`, yield the return value of that method
12
12
  # If provided, use `as` in the error message, overriding class-level `as`.
13
13
  def must_respond_to(method_name, args: [], as: nil)
14
+ local_as = as || implementation_as
15
+ method_signature = "##{method_name}(#{args.join(", ")})"
14
16
  if !object.respond_to?(method_name)
15
- local_as = as || implementation_as
16
- errors << "#{object.to_s} must respond to ##{method_name}(#{args.join(", ")}) to be a #{local_as}"
17
+ errors << "#{object.to_s} must respond to #{method_signature} to be a #{local_as}"
17
18
  elsif block_given?
18
- yield(object.public_send(method_name))
19
+ return_value = object.public_send(method_name)
20
+ if return_value.nil?
21
+ errors << "#{object.to_s} must return a value for #{method_signature} to be a #{local_as}"
22
+ else
23
+ yield(return_value)
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -30,8 +30,17 @@ class GraphQL::StaticValidation::VariableUsagesAreAllowed
30
30
  end
31
31
 
32
32
  arg_defn = arguments[arg_node.name]
33
- if var_type != arg_defn.type
34
- context.errors << message("Type mismatch on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})", arg_node)
33
+ arg_defn_type = arg_defn.type
34
+
35
+ var_inner_type = var_type.kind.unwrap(var_type)
36
+ arg_inner_type = arg_defn_type.kind.unwrap(arg_defn_type)
37
+
38
+ if var_inner_type != arg_inner_type
39
+ context.errors << create_error("Type mismatch", var_type, ast_var, arg_defn, arg_node)
40
+ elsif list_dimension(var_type) != list_dimension(arg_defn_type)
41
+ context.errors << create_error("List dimension mismatch", var_type, ast_var, arg_defn, arg_node)
42
+ elsif !non_null_levels_match(arg_defn_type, var_type)
43
+ context.errors << create_error("Nullability mismatch", var_type, ast_var, arg_defn, arg_node)
35
44
  end
36
45
  end
37
46
 
@@ -44,4 +53,28 @@ class GraphQL::StaticValidation::VariableUsagesAreAllowed
44
53
  types[ast_type.name]
45
54
  end
46
55
  end
56
+
57
+ def create_error(error_message, var_type, ast_var, arg_defn, arg_node)
58
+ message("#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})", arg_node)
59
+ end
60
+
61
+ def list_dimension(type)
62
+ if type.kind.list?
63
+ 1 + list_dimension(type.of_type)
64
+ elsif type.kind.non_null?
65
+ list_dimension(type.of_type)
66
+ else
67
+ 0
68
+ end
69
+ end
70
+
71
+ def non_null_levels_match(arg_type, var_type)
72
+ if arg_type.kind.non_null? && !var_type.kind.non_null?
73
+ false
74
+ elsif arg_type.kind.wraps? && var_type.kind.wraps?
75
+ non_null_levels_match(arg_type.of_type, var_type.of_type)
76
+ else
77
+ true
78
+ end
79
+ end
47
80
  end
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.6.0"
2
+ VERSION = "0.6.1"
3
3
  end
@@ -59,7 +59,7 @@ describe GraphQL::Language::Parser do
59
59
 
60
60
  it 'parses directives' do
61
61
  assert(parser.directives.parse_with_debug("@doSomething"), 'gets without argument')
62
- assert(parser.directives.parse_with_debug('@doSomething(why: "forSomeReason")'), 'gets with argument')
62
+ assert(parser.directives.parse_with_debug('@doSomething(why: "\"forSomeReason\"")'), 'gets with argument')
63
63
  assert(parser.directives.parse_with_debug('@myFlag, @doSomething(why: "forSomeReason")'), 'gets multiple')
64
64
  end
65
65
 
@@ -67,7 +67,7 @@ describe GraphQL::Language::Parser do
67
67
  assert(parser.field.parse_with_debug(%|myField { name, id }|), 'gets subselections')
68
68
  assert(parser.field.parse_with_debug(%{myAlias: myField}), 'gets an alias')
69
69
  assert(parser.field.parse_with_debug(%{myField(intKey: 1, floatKey: 1.1e5)}), 'gets arguments')
70
- assert(parser.field.parse_with_debug(%{myAlias: myField(stringKey: "my_string", boolKey: false, objKey: {key : true})}), 'gets alias and arguments')
70
+ assert(parser.field.parse_with_debug('myAlias: myField(stringKey: "\"my_string\"", boolKey: false, objKey: {key : true})'), 'gets alias and arguments')
71
71
  assert(parser.field.parse_with_debug(%|myField @withFlag, @skip(if: true) { name, id }|), 'gets with directive')
72
72
  end
73
73
 
@@ -100,7 +100,10 @@ describe GraphQL::Language::Parser do
100
100
  end
101
101
 
102
102
  it 'gets strings' do
103
- assert(parser.value.parse_with_debug('"my string"'))
103
+ assert(parser.value.parse_with_debug('"my string"'), "plain strings")
104
+ assert(parser.value.parse_with_debug('""'), "empty strings")
105
+ assert(parser.value.parse_with_debug('"\"Hi!\"\n"'), "escaped strings")
106
+ assert(parser.value.parse_with_debug('"\u0025\u0026"'), "escaped unicode")
104
107
  end
105
108
 
106
109
  it 'gets arrays' do
@@ -99,20 +99,20 @@ describe GraphQL::Language::Transform do
99
99
  assert_equal("SO_COOL", res.arguments[1].value.name)
100
100
  assert_equal({"nice" => {"very" => true}}, res.arguments[2].value.to_h)
101
101
 
102
- res = get_result(%|me @flag, @include(if: "something") {name, id}|, parse: :field)
102
+ res = get_result('me @flag, @include(if: "\"something\"") {name, id}', parse: :field)
103
103
  assert_equal("me", res.name)
104
104
  assert_equal(nil, res.alias)
105
105
  assert_equal(2, res.directives.length)
106
106
  assert_equal("flag", res.directives.first.name)
107
- assert_equal("something", res.directives.last.arguments.first.value)
107
+ assert_equal('"something"', res.directives.last.arguments.first.value)
108
108
  assert_equal(2, res.selections.length)
109
109
  end
110
110
 
111
111
  it 'transforms directives' do
112
- res = get_result("@doSomething(vigorously: true)", parse: :directive)
112
+ res = get_result('@doSomething(vigorously: "\"true\u0025\"")', parse: :directive)
113
113
  assert_equal("doSomething", res.name, 'gets the name without @')
114
114
  assert_equal("vigorously", res.arguments.first.name)
115
- assert_equal(true, res.arguments.first.value)
115
+ assert_equal('"true%"', res.arguments.first.value)
116
116
 
117
117
  res = get_result("@someFlag", parse: :directive)
118
118
  assert_equal("someFlag", res.name)
@@ -28,6 +28,16 @@ describe GraphQL::Schema::TypeValidator do
28
28
  end
29
29
  end
30
30
 
31
+ describe 'when a method returns nil' do
32
+ let(:type_defn) { base_type_defn.merge(interfaces: nil)}
33
+ it 'requires name' do
34
+ assert_equal(
35
+ ["InvalidType must return a value for #interfaces() to be a OBJECT"],
36
+ errors
37
+ )
38
+ end
39
+ end
40
+
31
41
  describe "when a field name isnt a string" do
32
42
  let(:type_defn) { base_type_defn.merge(fields: {symbol_field: (GraphQL::Field.new {|f|}) }) }
33
43
  it "requires string names" do
@@ -9,6 +9,7 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
9
9
  $badStr: String!,
10
10
  $goodAnimals: [DairyAnimal!]!,
11
11
  $badAnimals: [DairyAnimal]!,
12
+ $deepAnimals: [[DairyAnimal!]!]!,
12
13
  ) {
13
14
  goodCheese: cheese(id: $goodInt) { source }
14
15
  okCheese: cheese(id: $okInt) { source }
@@ -17,6 +18,11 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
17
18
  cheese(id: 1) {
18
19
  similarCheeses(source: $goodAnimals)
19
20
  other: similarCheeses(source: $badAnimals)
21
+ tooDeep: similarCheeses(source: $deepAnimals)
22
+ }
23
+
24
+ milk(id: 1) {
25
+ flavors(limit: $okInt)
20
26
  }
21
27
  }
22
28
  ')}
@@ -25,19 +31,23 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
25
31
  let(:errors) { validator.validate(document) }
26
32
 
27
33
  it "finds variables used as arguments but don't match the argument's type" do
28
- assert_equal(3, errors.length)
34
+ assert_equal(4, errors.length)
29
35
  expected = [
30
36
  {
31
- "message"=>"Type mismatch on variable $badInt and argument id (Int / Int!)",
32
- "locations"=>[{"line"=>12, "column"=>28}]
37
+ "message"=>"Nullability mismatch on variable $badInt and argument id (Int / Int!)",
38
+ "locations"=>[{"line"=>13, "column"=>28}]
33
39
  },
34
40
  {
35
41
  "message"=>"Type mismatch on variable $badStr and argument id (String! / Int!)",
36
- "locations"=>[{"line"=>13, "column"=>28}]
42
+ "locations"=>[{"line"=>14, "column"=>28}]
43
+ },
44
+ {
45
+ "message"=>"Nullability mismatch on variable $badAnimals and argument source ([DairyAnimal]! / [DairyAnimal!]!)",
46
+ "locations"=>[{"line"=>17, "column"=>31}]
37
47
  },
38
48
  {
39
- "message"=>"Type mismatch on variable $badAnimals and argument source ([DairyAnimal]! / [DairyAnimal!]!)",
40
- "locations"=>[{"line"=>16, "column"=>31}]
49
+ "message"=>"List dimension mismatch on variable $deepAnimals and argument source ([[DairyAnimal!]!]! / [DairyAnimal!]!)",
50
+ "locations"=>[{"line"=>18, "column"=>33}]
41
51
  }
42
52
  ]
43
53
  assert_equal(expected, errors)
@@ -140,8 +140,6 @@ ReplaceValuesInputType = GraphQL::InputObjectType.define do
140
140
  input_field :values, !types[!types.Int]
141
141
  end
142
142
 
143
- p ReplaceValuesInputType.input_fields.inspect
144
-
145
143
  MutationType = GraphQL::ObjectType.define do
146
144
  name "Mutation"
147
145
  description "The root for mutations in this schema"
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.6.0
4
+ version: 0.6.1
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-08-14 00:00:00.000000000 Z
11
+ date: 2015-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet