graphql 1.4.0 → 1.4.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/introspection/schema_type.rb +3 -3
  3. data/lib/graphql/language/nodes.rb +1 -1
  4. data/lib/graphql/query.rb +39 -27
  5. data/lib/graphql/query/executor.rb +1 -1
  6. data/lib/graphql/query/variables.rb +21 -28
  7. data/lib/graphql/relay/connection_type.rb +2 -0
  8. data/lib/graphql/relay/relation_connection.rb +8 -2
  9. data/lib/graphql/schema.rb +3 -0
  10. data/lib/graphql/schema/warden.rb +9 -0
  11. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  12. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  13. data/lib/graphql/version.rb +1 -1
  14. data/spec/graphql/analysis/analyze_query_spec.rb +15 -15
  15. data/spec/graphql/analysis/field_usage_spec.rb +1 -1
  16. data/spec/graphql/analysis/max_query_complexity_spec.rb +8 -8
  17. data/spec/graphql/analysis/max_query_depth_spec.rb +7 -7
  18. data/spec/graphql/analysis/query_complexity_spec.rb +2 -2
  19. data/spec/graphql/analysis/query_depth_spec.rb +1 -1
  20. data/spec/graphql/base_type_spec.rb +19 -11
  21. data/spec/graphql/directive_spec.rb +1 -1
  22. data/spec/graphql/enum_type_spec.rb +2 -2
  23. data/spec/graphql/execution/typecast_spec.rb +19 -19
  24. data/spec/graphql/execution_error_spec.rb +1 -1
  25. data/spec/graphql/field_spec.rb +15 -7
  26. data/spec/graphql/id_type_spec.rb +1 -1
  27. data/spec/graphql/input_object_type_spec.rb +16 -16
  28. data/spec/graphql/interface_type_spec.rb +6 -6
  29. data/spec/graphql/internal_representation/rewrite_spec.rb +34 -34
  30. data/spec/graphql/introspection/directive_type_spec.rb +1 -1
  31. data/spec/graphql/introspection/input_value_type_spec.rb +2 -2
  32. data/spec/graphql/introspection/introspection_query_spec.rb +1 -1
  33. data/spec/graphql/introspection/schema_type_spec.rb +2 -2
  34. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  35. data/spec/graphql/language/parser_spec.rb +1 -1
  36. data/spec/graphql/non_null_type_spec.rb +3 -3
  37. data/spec/graphql/object_type_spec.rb +8 -8
  38. data/spec/graphql/query/executor_spec.rb +4 -4
  39. data/spec/graphql/query/variables_spec.rb +20 -4
  40. data/spec/graphql/query_spec.rb +20 -2
  41. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  42. data/spec/graphql/relay/mutation_spec.rb +9 -9
  43. data/spec/graphql/relay/node_spec.rb +8 -8
  44. data/spec/graphql/relay/relation_connection_spec.rb +24 -6
  45. data/spec/graphql/schema/catchall_middleware_spec.rb +3 -3
  46. data/spec/graphql/schema/reduce_types_spec.rb +9 -9
  47. data/spec/graphql/schema/type_expression_spec.rb +3 -3
  48. data/spec/graphql/schema/validation_spec.rb +1 -1
  49. data/spec/graphql/schema/warden_spec.rb +79 -0
  50. data/spec/graphql/schema_spec.rb +2 -2
  51. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
  52. data/spec/graphql/static_validation/type_stack_spec.rb +2 -2
  53. data/spec/graphql/static_validation/validator_spec.rb +2 -2
  54. data/spec/graphql/union_type_spec.rb +2 -2
  55. data/spec/spec_helper.rb +1 -1
  56. data/spec/support/dummy/data.rb +27 -0
  57. data/spec/support/dummy/schema.rb +369 -0
  58. data/spec/support/star_wars/data.rb +81 -0
  59. data/spec/support/star_wars/schema.rb +250 -0
  60. data/spec/support/static_validation_helpers.rb +2 -2
  61. metadata +10 -10
  62. data/spec/support/dairy_app.rb +0 -369
  63. data/spec/support/dairy_data.rb +0 -26
  64. data/spec/support/star_wars_data.rb +0 -80
  65. data/spec/support/star_wars_schema.rb +0 -242
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'ostruct'
3
-
4
- Cheese = Struct.new(:id, :flavor, :origin, :fat_content, :source)
5
- CHEESES = {
6
- 1 => Cheese.new(1, "Brie", "France", 0.19, 1),
7
- 2 => Cheese.new(2, "Gouda", "Netherlands", 0.3, 1),
8
- 3 => Cheese.new(3, "Manchego", "Spain", 0.065, "SHEEP")
9
- }
10
-
11
- Milk = Struct.new(:id, :fatContent, :origin, :source, :flavors)
12
- MILKS = {
13
- 1 => Milk.new(1, 0.04, "Antiquity", 1, ["Natural", "Chocolate", "Strawberry"]),
14
- }
15
-
16
- DAIRY = OpenStruct.new(
17
- id: 1,
18
- cheese: CHEESES[1],
19
- milks: [MILKS[1]]
20
- )
21
-
22
- COW = OpenStruct.new(
23
- id: 1,
24
- name: "Billy",
25
- last_produced_dairy: MILKS[1]
26
- )
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'ostruct'
3
-
4
- names = [
5
- 'X-Wing',
6
- 'Y-Wing',
7
- 'A-Wing',
8
- 'Millenium Falcon',
9
- 'Home One',
10
- 'TIE Fighter',
11
- 'TIE Interceptor',
12
- 'Executor',
13
- ]
14
-
15
- # ActiveRecord::Base.logger = Logger.new(STDOUT)
16
- `rm -f ./_test_.db`
17
- # Set up "Bases" in ActiveRecord
18
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: "./_test_.db")
19
-
20
- ActiveRecord::Schema.define do
21
- self.verbose = false
22
- create_table :bases do |t|
23
- t.column :name, :string
24
- t.column :planet, :string
25
- t.column :faction_id, :integer
26
- end
27
- end
28
-
29
- class Base < ActiveRecord::Base
30
- end
31
-
32
- Base.create!(name: "Yavin", planet: "Yavin 4", faction_id: 1)
33
- Base.create!(name: "Echo Base", planet: "Hoth", faction_id: 1)
34
- Base.create!(name: "Secret Hideout", planet: "Dantooine", faction_id: 1)
35
- Base.create!(name: "Death Star", planet: nil, faction_id: 2)
36
- Base.create!(name: "Shield Generator", planet: "Endor", faction_id: 2)
37
- Base.create!(name: "Headquarters", planet: "Coruscant", faction_id: 2)
38
-
39
- # Also, set up Bases with Sequel
40
- DB = Sequel.sqlite("./_test_.db")
41
- class SequelBase < Sequel::Model(:bases)
42
- end
43
-
44
- rebels = OpenStruct.new({
45
- id: '1',
46
- name: 'Alliance to Restore the Republic',
47
- ships: ['1', '2', '3', '4', '5'],
48
- bases: Base.where(faction_id: 1),
49
- basesClone: Base.where(faction_id: 1),
50
- })
51
-
52
-
53
- empire = OpenStruct.new({
54
- id: '2',
55
- name: 'Galactic Empire',
56
- ships: ['6', '7', '8'],
57
- bases: Base.where(faction_id: 2),
58
- basesClone: Base.where(faction_id: 2),
59
- })
60
-
61
- STAR_WARS_DATA = {
62
- "Faction" => {
63
- "1" => rebels,
64
- "2" => empire,
65
- },
66
- "Ship" => names.each_with_index.reduce({}) do |memo, (name, idx)|
67
- id = (idx + 1).to_s
68
- memo[id] = OpenStruct.new(name: name, id: id)
69
- memo
70
- end,
71
- "Base" => Hash.new { |h, k| h[k] = Base.find(k) }
72
- }
73
-
74
- def STAR_WARS_DATA.create_ship(name, faction_id)
75
- new_id = (self["Ship"].keys.map(&:to_i).max + 1).to_s
76
- new_ship = OpenStruct.new(id: new_id, name: name)
77
- self["Ship"][new_id] = new_ship
78
- self["Faction"][faction_id].ships << new_id
79
- new_ship
80
- end
@@ -1,242 +0,0 @@
1
- # frozen_string_literal: true
2
- # Adapted from graphql-relay-js
3
- # https://github.com/graphql/graphql-relay-js/blob/master/src/__tests__/starWarsSchema.js
4
-
5
- Ship = GraphQL::ObjectType.define do
6
- name "Ship"
7
- interfaces [GraphQL::Relay::Node.interface]
8
- global_id_field :id
9
- field :name, types.String
10
- end
11
-
12
- BaseType = GraphQL::ObjectType.define do
13
- name "Base"
14
- interfaces [GraphQL::Relay::Node.interface]
15
- global_id_field :id
16
- field :name, types.String
17
- field :planet, types.String
18
- end
19
-
20
- # Use an optional block to add fields to the connection type:
21
- BaseConnectionWithTotalCountType = BaseType.define_connection(nodes_field: true) do
22
- name "BasesConnectionWithTotalCount"
23
- field :totalCount do
24
- type types.Int
25
- resolve ->(obj, args, ctx) { obj.nodes.count }
26
- end
27
- end
28
-
29
- class CustomBaseEdge < GraphQL::Relay::Edge
30
- def upcased_name
31
- node.name.upcase
32
- end
33
-
34
- def upcased_parent_name
35
- parent.name.upcase
36
- end
37
- end
38
-
39
- CustomBaseEdgeType = BaseType.define_edge do
40
- name "CustomBaseEdge"
41
- field :upcasedName, types.String, property: :upcased_name
42
- field :upcasedParentName, types.String, property: :upcased_parent_name
43
- field :edgeClassName, types.String do
44
- resolve ->(obj, args, ctx) { obj.class.name }
45
- end
46
- end
47
-
48
- CustomEdgeBaseConnectionType = BaseType.define_connection(edge_class: CustomBaseEdge, edge_type: CustomBaseEdgeType, nodes_field: true) do
49
- name "CustomEdgeBaseConnection"
50
-
51
- field :totalCountTimes100 do
52
- type types.Int
53
- resolve ->(obj, args, ctx) { obj.nodes.count * 100 }
54
- end
55
-
56
- field :fieldName, types.String, resolve: ->(obj, args, ctx) { obj.field.name }
57
- end
58
-
59
- Faction = GraphQL::ObjectType.define do
60
- name "Faction"
61
- interfaces [GraphQL::Relay::Node.interface]
62
-
63
- field :id, !types.ID, resolve: GraphQL::Relay::GlobalIdResolve.new(type: Faction)
64
- field :name, types.String
65
- connection :ships, Ship.connection_type do
66
- resolve ->(obj, args, ctx) {
67
- all_ships = obj.ships.map {|ship_id| STAR_WARS_DATA["Ship"][ship_id] }
68
- if args[:nameIncludes]
69
- all_ships = all_ships.select { |ship| ship.name.include?(args[:nameIncludes])}
70
- end
71
- all_ships
72
- }
73
- # You can define arguments here and use them in the connection
74
- argument :nameIncludes, types.String
75
- end
76
- connection :shipsWithMaxPageSize, Ship.connection_type, max_page_size: 2 do
77
- resolve ->(obj, args, ctx) {
78
- all_ships = obj.ships.map {|ship_id| STAR_WARS_DATA["Ship"][ship_id] }
79
- if args[:nameIncludes]
80
- all_ships = all_ships.select { |ship| ship.name.include?(args[:nameIncludes])}
81
- end
82
- all_ships
83
- }
84
- # You can define arguments here and use them in the connection
85
- argument :nameIncludes, types.String
86
- end
87
-
88
- connection :bases, BaseConnectionWithTotalCountType do
89
- # Resolve field should return an Array, the Connection
90
- # will do the rest!
91
- resolve ->(obj, args, ctx) {
92
- all_bases = Base.where(id: obj.bases)
93
- if args[:nameIncludes]
94
- all_bases = all_bases.where("name LIKE ?", "%#{args[:nameIncludes]}%")
95
- end
96
- all_bases
97
- }
98
- argument :nameIncludes, types.String
99
- end
100
-
101
- connection :basesClone, BaseType.connection_type
102
- connection :basesByName, BaseType.connection_type, property: :bases do
103
- argument :order, types.String, default_value: "name"
104
- resolve ->(obj, args, ctx) {
105
- if args[:order].present?
106
- obj.bases.order(args[:order])
107
- else
108
- obj.bases
109
- end
110
- }
111
- end
112
-
113
- connection :basesWithMaxLimitRelation, BaseType.connection_type, max_page_size: 2 do
114
- resolve ->(object, args, context) { Base.all }
115
- end
116
-
117
- connection :basesWithMaxLimitArray, BaseType.connection_type, max_page_size: 2 do
118
- resolve ->(object, args, context) { Base.all.to_a }
119
- end
120
-
121
- connection :basesAsSequelDataset, BaseConnectionWithTotalCountType do
122
- argument :nameIncludes, types.String
123
- resolve ->(obj, args, ctx) {
124
- all_bases = SequelBase.where(faction_id: obj.id)
125
- if args[:nameIncludes]
126
- all_bases = all_bases.where("name LIKE ?", "%#{args[:nameIncludes]}%")
127
- end
128
- all_bases
129
- }
130
- end
131
-
132
- connection :basesWithCustomEdge, CustomEdgeBaseConnectionType, property: :bases
133
- end
134
-
135
- # Define a mutation. It will also:
136
- # - define a derived InputObjectType
137
- # - define a derived ObjectType (for return)
138
- # - define a field, accessible from {Mutation#field}
139
- #
140
- # The resolve proc takes `inputs, ctx`, where:
141
- # - `inputs` has the keys defined with `input_field`
142
- # - `ctx` is the Query context (like normal fields)
143
- #
144
- # Notice that you leave out clientMutationId.
145
- IntroduceShipMutation = GraphQL::Relay::Mutation.define do
146
- # Used as the root for derived types:
147
- name "IntroduceShip"
148
- description "Add a ship to this faction"
149
-
150
- # Nested under `input` in the query:
151
- input_field :shipName, types.String
152
- input_field :factionId, !types.ID
153
-
154
- # Result may have access to these fields:
155
- return_field :shipEdge, Ship.edge_type
156
- return_field :faction, Faction
157
-
158
- # Here's the mutation operation:
159
- resolve ->(root_obj, inputs, ctx) {
160
- faction_id = inputs["factionId"]
161
- if inputs["shipName"] == 'Millennium Falcon'
162
- GraphQL::ExecutionError.new("Sorry, Millennium Falcon ship is reserved")
163
-
164
- else
165
- ship = STAR_WARS_DATA.create_ship(inputs["shipName"], faction_id)
166
- faction = STAR_WARS_DATA["Faction"][faction_id]
167
- connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(faction.ships)
168
- ships_connection = connection_class.new(faction.ships, inputs)
169
- ship_edge = GraphQL::Relay::Edge.new(ship, ships_connection)
170
- result = {
171
- shipEdge: ship_edge,
172
- faction: faction
173
- }
174
- if inputs["shipName"] == "Slave II"
175
- LazyWrapper.new(result)
176
- else
177
- result
178
- end
179
- end
180
- }
181
- end
182
-
183
-
184
- class LazyWrapper
185
- attr_reader :value
186
- def initialize(value)
187
- @value = value
188
- end
189
- end
190
-
191
- QueryType = GraphQL::ObjectType.define do
192
- name "Query"
193
- field :rebels, Faction do
194
- resolve ->(obj, args, ctx) { STAR_WARS_DATA["Faction"]["1"]}
195
- end
196
-
197
- field :empire, Faction do
198
- resolve ->(obj, args, ctx) { STAR_WARS_DATA["Faction"]["2"]}
199
- end
200
-
201
- field :largestBase, BaseType do
202
- resolve ->(obj, args, ctx) { Base.find(3) }
203
- end
204
-
205
- field :node, GraphQL::Relay::Node.field
206
- end
207
-
208
- MutationType = GraphQL::ObjectType.define do
209
- name "Mutation"
210
- # The mutation object exposes a field:
211
- field :introduceShip, field: IntroduceShipMutation.field
212
- end
213
-
214
- StarWarsSchema = GraphQL::Schema.define do
215
- query(QueryType)
216
- mutation(MutationType)
217
-
218
- resolve_type ->(object, ctx) {
219
- if object == :test_error
220
- :not_a_type
221
- elsif object.is_a?(Base)
222
- BaseType
223
- elsif STAR_WARS_DATA["Faction"].values.include?(object)
224
- Faction
225
- elsif STAR_WARS_DATA["Ship"].values.include?(object)
226
- Ship
227
- else
228
- nil
229
- end
230
- }
231
-
232
- object_from_id ->(node_id, ctx) do
233
- type_name, id = GraphQL::Schema::UniqueWithinType.decode(node_id)
234
- STAR_WARS_DATA[type_name][id]
235
- end
236
-
237
- id_from_object ->(object, type, ctx) do
238
- GraphQL::Schema::UniqueWithinType.encode(type.name, object.id)
239
- end
240
-
241
- lazy_resolve(LazyWrapper, :value)
242
- end