graphql 0.18.6 → 0.18.7

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.
@@ -228,7 +228,7 @@ rule
228
228
  }
229
229
 
230
230
  fragment_definition:
231
- FRAGMENT name ON name_without_on directives_list_opt selection_set {
231
+ FRAGMENT fragment_name_opt ON name_without_on directives_list_opt selection_set {
232
232
  return make_node(:FragmentDefinition, {
233
233
  name: val[1],
234
234
  type: val[3],
@@ -239,6 +239,9 @@ rule
239
239
  )
240
240
  }
241
241
 
242
+ fragment_name_opt:
243
+ /* none */ { return nil }
244
+ | name_without_on
242
245
 
243
246
  type_system_definition:
244
247
  schema_definition
@@ -80,7 +80,7 @@ module GraphQL
80
80
  results_hash = @resolve_proc.call(args[:input], ctx)
81
81
  Result.new(arguments: args, result: results_hash)
82
82
  }
83
- GraphQL::Field.define do
83
+ GraphQL::Field.define(description: self.description) do
84
84
  type(field_return_type)
85
85
  argument :input, !field_input_type
86
86
  resolve(field_resolve_proc)
@@ -22,9 +22,13 @@ module GraphQL
22
22
  types[type_object.name] = type_object
23
23
  end
24
24
 
25
- query = types.fetch(schema.fetch("queryType").fetch("name"))
25
+ kargs = { :orphan_types => types.values }
26
+ [:query, :mutation, :subscription].each do |root|
27
+ type = schema["#{root}Type"]
28
+ kargs[root] = types.fetch(type.fetch("name")) if type
29
+ end
26
30
 
27
- Schema.new(query: query, types: types.values)
31
+ Schema.define(**kargs)
28
32
  end
29
33
 
30
34
  class << self
@@ -61,7 +65,7 @@ module GraphQL
61
65
  InterfaceType.define(
62
66
  name: type["name"],
63
67
  description: type["description"],
64
- fields: Hash[type["fields"].map { |field|
68
+ fields: Hash[(type["fields"] || []).map { |field|
65
69
  [field["name"], define_type(field.merge("kind" => "FIELD"), type_resolver)]
66
70
  }]
67
71
  )
@@ -77,6 +81,9 @@ module GraphQL
77
81
  ObjectType.define(
78
82
  name: type["name"],
79
83
  description: type["description"],
84
+ interfaces: (type["interfaces"] || []).map { |interface|
85
+ type_resolver.call(interface)
86
+ },
80
87
  fields: Hash[type["fields"].map { |field|
81
88
  [field["name"], define_type(field.merge("kind" => "FIELD"), type_resolver)]
82
89
  }]
@@ -9,6 +9,7 @@ module GraphQL
9
9
  GraphQL::StaticValidation::DirectivesAreDefined,
10
10
  GraphQL::StaticValidation::DirectivesAreInValidLocations,
11
11
  GraphQL::StaticValidation::FragmentsAreFinite,
12
+ GraphQL::StaticValidation::FragmentsAreNamed,
12
13
  GraphQL::StaticValidation::FragmentsAreUsed,
13
14
  GraphQL::StaticValidation::FragmentTypesExist,
14
15
  GraphQL::StaticValidation::FragmentsAreOnCompositeTypes,
@@ -0,0 +1,19 @@
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentsAreNamed
4
+ include GraphQL::StaticValidation::Message::MessageHelper
5
+
6
+ def validate(context)
7
+ context.visitor[GraphQL::Language::Nodes::FragmentDefinition] << -> (node, parent) { validate_name_exists(node, context) }
8
+ end
9
+
10
+ private
11
+
12
+ def validate_name_exists(node, context)
13
+ if node.name.nil?
14
+ context.errors << message("Fragment definition has no name", node, context: context)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -38,7 +38,7 @@ module GraphQL
38
38
  end
39
39
 
40
40
  def find_difference(fragments, allowed_fragment_names)
41
- fragments.select {|f| !allowed_fragment_names.include?(f.name) }
41
+ fragments.select {|f| f.name && !allowed_fragment_names.include?(f.name) }
42
42
  end
43
43
 
44
44
  class FragmentInstance
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.18.6"
2
+ VERSION = "0.18.7"
3
3
  end
data/readme.md CHANGED
@@ -63,8 +63,8 @@ end
63
63
 
64
64
  # Then create your schema
65
65
  Schema = GraphQL::Schema.define do
66
- query QueryType,
67
- max_depth 8,
66
+ query QueryType
67
+ max_depth 8
68
68
  end
69
69
  ```
70
70
 
@@ -135,3 +135,5 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
135
135
  - Reduce duplication in ArrayConnection / RelationConnection
136
136
  - Improve API for creating edges (better RANGE_ADD support)
137
137
  - If the new edge isn't a member of the connection's objects, raise a nice error
138
+ - Missing Enum value should raise a descriptive error, not "key not found"
139
+ - `args` should whitelist keys -- if you request a key that isn't defined for the field, it should 💥
@@ -8,6 +8,7 @@ describe GraphQL::Introspection::TypeType do
8
8
  dairyAnimal: __type(name: "DairyAnimal") { name, kind, enumValues(includeDeprecated: false) { name, isDeprecated } }
9
9
  dairyProduct: __type(name: "DairyProduct") { name, kind, possibleTypes { name } }
10
10
  animalProduct: __type(name: "AnimalProduct") { name, kind, possibleTypes { name }, fields { name } }
11
+ missingType: __type(name: "NotAType") { name }
11
12
  }
12
13
  |}
13
14
  let(:result) { DummySchema.execute(query_string, context: {}, variables: {"cheeseId" => 2}) }
@@ -64,7 +65,8 @@ describe GraphQL::Introspection::TypeType do
64
65
  "fields"=>[
65
66
  {"name"=>"source"},
66
67
  ]
67
- }
68
+ },
69
+ "missingType" => nil,
68
70
  }}
69
71
  assert_equal(expected, result)
70
72
  end
@@ -7,7 +7,7 @@ describe GraphQL::Language::Generation do
7
7
  myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
8
8
  anotherField(someArg: [1, 2, 3]) {
9
9
  nestedField
10
- ... moreNestedFields @skip(if: $skipNested)
10
+ ...moreNestedFields @skip(if: $skipNested)
11
11
  }
12
12
  ... on OtherType @include(unless: false) {
13
13
  field(arg: [{ key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER }])
@@ -4,4 +4,32 @@ require 'graphql/language/parser_tests'
4
4
  describe GraphQL::Language::Parser do
5
5
  include GraphQL::Language::ParserTests
6
6
  subject { GraphQL::Language::Parser }
7
+
8
+ describe "anonymous fragment extension" do
9
+ let(:document) { GraphQL.parse(query_string) }
10
+ let(:query_string) {%|
11
+ fragment on NestedType @or(something: "ok") {
12
+ anotherNestedField
13
+ }
14
+ |}
15
+
16
+ describe ".parse" do
17
+ it "parses queries" do
18
+ assert document
19
+ end
20
+
21
+ describe "visited nodes" do
22
+ let(:fragment) { document.definitions.first }
23
+
24
+ it "creates an anonymous fragment definition" do
25
+ assert fragment.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
26
+ assert_equal nil, fragment.name
27
+ assert_equal 1, fragment.selections.length
28
+ assert_equal "NestedType", fragment.type
29
+ assert_equal 1, fragment.directives.length
30
+ assert_equal [2, 7], fragment.position
31
+ end
32
+ end
33
+ end
34
+ end
7
35
  end
@@ -47,4 +47,8 @@ describe GraphQL::Relay::Mutation do
47
47
  new_ship_name = result["data"]["introduceShip"]["shipEdge"]["node"]["name"]
48
48
  assert_equal("Bagel", new_ship_name)
49
49
  end
50
+
51
+ it "applies the description to the derived field" do
52
+ assert_equal "Add a ship to this faction", IntroduceShipMutation.field.description
53
+ end
50
54
  end
@@ -45,6 +45,22 @@ describe GraphQL::Schema::Loader do
45
45
  field :body, !types.String
46
46
  end
47
47
 
48
+ media_type = GraphQL::InterfaceType.define do
49
+ name "Media"
50
+ description "!!!"
51
+ field :type, !types.String
52
+ end
53
+
54
+ video_type = GraphQL::ObjectType.define do
55
+ name "Video"
56
+ interfaces [media_type]
57
+ end
58
+
59
+ audio_type = GraphQL::ObjectType.define do
60
+ name "Audio"
61
+ interfaces [media_type]
62
+ end
63
+
48
64
  post_type = GraphQL::ObjectType.define do
49
65
  name "Post"
50
66
  description "A blog post"
@@ -53,6 +69,7 @@ describe GraphQL::Schema::Loader do
53
69
  field :title, !types.String
54
70
  field :body, !types.String
55
71
  field :comments, types[!comment_type]
72
+ field :attachment, media_type
56
73
  end
57
74
 
58
75
  content_type = GraphQL::UnionType.define do
@@ -76,7 +93,16 @@ describe GraphQL::Schema::Loader do
76
93
  end
77
94
  end
78
95
 
79
- GraphQL::Schema.new(query: query_root)
96
+ ping_mutation = GraphQL::Relay::Mutation.define do
97
+ name "Ping"
98
+ end
99
+
100
+ mutation_root = GraphQL::ObjectType.define do
101
+ name "Mutation"
102
+ field :ping, field: ping_mutation.field
103
+ end
104
+
105
+ GraphQL::Schema.define(query: query_root, mutation: mutation_root, orphan_types: [audio_type, video_type])
80
106
  }
81
107
 
82
108
  let(:schema_json) {
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe GraphQL::StaticValidation::FragmentTypesExist do
4
+ let(:query_string) {"
5
+ fragment on Cheese {
6
+ id
7
+ flavor
8
+ }
9
+ "}
10
+
11
+ let(:validator) { GraphQL::StaticValidation::Validator.new(schema: DummySchema, rules: [GraphQL::StaticValidation::FragmentsAreNamed]) }
12
+ let(:query) { GraphQL::Query.new(DummySchema, query_string) }
13
+ let(:errors) { validator.validate(query)[:errors] }
14
+
15
+ it "finds non-existent types on fragments" do
16
+ assert_equal(1, errors.length)
17
+ fragment_def_error = {
18
+ "message"=>"Fragment definition has no name",
19
+ "locations"=>[{"line"=>2, "column"=>5}],
20
+ "path"=>["fragment "],
21
+ }
22
+ assert_includes(errors, fragment_def_error, "on fragment definitions")
23
+ end
24
+ end
@@ -65,5 +65,17 @@ describe GraphQL::StaticValidation::Validator do
65
65
  assert_equal(1, errors.length)
66
66
  end
67
67
  end
68
+
69
+ describe "fragments with no names" do
70
+ let(:query_string) {%|
71
+ fragment on Cheese {
72
+ id
73
+ flavor
74
+ }
75
+ |}
76
+ it "marks an error" do
77
+ assert_equal(1, errors.length)
78
+ end
79
+ end
68
80
  end
69
81
  end
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.18.6
4
+ version: 0.18.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-29 00:00:00.000000000 Z
11
+ date: 2016-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codeclimate-test-reporter
@@ -372,6 +372,7 @@ files:
372
372
  - lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb
373
373
  - lib/graphql/static_validation/rules/fragment_types_exist.rb
374
374
  - lib/graphql/static_validation/rules/fragments_are_finite.rb
375
+ - lib/graphql/static_validation/rules/fragments_are_named.rb
375
376
  - lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb
376
377
  - lib/graphql/static_validation/rules/fragments_are_used.rb
377
378
  - lib/graphql/static_validation/rules/required_arguments_are_present.rb
@@ -452,6 +453,7 @@ files:
452
453
  - spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb
453
454
  - spec/graphql/static_validation/rules/fragment_types_exist_spec.rb
454
455
  - spec/graphql/static_validation/rules/fragments_are_finite_spec.rb
456
+ - spec/graphql/static_validation/rules/fragments_are_named_spec.rb
455
457
  - spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb
456
458
  - spec/graphql/static_validation/rules/fragments_are_used_spec.rb
457
459
  - spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb
@@ -559,6 +561,7 @@ test_files:
559
561
  - spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb
560
562
  - spec/graphql/static_validation/rules/fragment_types_exist_spec.rb
561
563
  - spec/graphql/static_validation/rules/fragments_are_finite_spec.rb
564
+ - spec/graphql/static_validation/rules/fragments_are_named_spec.rb
562
565
  - spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb
563
566
  - spec/graphql/static_validation/rules/fragments_are_used_spec.rb
564
567
  - spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb