graphql 0.18.6 → 0.18.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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