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.
- checksums.yaml +4 -4
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
- data/lib/graphql/enum_type.rb +4 -0
- data/lib/graphql/execution/execute.rb +2 -2
- data/lib/graphql/field.rb +1 -7
- data/lib/graphql/schema.rb +25 -3
- data/lib/graphql/schema/argument.rb +3 -4
- data/lib/graphql/schema/field.rb +19 -4
- data/lib/graphql/types/iso_8601_date_time.rb +15 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
- data/spec/graphql/base_type_spec.rb +3 -3
- data/spec/graphql/enum_type_spec.rb +1 -1
- data/spec/graphql/execution/lazy_spec.rb +18 -1
- data/spec/graphql/execution/typecast_spec.rb +20 -20
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/input_object_type_spec.rb +25 -0
- data/spec/graphql/interface_type_spec.rb +4 -4
- data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
- data/spec/graphql/object_type_spec.rb +32 -27
- data/spec/graphql/query/executor_spec.rb +2 -2
- data/spec/graphql/schema/argument_spec.rb +27 -0
- data/spec/graphql/schema/field_spec.rb +16 -0
- data/spec/graphql/schema/interface_spec.rb +2 -2
- data/spec/graphql/schema/relay_classic_mutation_spec.rb +36 -0
- data/spec/graphql/schema/traversal_spec.rb +10 -10
- data/spec/graphql/schema/type_expression_spec.rb +2 -2
- data/spec/graphql/schema/validation_spec.rb +1 -1
- data/spec/graphql/types/iso_8601_date_time_spec.rb +25 -0
- data/spec/graphql/union_type_spec.rb +2 -2
- data/spec/integration/rails/graphql/input_object_type_spec.rb +4 -4
- data/spec/integration/rails/graphql/query/variables_spec.rb +7 -7
- data/spec/integration/rails/graphql/schema_spec.rb +6 -5
- data/spec/integration/tmp/app/graphql/types/page_type.rb +4 -0
- data/spec/support/dummy/data.rb +20 -17
- data/spec/support/dummy/schema.rb +271 -281
- data/spec/support/jazz.rb +45 -0
- data/spec/support/lazy_helpers.rb +13 -4
- 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
|
-
"
|
73
|
-
|
74
|
-
|
72
|
+
origin_dairy: "Sugar Hollow Dairy",
|
73
|
+
organic: false,
|
74
|
+
order_by: { direction: "ASC" },
|
75
75
|
}
|
76
76
|
|
77
77
|
expected_input_1 = {
|
78
|
-
|
79
|
-
|
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
|
-
|
86
|
-
|
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::
|
51
|
-
Dummy::
|
52
|
-
Dummy::
|
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
|
-
|
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::
|
454
|
+
field_2 = schema.get_field(Dummy::Cheese.graphql_definition, "id")
|
454
455
|
assert_equal field, field_2
|
455
456
|
end
|
456
457
|
end
|
data/spec/support/dummy/data.rb
CHANGED
@@ -1,27 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'ostruct'
|
3
3
|
module Dummy
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
11
|
-
|
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
|
-
|
17
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
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
|
-
|
54
|
-
|
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
|
-
|
80
|
+
implements Edible
|
81
|
+
implements EdibleAsMilk
|
82
|
+
implements AnimalProduct
|
83
|
+
implements LocalProduct
|
58
84
|
|
59
|
-
|
60
|
-
field :
|
61
|
-
field :
|
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,
|
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
|
-
|
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,
|
72
|
-
argument :nullableSource,
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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 :
|
85
|
-
argument :source,
|
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 :
|
90
|
-
argument :source,
|
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 :
|
96
|
-
|
97
|
-
|
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
|
-
|
103
|
-
name "Milk"
|
128
|
+
class Milk < BaseObject
|
104
129
|
description "Dairy beverage"
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
121
|
-
|
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
|
-
|
126
|
-
|
127
|
-
field :sweetness,
|
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
|
-
|
132
|
-
name "Honey"
|
164
|
+
class Honey < BaseObject
|
133
165
|
description "Sweet, dehydrated bee barf"
|
134
|
-
field :
|
135
|
-
|
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
|
-
|
139
|
-
name "Dairy"
|
172
|
+
class Dairy < BaseObject
|
140
173
|
description "A farm where milk is harvested and cheese is produced"
|
141
|
-
field :id,
|
142
|
-
field :cheese,
|
143
|
-
field :milks,
|
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
|
-
|
147
|
-
name "MaybeNull"
|
179
|
+
class MaybeNull < BaseObject
|
148
180
|
description "An object whose fields return nil"
|
149
|
-
field :cheese,
|
181
|
+
field :cheese, Cheese, null: true
|
150
182
|
end
|
151
183
|
|
152
|
-
|
153
|
-
name "TracingScalar"
|
184
|
+
class TracingScalar < BaseObject
|
154
185
|
description "An object which has traced scalars"
|
155
186
|
|
156
|
-
field :
|
157
|
-
field :
|
158
|
-
field :
|
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
|
-
|
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
|
195
|
+
possible_types "Dummy::Milk", Cheese
|
166
196
|
end
|
167
197
|
|
168
|
-
|
169
|
-
name "Cow"
|
198
|
+
class Cow < BaseObject
|
170
199
|
description "A bovine animal that produces milk"
|
171
|
-
field :id,
|
172
|
-
field :name,
|
173
|
-
field :last_produced_dairy,
|
200
|
+
field :id, ID, null: false
|
201
|
+
field :name, String, null: true
|
202
|
+
field :last_produced_dairy, DairyProduct, null: true
|
174
203
|
|
175
|
-
field :
|
176
|
-
|
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 :
|
181
|
-
|
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
|
-
|
187
|
-
name "Goat"
|
211
|
+
class Goat < BaseObject
|
188
212
|
description "An caprinae animal that produces milk"
|
189
|
-
field :id,
|
190
|
-
field :name,
|
191
|
-
field :last_produced_dairy,
|
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
|
-
|
195
|
-
name "Animal"
|
218
|
+
class Animal < BaseUnion
|
196
219
|
description "Species of living things"
|
197
|
-
possible_types
|
220
|
+
possible_types Cow, Goat
|
198
221
|
end
|
199
222
|
|
200
|
-
|
201
|
-
name "AnimalAsCow"
|
223
|
+
class AnimalAsCow < BaseUnion
|
202
224
|
description "All animals go mooooo!"
|
203
|
-
possible_types
|
204
|
-
resolve_type
|
205
|
-
|
206
|
-
|
225
|
+
possible_types Cow
|
226
|
+
def self.resolve_type(obj, ctx)
|
227
|
+
Cow
|
228
|
+
end
|
207
229
|
end
|
208
230
|
|
209
|
-
|
210
|
-
|
231
|
+
class ResourceOrder < BaseInputObject
|
232
|
+
graphql_name "ResourceOrderType"
|
211
233
|
description "Properties used to determine ordering"
|
212
234
|
|
213
|
-
argument :direction,
|
214
|
-
|
215
|
-
end
|
216
|
-
}
|
235
|
+
argument :direction, String, required: true, description: "ASC or DESC"
|
236
|
+
end
|
217
237
|
|
218
|
-
|
219
|
-
name "DairyProductInput"
|
238
|
+
class DairyProductInput < BaseInputObject
|
220
239
|
description "Properties for finding a dairy product"
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
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
|
-
|
229
|
-
|
230
|
-
|
247
|
+
class DeepNonNull < BaseObject
|
248
|
+
field :non_null_int, Integer, null: false do
|
249
|
+
argument :returning, Integer, required: false
|
231
250
|
end
|
232
|
-
|
233
|
-
|
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 :
|
247
|
-
|
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
|
-
|
252
|
-
name "Time"
|
259
|
+
class Time < BaseScalar
|
253
260
|
description "Time since epoch in seconds"
|
254
261
|
|
255
|
-
coerce_input
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
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
|
307
|
+
type Edible
|
310
308
|
resolve ->(t, a, c) { MILKS[1] }
|
311
309
|
end
|
312
310
|
|
313
|
-
|
314
|
-
|
311
|
+
class DairyAppQuery < BaseObject
|
312
|
+
graphql_name "Query"
|
315
313
|
description "Query root of the system"
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
field :
|
322
|
-
field :
|
323
|
-
field :
|
324
|
-
field :
|
325
|
-
|
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,
|
330
|
-
argument :
|
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
|
-
|
342
|
-
|
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 :
|
346
|
-
|
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 :
|
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 :
|
359
|
-
|
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 :
|
363
|
-
|
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 :
|
367
|
-
|
368
|
-
|
369
|
-
|
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 :
|
373
|
-
|
374
|
-
|
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 :
|
378
|
-
|
379
|
-
|
380
|
-
|
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 :
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
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 :
|
394
|
-
|
395
|
-
|
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 :
|
401
|
-
|
402
|
-
|
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 :
|
409
|
-
|
407
|
+
field :maybe_null, MaybeNull, null: true
|
408
|
+
def maybe_null
|
409
|
+
OpenStruct.new(cheese: nil)
|
410
410
|
end
|
411
411
|
|
412
|
-
field :
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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 :
|
423
|
-
|
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
|
-
|
430
|
-
|
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
|
431
|
+
class DairyAppMutation < BaseObject
|
446
432
|
graphql_name "Mutation"
|
447
433
|
description "The root for mutations in this schema"
|
448
|
-
|
449
|
-
|
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,
|
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
|
-
|
463
|
-
|
464
|
-
|
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
|
471
|
-
mutation
|
472
|
-
subscription
|
459
|
+
query DairyAppQuery
|
460
|
+
mutation DairyAppMutation
|
461
|
+
subscription Subscription
|
473
462
|
max_depth 5
|
474
|
-
|
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
|
|