graphql 1.8.8 → 1.8.9

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/base_type.rb +1 -1
  3. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
  4. data/lib/graphql/enum_type.rb +4 -0
  5. data/lib/graphql/execution/execute.rb +2 -2
  6. data/lib/graphql/field.rb +1 -7
  7. data/lib/graphql/schema.rb +25 -3
  8. data/lib/graphql/schema/argument.rb +3 -4
  9. data/lib/graphql/schema/field.rb +19 -4
  10. data/lib/graphql/types/iso_8601_date_time.rb +15 -1
  11. data/lib/graphql/version.rb +1 -1
  12. data/readme.md +1 -1
  13. data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
  14. data/spec/graphql/base_type_spec.rb +3 -3
  15. data/spec/graphql/enum_type_spec.rb +1 -1
  16. data/spec/graphql/execution/lazy_spec.rb +18 -1
  17. data/spec/graphql/execution/typecast_spec.rb +20 -20
  18. data/spec/graphql/field_spec.rb +1 -1
  19. data/spec/graphql/input_object_type_spec.rb +25 -0
  20. data/spec/graphql/interface_type_spec.rb +4 -4
  21. data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
  22. data/spec/graphql/object_type_spec.rb +32 -27
  23. data/spec/graphql/query/executor_spec.rb +2 -2
  24. data/spec/graphql/schema/argument_spec.rb +27 -0
  25. data/spec/graphql/schema/field_spec.rb +16 -0
  26. data/spec/graphql/schema/interface_spec.rb +2 -2
  27. data/spec/graphql/schema/relay_classic_mutation_spec.rb +36 -0
  28. data/spec/graphql/schema/traversal_spec.rb +10 -10
  29. data/spec/graphql/schema/type_expression_spec.rb +2 -2
  30. data/spec/graphql/schema/validation_spec.rb +1 -1
  31. data/spec/graphql/types/iso_8601_date_time_spec.rb +25 -0
  32. data/spec/graphql/union_type_spec.rb +2 -2
  33. data/spec/integration/rails/graphql/input_object_type_spec.rb +4 -4
  34. data/spec/integration/rails/graphql/query/variables_spec.rb +7 -7
  35. data/spec/integration/rails/graphql/schema_spec.rb +6 -5
  36. data/spec/integration/tmp/app/graphql/types/page_type.rb +4 -0
  37. data/spec/support/dummy/data.rb +20 -17
  38. data/spec/support/dummy/schema.rb +271 -281
  39. data/spec/support/jazz.rb +45 -0
  40. data/spec/support/lazy_helpers.rb +13 -4
  41. metadata +216 -212
@@ -69,21 +69,21 @@ describe GraphQL::Query::Variables do
69
69
  it "checks for string matches" do
70
70
  # These get merged into all the values above
71
71
  default_values = {
72
- "originDairy"=>"Sugar Hollow Dairy",
73
- "organic"=>false,
74
- "order_by"=>{"direction"=>"ASC"}
72
+ origin_dairy: "Sugar Hollow Dairy",
73
+ organic: false,
74
+ order_by: { direction: "ASC" },
75
75
  }
76
76
 
77
77
  expected_input_1 = {
78
- "source" => 1,
79
- "fatContent" => 0.99,
78
+ source: 1,
79
+ fat_content: 0.99,
80
80
  }.merge(default_values)
81
81
 
82
82
  assert_equal(expected_input_1, variables["dairy_product_1"].to_h)
83
83
 
84
84
  expected_input_2 = {
85
- "source" => :donkey,
86
- "fatContent" => 0.89,
85
+ source: :donkey,
86
+ fat_content: 0.89,
87
87
  }.merge(default_values)
88
88
  assert_equal(expected_input_2, variables["dairy_product_2"].to_h)
89
89
  end
@@ -47,9 +47,9 @@ describe GraphQL::Schema do
47
47
  it "returns a list of the schema's root types" do
48
48
  assert_equal(
49
49
  [
50
- Dummy::DairyAppQueryType,
51
- Dummy::DairyAppMutationType.graphql_definition,
52
- Dummy::SubscriptionType
50
+ Dummy::DairyAppQuery.graphql_definition,
51
+ Dummy::DairyAppMutation.graphql_definition.graphql_definition,
52
+ Dummy::Subscription.graphql_definition
53
53
  ],
54
54
  schema.root_types
55
55
  )
@@ -58,7 +58,8 @@ describe GraphQL::Schema do
58
58
 
59
59
  describe "#references_to" do
60
60
  it "returns a list of Field and Arguments of that type" do
61
- assert_equal [schema.types["Query"].fields["cow"]], schema.references_to("Cow")
61
+ cow_field = schema.get_field("Query", "cow")
62
+ assert_equal [cow_field], schema.references_to("Cow")
62
63
  end
63
64
 
64
65
  it "returns an empty list when type is not referenced by any field or argument" do
@@ -450,7 +451,7 @@ type Query {
450
451
  it "returns fields by type or type name" do
451
452
  field = schema.get_field("Cheese", "id")
452
453
  assert_instance_of GraphQL::Field, field
453
- field_2 = schema.get_field(Dummy::CheeseType, "id")
454
+ field_2 = schema.get_field(Dummy::Cheese.graphql_definition, "id")
454
455
  assert_equal field, field_2
455
456
  end
456
457
  end
@@ -0,0 +1,4 @@
1
+ module Types
2
+ class PageType < Types::BaseObject
3
+ end
4
+ end
@@ -1,27 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
  require 'ostruct'
3
3
  module Dummy
4
- Cheese = Struct.new(:id, :flavor, :origin, :fat_content, :source) do
5
- def ==(other)
6
- # This is buggy on purpose -- it shouldn't be called during execution.
7
- other.id == id
8
- end
4
+ module Data
5
+ Cheese = Struct.new(:id, :flavor, :origin, :fat_content, :source) do
6
+ def ==(other)
7
+ # This is buggy on purpose -- it shouldn't be called during execution.
8
+ other.id == id
9
+ end
9
10
 
10
- # Alias for when this is treated as milk in EdibleAsMilkInterface
11
- def fatContent # rubocop:disable Naming/MethodName
12
- fat_content
11
+ # Alias for when this is treated as milk in EdibleAsMilkInterface
12
+ def fatContent # rubocop:disable Naming/MethodName
13
+ fat_content
14
+ end
13
15
  end
16
+
17
+ Milk = Struct.new(:id, :fat_content, :origin, :source, :flavors)
18
+ Cow = Struct.new(:id, :name, :last_produced_dairy)
19
+ Goat = Struct.new(:id, :name, :last_produced_dairy)
14
20
  end
15
21
 
16
22
  CHEESES = {
17
- 1 => Cheese.new(1, "Brie", "France", 0.19, 1),
18
- 2 => Cheese.new(2, "Gouda", "Netherlands", 0.3, 1),
19
- 3 => Cheese.new(3, "Manchego", "Spain", 0.065, "SHEEP")
23
+ 1 => Data::Cheese.new(1, "Brie", "France", 0.19, 1),
24
+ 2 => Data::Cheese.new(2, "Gouda", "Netherlands", 0.3, 1),
25
+ 3 => Data::Cheese.new(3, "Manchego", "Spain", 0.065, "SHEEP")
20
26
  }
21
27
 
22
- Milk = Struct.new(:id, :fatContent, :origin, :source, :flavors)
23
28
  MILKS = {
24
- 1 => Milk.new(1, 0.04, "Antiquity", 1, ["Natural", "Chocolate", "Strawberry"]),
29
+ 1 => Data::Milk.new(1, 0.04, "Antiquity", 1, ["Natural", "Chocolate", "Strawberry"]),
25
30
  }
26
31
 
27
32
  DAIRY = OpenStruct.new(
@@ -30,13 +35,11 @@ module Dummy
30
35
  milks: [MILKS[1]]
31
36
  )
32
37
 
33
- Cow = Struct.new(:id, :name, :last_produced_dairy)
34
38
  COWS = {
35
- 1 => Cow.new(1, "Billy", MILKS[1])
39
+ 1 => Data::Cow.new(1, "Billy", MILKS[1])
36
40
  }
37
41
 
38
- Goat = Struct.new(:id, :name, :last_produced_dairy)
39
42
  GOATS = {
40
- 1 => Goat.new(1, "Gilly", MILKS[1]),
43
+ 1 => Data::Goat.new(1, "Gilly", MILKS[1]),
41
44
  }
42
45
  end
@@ -7,40 +7,58 @@ module Dummy
7
7
  GraphQL::Field.accepts_definitions(joins: GraphQL::Define.assign_metadata_key(:joins))
8
8
  GraphQL::BaseType.accepts_definitions(class_names: GraphQL::Define.assign_metadata_key(:class_names))
9
9
 
10
- LocalProductInterface = GraphQL::InterfaceType.define do
11
- name "LocalProduct"
12
- description "Something that comes from somewhere"
13
- field :origin, !types.String, "Place the thing comes from"
10
+ class BaseField < GraphQL::Schema::Field
11
+ accepts_definition :joins
14
12
  end
15
13
 
16
- EdibleInterface = GraphQL::InterfaceType.define do
17
- name "Edible"
18
- description "Something you can eat, yum"
19
- field :fatContent, !types.Float, "Percentage which is fat"
20
- field :origin, !types.String, "Place the edible comes from"
21
- field :selfAsEdible, EdibleInterface, resolve: ->(o, a, c) { o }
14
+ module BaseInterface
15
+ include GraphQL::Schema::Interface
22
16
  end
23
17
 
24
- EdibleAsMilkInterface = EdibleInterface.redefine do
25
- name "EdibleAsMilk"
26
- description "Milk :+1:"
27
- resolve_type ->(obj, ctx) { MilkType }
18
+ class BaseObject < GraphQL::Schema::Object
19
+ field_class BaseField
20
+ accepts_definition :class_names
28
21
  end
29
22
 
30
- AnimalProductInterface = GraphQL::InterfaceType.define do
31
- name "AnimalProduct"
32
- description "Comes from an animal, no joke"
33
- field :source, !DairyAnimalEnum, "Animal which produced this product"
23
+ class BaseUnion < GraphQL::Schema::Union
34
24
  end
35
25
 
36
- BeverageUnion = GraphQL::UnionType.define do
37
- name "Beverage"
38
- description "Something you can drink"
39
- possible_types [MilkType]
26
+ class BaseEnum < GraphQL::Schema::Enum
27
+ end
28
+
29
+ class BaseInputObject < GraphQL::Schema::InputObject
30
+ end
31
+
32
+ class BaseScalar < GraphQL::Schema::Scalar
40
33
  end
41
34
 
42
- DairyAnimalEnum = GraphQL::EnumType.define do
43
- name "DairyAnimal"
35
+ module LocalProduct
36
+ include BaseInterface
37
+ description "Something that comes from somewhere"
38
+ field :origin, String, null: false,
39
+ description: "Place the thing comes from"
40
+ end
41
+
42
+ module Edible
43
+ include BaseInterface
44
+ description "Something you can eat, yum"
45
+ field :fat_content, Float, null: false, description: "Percentage which is fat"
46
+ field :origin, String, null: false, description: "Place the edible comes from"
47
+ field :self_as_edible, Edible, null: true
48
+ def self_as_edible
49
+ object
50
+ end
51
+ end
52
+
53
+ module EdibleAsMilk
54
+ include Edible
55
+ description "Milk :+1:"
56
+ def self.resolve_type(obj, ctx)
57
+ Milk
58
+ end
59
+ end
60
+
61
+ class DairyAnimal < BaseEnum
44
62
  description "An animal which can yield milk"
45
63
  value("COW", "Animal with black and white spots", value: 1)
46
64
  value("DONKEY", "Animal with fur", value: :donkey)
@@ -50,217 +68,206 @@ module Dummy
50
68
  value("YAK", "Animal with long hair", deprecation_reason: "Out of fashion")
51
69
  end
52
70
 
53
- CheeseType = GraphQL::ObjectType.define do
54
- name "Cheese"
71
+ module AnimalProduct
72
+ include BaseInterface
73
+ description "Comes from an animal, no joke"
74
+ field :source, DairyAnimal, "Animal which produced this product", null: false
75
+ end
76
+
77
+ class Cheese < BaseObject
55
78
  class_names ["Cheese"]
56
79
  description "Cultured dairy product"
57
- interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
80
+ implements Edible
81
+ implements EdibleAsMilk
82
+ implements AnimalProduct
83
+ implements LocalProduct
58
84
 
59
- # Can have (name, type, desc)
60
- field :id, !types.Int, "Unique identifier"
61
- field :flavor, !types.String, "Kind of Cheese"
62
- field :origin, !types.String, "Place the cheese comes from"
85
+ field :id, Int, "Unique identifier", null: false
86
+ field :flavor, String, "Kind of Cheese", null: false
87
+ field :origin, String, "Place the cheese comes from", null: false
63
88
 
64
- field :source, !DairyAnimalEnum,
65
- "Animal which produced the milk for this cheese"
89
+ field :source, DairyAnimal,
90
+ "Animal which produced the milk for this cheese",
91
+ null: false
66
92
 
67
- # Or can define by block, `resolve ->` should override `property:`
68
- field :similarCheese, CheeseType, "Cheeses like this one", property: :this_should_be_overriden do
93
+ field :similar_cheese, Cheese, "Cheeses like this one", null: true do
69
94
  # metadata test
70
95
  joins [:cheeses, :milks]
71
- argument :source, !types[!DairyAnimalEnum]
72
- argument :nullableSource, types[!DairyAnimalEnum], default_value: [1]
73
- resolve ->(t, a, c) {
74
- # get the strings out:
75
- sources = a["source"]
76
- if sources.include?("YAK")
77
- raise NoSuchDairyError.new("No cheeses are made from Yak milk!")
78
- else
79
- CHEESES.values.find { |cheese| sources.include?(cheese.source) }
80
- end
81
- }
96
+ argument :source, [DairyAnimal], required: true
97
+ argument :nullableSource, [DairyAnimal], required: false, default_value: [1]
98
+ end
99
+
100
+ def similar_cheese(source:, nullable_source:)
101
+ # get the strings out:
102
+ sources = source
103
+ if sources.include?("YAK")
104
+ raise NoSuchDairyError.new("No cheeses are made from Yak milk!")
105
+ else
106
+ CHEESES.values.find { |cheese| sources.include?(cheese.source) }
107
+ end
82
108
  end
83
109
 
84
- field :nullableCheese, CheeseType, "Cheeses like this one" do
85
- argument :source, types[!DairyAnimalEnum]
86
- resolve ->(t, a, c) { raise("NotImplemented") }
110
+ field :nullable_cheese, Cheese, "Cheeses like this one", null: true do
111
+ argument :source, [DairyAnimal], required: false
87
112
  end
113
+ def nullable_cheese; raise("NotImplemented"); end
88
114
 
89
- field :deeplyNullableCheese, CheeseType, "Cheeses like this one" do
90
- argument :source, types[types[DairyAnimalEnum]]
91
- resolve ->(t, a, c) { raise("NotImplemented") }
115
+ field :deeply_nullable_cheese, Cheese, "Cheeses like this one", null: true do
116
+ argument :source, [[DairyAnimal, null: true], null: true], required: false
92
117
  end
118
+ def deeply_nullable_cheese; raise("NotImplemented"); end
93
119
 
94
120
  # Keywords can be used for definition methods
95
- field :fatContent,
96
- property: :fat_content,
97
- type: !GraphQL::FLOAT_TYPE,
121
+ field :fat_content,
122
+ type: GraphQL::FLOAT_TYPE,
123
+ null: false,
98
124
  description: "Percentage which is milkfat",
99
125
  deprecation_reason: "Diet fashion has changed"
100
126
  end
101
127
 
102
- MilkType = GraphQL::ObjectType.define do
103
- name "Milk"
128
+ class Milk < BaseObject
104
129
  description "Dairy beverage"
105
- interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
106
- field :id, !types.ID
107
- field :source, !DairyAnimalEnum, "Animal which produced this milk", hash_key: :source
108
- field :origin, !types.String, "Place the milk comes from"
109
- field :flavors, types[types.String], "Chocolate, Strawberry, etc" do
110
- argument :limit, types.Int
111
- resolve ->(milk, args, ctx) {
112
- args[:limit] ? milk.flavors.first(args.limit) : milk.flavors
113
- }
114
- end
115
- field :executionError do
116
- type GraphQL::STRING_TYPE
117
- resolve ->(t, a, c) { raise(GraphQL::ExecutionError, "There was an execution error") }
130
+ implements Edible
131
+ implements EdibleAsMilk
132
+ implements AnimalProduct
133
+ implements LocalProduct
134
+
135
+ field :id, ID, null: false
136
+ field :source, DairyAnimal, null: false, description: "Animal which produced this milk"
137
+ field :origin, String, null: false, description: "Place the milk comes from"
138
+ field :flavors, [String, null: true], null: true, description: "Chocolate, Strawberry, etc" do
139
+ argument :limit, Int, required: false
118
140
  end
119
141
 
120
- field :allDairy, -> { types[DairyProductUnion] } do
121
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
142
+ def flavors(limit: nil)
143
+ limit ? object.flavors.first(limit) : object.flavors
122
144
  end
145
+
146
+ field :execution_error, String, null: true
147
+ def execution_error; raise(GraphQL::ExecutionError, "There was an execution error"); end
148
+
149
+ field :all_dairy, ["Dummy::DairyProduct", null: true], null: true
150
+ def all_dairy; CHEESES.values + MILKS.values; end
151
+ end
152
+
153
+ class Beverage < BaseUnion
154
+ description "Something you can drink"
155
+ possible_types Milk
123
156
  end
124
157
 
125
- SweetenerInterface = GraphQL::InterfaceType.define do
126
- name "Sweetener"
127
- field :sweetness, types.Int
158
+ module Sweetener
159
+ include BaseInterface
160
+ field :sweetness, Integer, null: true
128
161
  end
129
162
 
130
163
  # No actual data; This type is an "orphan", only accessible through Interfaces
131
- HoneyType = GraphQL::ObjectType.define do
132
- name "Honey"
164
+ class Honey < BaseObject
133
165
  description "Sweet, dehydrated bee barf"
134
- field :flowerType, types.String, "What flower this honey came from"
135
- interfaces [EdibleInterface, AnimalProductInterface, SweetenerInterface]
166
+ field :flower_type, String, "What flower this honey came from", null: true
167
+ implements Edible
168
+ implements AnimalProduct
169
+ implements Sweetener
136
170
  end
137
171
 
138
- DairyType = GraphQL::ObjectType.define do
139
- name "Dairy"
172
+ class Dairy < BaseObject
140
173
  description "A farm where milk is harvested and cheese is produced"
141
- field :id, !types.ID
142
- field :cheese, CheeseType
143
- field :milks, types[MilkType]
174
+ field :id, ID, null: false
175
+ field :cheese, Cheese, null: true
176
+ field :milks, [Milk, null: true], null: true
144
177
  end
145
178
 
146
- MaybeNullType = GraphQL::ObjectType.define do
147
- name "MaybeNull"
179
+ class MaybeNull < BaseObject
148
180
  description "An object whose fields return nil"
149
- field :cheese, CheeseType
181
+ field :cheese, Cheese, null: true
150
182
  end
151
183
 
152
- TracingScalarType = GraphQL::ObjectType.define do
153
- name "TracingScalar"
184
+ class TracingScalar < BaseObject
154
185
  description "An object which has traced scalars"
155
186
 
156
- field :traceNil, types.Int
157
- field :traceFalse, types.Int, trace: false
158
- field :traceTrue, types.Int, trace: true
187
+ field :trace_nil, Integer, null: true
188
+ field :trace_false, Integer, null: true, trace: false
189
+ field :trace_true, Integer, null: true, trace: true
159
190
  end
160
191
 
161
- DairyProductUnion = GraphQL::UnionType.define do
162
- name "DairyProduct"
192
+ class DairyProduct < BaseUnion
163
193
  description "Kinds of food made from milk"
164
194
  # Test that these forms of declaration still work:
165
- possible_types ["Dummy::MilkType", -> { CheeseType }]
195
+ possible_types "Dummy::Milk", Cheese
166
196
  end
167
197
 
168
- CowType = GraphQL::ObjectType.define do
169
- name "Cow"
198
+ class Cow < BaseObject
170
199
  description "A bovine animal that produces milk"
171
- field :id, !types.ID
172
- field :name, types.String
173
- field :last_produced_dairy, DairyProductUnion
200
+ field :id, ID, null: false
201
+ field :name, String, null: true
202
+ field :last_produced_dairy, DairyProduct, null: true
174
203
 
175
- field :cantBeNullButIs do
176
- type !GraphQL::STRING_TYPE
177
- resolve ->(t, a, c) { nil }
178
- end
204
+ field :cant_be_null_but_is, String, null: false
205
+ def cant_be_null_but_is; nil; end
179
206
 
180
- field :cantBeNullButRaisesExecutionError do
181
- type !GraphQL::STRING_TYPE
182
- resolve ->(t, a, c) { raise GraphQL::ExecutionError, "BOOM" }
183
- end
207
+ field :cant_be_null_but_raises_execution_error, String, null: false
208
+ def cant_be_null_but_raises_execution_error; raise(GraphQL::ExecutionError, "BOOM"); end
184
209
  end
185
210
 
186
- GoatType = GraphQL::ObjectType.define do
187
- name "Goat"
211
+ class Goat < BaseObject
188
212
  description "An caprinae animal that produces milk"
189
- field :id, !types.ID
190
- field :name, types.String
191
- field :last_produced_dairy, DairyProductUnion
213
+ field :id, ID, null: false
214
+ field :name, String, null: true
215
+ field :last_produced_dairy, DairyProduct, null: true
192
216
  end
193
217
 
194
- AnimalUnion = GraphQL::UnionType.define do
195
- name "Animal"
218
+ class Animal < BaseUnion
196
219
  description "Species of living things"
197
- possible_types [CowType, GoatType]
220
+ possible_types Cow, Goat
198
221
  end
199
222
 
200
- AnimalAsCowUnion = GraphQL::UnionType.define do
201
- name "AnimalAsCow"
223
+ class AnimalAsCow < BaseUnion
202
224
  description "All animals go mooooo!"
203
- possible_types [CowType]
204
- resolve_type ->(obj, ctx) {
205
- CowType
206
- }
225
+ possible_types Cow
226
+ def self.resolve_type(obj, ctx)
227
+ Cow
228
+ end
207
229
  end
208
230
 
209
- ResourceOrderType = GraphQL::InputObjectType.define {
210
- name "ResourceOrderType"
231
+ class ResourceOrder < BaseInputObject
232
+ graphql_name "ResourceOrderType"
211
233
  description "Properties used to determine ordering"
212
234
 
213
- argument :direction, !types.String do
214
- description "ASC or DESC"
215
- end
216
- }
235
+ argument :direction, String, required: true, description: "ASC or DESC"
236
+ end
217
237
 
218
- DairyProductInputType = GraphQL::InputObjectType.define {
219
- name "DairyProductInput"
238
+ class DairyProductInput < BaseInputObject
220
239
  description "Properties for finding a dairy product"
221
- input_field :source, !DairyAnimalEnum do
222
- # ensure we can define description in block
223
- description "Where it came from"
224
- end
225
-
226
- input_field :originDairy, types.String, "Dairy which produced it", default_value: "Sugar Hollow Dairy"
240
+ argument :source, DairyAnimal, required: true, description: "Where it came from"
241
+ argument :origin_dairy, String, required: false, description: "Dairy which produced it", default_value: "Sugar Hollow Dairy"
242
+ argument :fat_content, Float, required: false, description: "How much fat it has", default_value: 0.3
243
+ argument :organic, Boolean, required: false, default_value: false
244
+ argument :order_by, ResourceOrder, required: false, default_value: { direction: "ASC" }, camelize: false
245
+ end
227
246
 
228
- input_field :fatContent, types.Float, "How much fat it has" do
229
- # ensure we can define default in block
230
- default_value 0.3
247
+ class DeepNonNull < BaseObject
248
+ field :non_null_int, Integer, null: false do
249
+ argument :returning, Integer, required: false
231
250
  end
232
-
233
- # ensure default can be false
234
- input_field :organic, types.Boolean, default_value: false
235
-
236
- input_field :order_by, -> { ResourceOrderType }, default_value: { direction: 'ASC' }
237
- }
238
-
239
- DeepNonNullType = GraphQL::ObjectType.define do
240
- name "DeepNonNull"
241
- field :nonNullInt, !types.Int do
242
- argument :returning, types.Int
243
- resolve ->(obj, args, ctx) { args.returning }
251
+ def non_null_int(returning: nil)
252
+ returning
244
253
  end
245
254
 
246
- field :deepNonNull, DeepNonNullType.to_non_null_type do
247
- resolve ->(obj, args, ctx) { :deepNonNull }
248
- end
255
+ field :deep_non_null, DeepNonNull, null: false
256
+ def deep_non_null; :deep_non_null; end
249
257
  end
250
258
 
251
- TimeType = GraphQL::ScalarType.define do
252
- name "Time"
259
+ class Time < BaseScalar
253
260
  description "Time since epoch in seconds"
254
261
 
255
- coerce_input ->(value, ctx) do
256
- begin
257
- Time.at(Float(value))
258
- rescue ArgumentError
259
- raise GraphQL::CoercionError, 'cannot coerce to Float'
260
- end
262
+ def self.coerce_input(value, ctx)
263
+ Time.at(Float(value))
264
+ rescue ArgumentError
265
+ raise GraphQL::CoercionError, 'cannot coerce to Float'
261
266
  end
262
267
 
263
- coerce_result ->(value, ctx) { value.to_f }
268
+ def self.coerce_result(value, ctx)
269
+ value.to_f
270
+ end
264
271
  end
265
272
 
266
273
  class FetchItem < GraphQL::Function
@@ -294,162 +301,146 @@ module Dummy
294
301
  end
295
302
  end
296
303
 
297
- SourceFieldDefn = Proc.new {
298
- type GraphQL::ListType.new(of_type: CheeseType)
299
- description "Cheese from source"
300
- argument :source, DairyAnimalEnum, default_value: 1
301
- resolve ->(target, arguments, context) {
302
- CHEESES.values.select{ |c| c.source == arguments["source"] }
303
- }
304
- }
305
-
306
304
  FavoriteFieldDefn = GraphQL::Field.define do
307
305
  name "favoriteEdible"
308
306
  description "My favorite food"
309
- type EdibleInterface
307
+ type Edible
310
308
  resolve ->(t, a, c) { MILKS[1] }
311
309
  end
312
310
 
313
- DairyAppQueryType = GraphQL::ObjectType.define do
314
- name "Query"
311
+ class DairyAppQuery < BaseObject
312
+ graphql_name "Query"
315
313
  description "Query root of the system"
316
- field :root, types.String do
317
- resolve ->(root_value, args, c) { root_value }
318
- end
319
- field :cheese, function: FetchItem.new(type: CheeseType, data: CHEESES)
320
- field :milk, function: FetchItem.new(type: MilkType, data: MILKS, id_type: !types.ID)
321
- field :dairy, function: GetSingleton.new(type: DairyType, data: DAIRY)
322
- field :fromSource, &SourceFieldDefn
323
- field :favoriteEdible, FavoriteFieldDefn
324
- field :cow, function: GetSingleton.new(type: CowType, data: COWS[1])
325
- field :searchDairy do
314
+ # Returns `root_value:`
315
+ field :root, String, null: true
316
+ def root
317
+ object
318
+ end
319
+ field :cheese, function: FetchItem.new(type: Cheese, data: CHEESES)
320
+ field :milk, function: FetchItem.new(type: Milk, data: MILKS, id_type: GraphQL::Types::ID.to_non_null_type)
321
+ field :dairy, function: GetSingleton.new(type: Dairy, data: DAIRY)
322
+ field :from_source, [Cheese, null: true], null: true, description: "Cheese from source" do
323
+ argument :source, DairyAnimal, required: false, default_value: 1
324
+ end
325
+ def from_source(source:)
326
+ CHEESES.values.select { |c| c.source == source }
327
+ end
328
+
329
+ field :favorite_edible, field: FavoriteFieldDefn
330
+ field :cow, function: GetSingleton.new(type: Cow, data: COWS[1])
331
+ field :search_dairy, DairyProduct, null: false do
326
332
  description "Find dairy products matching a description"
327
- type !DairyProductUnion
328
333
  # This is a list just for testing 😬
329
- argument :product, types[DairyProductInputType], default_value: [{"source" => "SHEEP"}]
330
- argument :expiresAfter, TimeType
331
- resolve ->(t, args, c) {
332
- source = args["product"][0][:source] # String or Sym is ok
333
- products = CHEESES.values + MILKS.values
334
- if !source.nil?
335
- products = products.select { |pr| pr.source == source }
336
- end
337
- products.first
338
- }
334
+ argument :product, [DairyProductInput, null: true], required: false, default_value: [{"source" => "SHEEP"}]
335
+ argument :expires_after, Time, required: false
339
336
  end
340
337
 
341
- field :allAnimal, !types[AnimalUnion] do
342
- resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
338
+ def search_dairy(product:, expires_after: nil)
339
+ source = product[0][:source]
340
+ products = CHEESES.values + MILKS.values
341
+ if !source.nil?
342
+ products = products.select { |pr| pr.source == source }
343
+ end
344
+ products.first
343
345
  end
344
346
 
345
- field :allAnimalAsCow, !types[AnimalAsCowUnion] do
346
- resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
347
+ field :all_animal, [Animal, null: true], null: false
348
+ def all_animal
349
+ COWS.values + GOATS.values
347
350
  end
348
351
 
349
- field :allDairy, types[DairyProductUnion] do
350
- argument :executionErrorAtIndex, types.Int
351
- resolve ->(obj, args, ctx) {
352
- result = CHEESES.values + MILKS.values
353
- result[args.executionErrorAtIndex] = GraphQL::ExecutionError.new("missing dairy") if args.executionErrorAtIndex
354
- result
355
- }
356
- end
352
+ field :all_animal_as_cow, [AnimalAsCow, null: true], null: false, method: :all_animal
357
353
 
358
- field :allEdible, types[EdibleInterface] do
359
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
354
+ field :all_dairy, [DairyProduct, null: true], null: true do
355
+ argument :execution_error_at_index, Integer, required: false
356
+ end
357
+ def all_dairy(execution_error_at_index: nil)
358
+ result = CHEESES.values + MILKS.values
359
+ if execution_error_at_index
360
+ result[execution_error_at_index] = GraphQL::ExecutionError.new("missing dairy")
361
+ end
362
+ result
360
363
  end
361
364
 
362
- field :allEdibleAsMilk, types[EdibleAsMilkInterface] do
363
- resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
365
+ field :all_edible, [Edible, null: true], null: true
366
+ def all_edible
367
+ CHEESES.values + MILKS.values
364
368
  end
365
369
 
366
- field :error do
367
- description "Raise an error"
368
- type GraphQL::STRING_TYPE
369
- resolve ->(t, a, c) { raise("This error was raised on purpose") }
370
+ field :all_edible_as_milk, [EdibleAsMilk, null: true], null: true, method: :all_edible
371
+
372
+ field :error, String, null: true, description: "Raise an error"
373
+ def error
374
+ raise("This error was raised on purpose")
370
375
  end
371
376
 
372
- field :executionError do
373
- type GraphQL::STRING_TYPE
374
- resolve ->(t, a, c) { raise(GraphQL::ExecutionError, "There was an execution error") }
377
+ field :execution_error, String, null: true
378
+ def execution_error
379
+ raise(GraphQL::ExecutionError, "There was an execution error")
375
380
  end
376
381
 
377
- field :valueWithExecutionError do
378
- type !GraphQL::INT_TYPE
379
- resolve ->(t, a, c) {
380
- c.add_error(GraphQL::ExecutionError.new("Could not fetch latest value"))
381
- return 0
382
- }
382
+ field :value_with_execution_error, Integer, null: false, extras: [:execution_errors]
383
+ def value_with_execution_error(execution_errors:)
384
+ execution_errors.add("Could not fetch latest value")
385
+ 0
383
386
  end
384
387
 
385
- field :multipleErrorsOnNonNullableField do
386
- type !GraphQL::STRING_TYPE
387
- resolve ->(t, a, c) {
388
- [GraphQL::ExecutionError.new("This is an error message for some error."),
389
- GraphQL::ExecutionError.new("This is another error message for a different error.")]
390
- }
388
+ field :multiple_errors_on_non_nullable_field, String, null: false
389
+ def multiple_errors_on_non_nullable_field
390
+ [
391
+ GraphQL::ExecutionError.new("This is an error message for some error."),
392
+ GraphQL::ExecutionError.new("This is another error message for a different error.")
393
+ ]
391
394
  end
392
395
 
393
- field :executionErrorWithOptions do
394
- type GraphQL::INT_TYPE
395
- resolve ->(t, a, c) {
396
- GraphQL::ExecutionError.new("Permission Denied!", options: { "code" => "permission_denied" })
397
- }
396
+ field :execution_error_with_options, Integer, null: true
397
+ def execution_error_with_options
398
+ GraphQL::ExecutionError.new("Permission Denied!", options: { "code" => "permission_denied" })
398
399
  end
399
400
 
400
- field :executionErrorWithExtensions do
401
- type GraphQL::INT_TYPE
402
- resolve ->(t, a, c) {
403
- GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
404
- }
401
+ field :execution_error_with_extensions, Integer, null: true
402
+ def execution_error_with_extensions
403
+ GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
405
404
  end
406
405
 
407
406
  # To test possibly-null fields
408
- field :maybeNull, MaybeNullType do
409
- resolve ->(t, a, c) { OpenStruct.new(cheese: nil) }
407
+ field :maybe_null, MaybeNull, null: true
408
+ def maybe_null
409
+ OpenStruct.new(cheese: nil)
410
410
  end
411
411
 
412
- field :tracingScalar, TracingScalarType do
413
- resolve ->(o, a, c) do
414
- OpenStruct.new(
415
- traceNil: 2,
416
- traceFalse: 3,
417
- tracetrue: 5,
418
- )
419
- end
412
+ field :tracing_scalar, TracingScalar, null: true
413
+ def tracing_scalar
414
+ OpenStruct.new(
415
+ trace_nil: 2,
416
+ trace_false: 3,
417
+ trace_true: 5,
418
+ )
420
419
  end
421
420
 
422
- field :deepNonNull, !DeepNonNullType do
423
- resolve ->(o, a, c) { :deepNonNull }
424
- end
421
+ field :deep_non_null, DeepNonNull, null: false
422
+ def deep_non_null; :deep_non_null; end
425
423
  end
426
424
 
427
425
  GLOBAL_VALUES = []
428
426
 
429
- ReplaceValuesInputType = GraphQL::InputObjectType.define do
430
- name "ReplaceValuesInput"
431
- input_field :values, !types[!types.Int]
432
- end
433
-
434
- PushValueField = GraphQL::Field.define do
435
- name :pushValue
436
- type !types[!types.Int]
437
- description("Push a value onto a global array :D")
438
- argument :value, !types.Int, as: :val
439
- resolve ->(o, args, ctx) {
440
- GLOBAL_VALUES << args.val
441
- GLOBAL_VALUES
442
- }
427
+ class ReplaceValuesInput < BaseInputObject
428
+ argument :values, [Integer], required: true
443
429
  end
444
430
 
445
- class DairyAppMutationType < GraphQL::Schema::Object
431
+ class DairyAppMutation < BaseObject
446
432
  graphql_name "Mutation"
447
433
  description "The root for mutations in this schema"
448
- # Test the `field:` compatibility option
449
- field :pushValue, field: PushValueField
434
+ field :push_value, [Integer], null: false, description: "Push a value onto a global array :D" do
435
+ argument :value, Integer, required: true, as: :val
436
+ end
437
+ def push_value(val:)
438
+ GLOBAL_VALUES << val
439
+ GLOBAL_VALUES
440
+ end
450
441
 
451
442
  field :replaceValues, [Integer], "Replace the global array with new values", null: false do
452
- argument :input, ReplaceValuesInputType, required: true
443
+ argument :input, ReplaceValuesInput, required: true
453
444
  end
454
445
 
455
446
  def replace_values(input:)
@@ -459,19 +450,18 @@ module Dummy
459
450
  end
460
451
  end
461
452
 
462
- SubscriptionType = GraphQL::ObjectType.define do
463
- name "Subscription"
464
- field :test, types.String do
465
- resolve ->(o, a, c) { "Test" }
466
- end
453
+ class Subscription < BaseObject
454
+ field :test, String, null: true
455
+ def test; "Test"; end
467
456
  end
468
457
 
469
458
  class Schema < GraphQL::Schema
470
- query DairyAppQueryType
471
- mutation DairyAppMutationType
472
- subscription SubscriptionType
459
+ query DairyAppQuery
460
+ mutation DairyAppMutation
461
+ subscription Subscription
473
462
  max_depth 5
474
- orphan_types [HoneyType, BeverageUnion]
463
+ # TODO why is `.graphql_definition` required here?
464
+ orphan_types Honey, Beverage.graphql_definition
475
465
 
476
466
  rescue_from(NoSuchDairyError) { |err| err.message }
477
467