graphql 0.10.3 → 0.10.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: 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