graphql 0.10.3 → 0.10.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cace79bd801a58fbf53eb0ff5a5ef4ea501b1208
4
- data.tar.gz: 495b61e0510a41d880db3a99008446650196742a
3
+ metadata.gz: 47e57c2465fd5d01d22c69ddfc1e964dc0b93239
4
+ data.tar.gz: c759b0a07b75f19ac51f31c77c89be361c5ab897
5
5
  SHA512:
6
- metadata.gz: 635f9a6cbc5d9093227b3699cb93271526c105fff445bacc4e1a39777a51a6b8db1fcc5c692271a0de4d00045b2dd3d33b39dfea90f33c74176ef6ea3e7a57cb
7
- data.tar.gz: 8ca5879203ad6178ad7fff7e3ef12e76de2c90825b1de2e5efd831afe654f49bb3d02b0f9ef6a5d5654586ee20693452ba971e645717d2e561caba396c6c1e3d
6
+ metadata.gz: e16ebf74d11acb3deece7cab048c89b99a1d564b2daba526bc0234609c56fded00beb8fa38066aa8c0330dc29c5aef532e4231cfd485ff615547ee6eb60ae538
7
+ data.tar.gz: 84c3ec086585193859acc914e29cf74f62473360994394125e12b83a0ee67d3e5382fc0c4c1f537a706f5a4d0c6c9f07ad8f6c3b6cb762f8de4cb9cbd02d7dd5
data/lib/graphql.rb CHANGED
@@ -22,7 +22,11 @@ module GraphQL
22
22
  def self.parse(string, as: nil)
23
23
  parser = as ? GraphQL::PARSER.send(as) : GraphQL::PARSER
24
24
  tree = parser.parse(string)
25
- GraphQL::TRANSFORM.apply(tree)
25
+ document = GraphQL::TRANSFORM.apply(tree)
26
+ if !document.is_a?(GraphQL::Language::Nodes::Document)
27
+ raise("Parse failed! Sorry, somehow we failed to turn this string into a document. Please report this bug!")
28
+ end
29
+ document
26
30
  rescue Parslet::ParseFailed => error
27
31
  line, col = error.cause.source.line_and_column(error.cause.pos)
28
32
  raise GraphQL::ParseError.new(error.message, line, col, string)
@@ -78,7 +78,7 @@ module GraphQL::DefinitionHelpers::DefinedByConfig
78
78
  end
79
79
  argument.name = name
80
80
  type && argument.type = type
81
- desc && argument.desc = desc
81
+ desc && argument.description = desc
82
82
  default_value && argument.default_value = default_value
83
83
  input_fields[name.to_s] = argument
84
84
  end
@@ -91,7 +91,7 @@ module GraphQL
91
91
  value_enum
92
92
  )}
93
93
  rule(:value_sign?) { match('[\-\+]').maybe }
94
- rule(:value_array) { (str("[") >> (value >> separator?).repeat(0) >> str("]")).as(:array) }
94
+ rule(:value_array) { (str("[") >> space? >> (value >> separator?).repeat(0) >> str("]")).as(:array) }
95
95
  rule(:value_boolean) { (str("true") | str("false")).as(:boolean) }
96
96
  rule(:value_float) { (value_sign? >> match('\d').repeat(1) >> str(".") >> match('\d').repeat(1) >> (match("[eE]") >> value_sign? >> match('\d').repeat(1)).maybe).as(:float) }
97
97
  rule(:value_input_object) { str("{") >> space? >> value_input_object_pair.repeat(1).as(:input_object) >> space? >> str("}") }
@@ -93,6 +93,7 @@ module GraphQL
93
93
 
94
94
  # Values
95
95
  rule(array: sequence(:v)) { v }
96
+ rule(array: simple(:v)) { [] } # just `nil`
96
97
  rule(boolean: simple(:v)) { v == "true" ? true : false }
97
98
  rule(input_object: sequence(:v)) { create_node(:InputObject, pairs: v, line: v.first.line, col: v.first.col) }
98
99
  rule(input_object_name: simple(:n), input_object_value: simple(:v)) { create_node(:Argument, name: n.to_s, value: v, position_source: n)}
data/lib/graphql/query.rb CHANGED
@@ -37,7 +37,7 @@ class GraphQL::Query
37
37
  def initialize(schema, query_string, context: nil, variables: {}, debug: false, validate: true, operation_name: nil)
38
38
  @schema = schema
39
39
  @debug = debug
40
- @context = Context.new(values: context)
40
+ @context = Context.new(query: self, values: context)
41
41
  @validate = validate
42
42
  @operation_name = operation_name
43
43
  @fragments = {}
@@ -7,6 +7,7 @@ module GraphQL
7
7
  extend Forwardable
8
8
 
9
9
  def initialize(values)
10
+ @hash = values
10
11
  @values = values.inject({}) do |memo, (inner_key, inner_value)|
11
12
  memo[inner_key.to_s] = wrap_value(inner_value)
12
13
  memo
@@ -19,6 +20,12 @@ module GraphQL
19
20
  @values[key.to_s]
20
21
  end
21
22
 
23
+ # Get the original Ruby hash
24
+ # @return [Hash] the original values hash
25
+ def to_h
26
+ @hash
27
+ end
28
+
22
29
  def_delegators :@values, :keys, :values, :each
23
30
 
24
31
  private
@@ -12,9 +12,14 @@ module GraphQL
12
12
  # @return [Array<GraphQL::ExecutionError>] errors returned during execution
13
13
  attr_reader :errors
14
14
 
15
+ # @return [GraphQL::Query] The query whose context this is
16
+ attr_reader :query
17
+
15
18
  # 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
17
- def initialize(values:)
19
+ # @param query [GraphQL::Query] the query who owns this context
20
+ # @param values [Hash] A hash of arbitrary values which will be accessible at query-time
21
+ def initialize(query:, values:)
22
+ @query = query
18
23
  @values = values
19
24
  @errors = []
20
25
  end
@@ -11,16 +11,34 @@ class GraphQL::StaticValidation::LiteralValidator
11
11
  elsif type.kind.enum? && ast_value.is_a?(GraphQL::Language::Nodes::Enum)
12
12
  type.valid_input?(ast_value.name)
13
13
  elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
14
- fields = type.input_fields
15
- ast_value.pairs.all? do |value|
16
- field_type = fields[value.name].type
17
- present_if_required = field_type.kind.non_null? ? !value.nil? : true
18
- present_if_required && validate(value.value, field_type)
19
- end
14
+ required_input_fields_are_present(type, ast_value) &&
15
+ present_input_field_values_are_valid(type, ast_value)
20
16
  elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
21
17
  true
22
18
  else
23
19
  false
24
20
  end
25
21
  end
22
+
23
+
24
+ private
25
+
26
+
27
+ def required_input_fields_are_present(type, ast_node)
28
+ required_field_names = type.input_fields
29
+ .values
30
+ .select { |f| f.type.kind.non_null? }
31
+ .map(&:name)
32
+ present_field_names = ast_node.pairs.map(&:name)
33
+ missing_required_field_names = required_field_names - present_field_names
34
+ missing_required_field_names.none?
35
+ end
36
+
37
+ def present_input_field_values_are_valid(type, ast_node)
38
+ fields = type.input_fields
39
+ ast_node.pairs.all? do |value|
40
+ field_type = fields[value.name].type
41
+ validate(value.value, field_type)
42
+ end
43
+ end
26
44
  end
@@ -5,7 +5,12 @@ class GraphQL::StaticValidation::ArgumentLiteralsAreCompatible < GraphQL::Static
5
5
  arg_defn = defn.arguments[node.name]
6
6
  valid = validator.validate(node.value, arg_defn.type)
7
7
  if !valid
8
- context.errors << message("Argument #{node.name} on #{parent.class.name.split("::").last} '#{parent.name}' has an invalid value", parent)
8
+ field_name = if parent.respond_to?(:alias)
9
+ parent.alias || parent.name
10
+ else
11
+ parent.name
12
+ end
13
+ context.errors << message("Argument #{node.name} on #{parent.class.name.split("::").last} '#{field_name}' has an invalid value", parent)
9
14
  end
10
15
  end
11
16
  end
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.10.3"
2
+ VERSION = "0.10.4"
3
3
  end
@@ -103,7 +103,7 @@ describe GraphQL::Introspection::TypeType do
103
103
  "description"=>"Properties for finding a dairy product",
104
104
  "kind"=>"INPUT_OBJECT",
105
105
  "inputFields"=>[
106
- {"name"=>"source", "type"=>{ "name" => "DairyAnimal"}, "defaultValue"=>nil},
106
+ {"name"=>"source", "type"=>{ "name" => "Non-Null"}, "defaultValue"=>nil},
107
107
  {"name"=>"fatContent", "type"=>{ "name" => "Float"}, "defaultValue"=>nil}
108
108
  ]
109
109
  }
@@ -112,6 +112,7 @@ describe GraphQL::Language::Parser do
112
112
 
113
113
  it 'gets arrays' do
114
114
  assert(parser.value.parse_with_debug('[true, 1, "my string", -5.123e56]'), 'array of values')
115
+ assert(parser.value.parse_with_debug('[ -5.123e56, $myVar ]'), 'array of values with whitespace')
115
116
  assert(parser.value.parse_with_debug('[]'), 'empty array')
116
117
  assert(parser.value.parse_with_debug('[[true, 1], ["my string", -5.123e56]]'), 'array of arrays')
117
118
  end
@@ -29,6 +29,7 @@ describe GraphQL::Language::Transform do
29
29
  # assign fragments:
30
30
  fragment personInfo on Person {
31
31
  birthdate, name # with fields
32
+ hobbies(names: [])
32
33
  }
33
34
 
34
35
  fragment petInfo on Pet { isHousebroken, species } # all on one line
@@ -18,4 +18,8 @@ describe GraphQL::Query::Arguments do
18
18
  end
19
19
  assert_equal([['a', 1], ['b', 2]], pairs)
20
20
  end
21
+
22
+ it 'returns original Ruby hash values with to_h' do
23
+ assert_equal({ a: 1, b: 2 }, arguments.to_h)
24
+ end
21
25
  end
@@ -9,6 +9,10 @@ describe GraphQL::Query::Context do
9
9
  field :contextAstNodeName, types.String do
10
10
  resolve -> (target, args, ctx) { ctx.ast_node.class.name }
11
11
  end
12
+
13
+ field :queryName, types.String do
14
+ resolve -> (target, args, ctx) { ctx.query.class.name }
15
+ end
12
16
  }}
13
17
  let(:schema) { GraphQL::Schema.new(query: query_type, mutation: nil)}
14
18
  let(:result) { schema.execute(query_string, context: {"some_key" => "some value"})}
@@ -34,4 +38,15 @@ describe GraphQL::Query::Context do
34
38
  assert_equal(expected, result)
35
39
  end
36
40
  end
41
+
42
+ describe "access to the query" do
43
+ let(:query_string) { %|
44
+ query getCtx { queryName }
45
+ |}
46
+
47
+ it 'provides access to the AST node' do
48
+ expected = {"data" => {"queryName" => "GraphQL::Query"}}
49
+ assert_equal(expected, result)
50
+ end
51
+ end
37
52
  end
@@ -7,6 +7,7 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
7
7
  cheese(id: 1) { source @skip(if: {id: 1})}
8
8
  yakSource: searchDairy(product: [{source: YAK, fatContent: 1.1}]) { source }
9
9
  badSource: searchDairy(product: [{source: 1.1}]) { source }
10
+ missingSource: searchDairy(product: [{fatContent: 1.1}]) { source }
10
11
  }
11
12
 
12
13
  fragment cheeseFields on Cheese {
@@ -17,8 +18,8 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
17
18
  let(:validator) { GraphQL::StaticValidation::Validator.new(schema: DummySchema, rules: [GraphQL::StaticValidation::ArgumentLiteralsAreCompatible]) }
18
19
  let(:errors) { validator.validate(document) }
19
20
 
20
- it 'finds undefined arguments to fields and directives' do
21
- assert_equal(4, errors.length)
21
+ it 'finds undefined or missing-required arguments to fields and directives' do
22
+ assert_equal(5, errors.length)
22
23
 
23
24
  query_root_error = {
24
25
  "message"=>"Argument id on Field 'cheese' has an invalid value",
@@ -33,14 +34,20 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
33
34
  assert_includes(errors, directive_error)
34
35
 
35
36
  input_object_error = {
36
- "message"=>"Argument product on Field 'searchDairy' has an invalid value",
37
+ "message"=>"Argument product on Field 'badSource' has an invalid value",
37
38
  "locations"=>[{"line"=>6, "column"=>7}]
38
39
  }
39
40
  assert_includes(errors, input_object_error)
40
41
 
42
+ missing_required_field_error = {
43
+ "message"=>"Argument product on Field 'missingSource' has an invalid value",
44
+ "locations"=>[{"line"=>7, "column"=>7}]
45
+ }
46
+ assert_includes(errors, missing_required_field_error)
47
+
41
48
  fragment_error = {
42
49
  "message"=>"Argument source on Field 'similarCheese' has an invalid value",
43
- "locations"=>[{"line"=>10, "column"=>7}]
50
+ "locations"=>[{"line"=>11, "column"=>7}]
44
51
  }
45
52
  assert_includes(errors, fragment_error)
46
53
  end
@@ -102,8 +102,11 @@ end
102
102
  DairyProductInputType = GraphQL::InputObjectType.define {
103
103
  name "DairyProductInput"
104
104
  description "Properties for finding a dairy product"
105
- input_field :source, DairyAnimalEnum
106
- input_field :fatContent, types.Float
105
+ input_field :source, !DairyAnimalEnum do
106
+ description "Where it came from"
107
+ end
108
+
109
+ input_field :fatContent, types.Float, "How much fat it has"
107
110
  }
108
111
 
109
112
 
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.10.3
4
+ version: 0.10.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-11-11 00:00:00.000000000 Z
11
+ date: 2015-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet