graphql 0.18.2 → 0.18.3
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/execution/typecast.rb +17 -13
- data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -4
- data/lib/graphql/relay/base_connection.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/execution/typecast_spec.rb +51 -0
- data/spec/graphql/interface_type_spec.rb +49 -0
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/introspection/type_type_spec.rb +2 -1
- data/spec/graphql/object_type_spec.rb +1 -1
- data/spec/graphql/relay/mutation_spec.rb +10 -15
- data/spec/graphql/schema/reduce_types_spec.rb +1 -0
- data/spec/graphql/union_type_spec.rb +28 -1
- data/spec/support/dairy_app.rb +24 -3
- data/spec/support/star_wars_schema.rb +5 -2
- metadata +4 -3
- data/lib/graphql/schema/middleware.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e542df508ad2037e784439e944e47df3711dc7b7
|
4
|
+
data.tar.gz: 4623d2ac01705a25245a114aec72a71117172c77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2b6f96474c81050d2f626e62ab96c784459662f3676c6b4a28ea8d36def062e5de6b1cefa097705f6c93be2b026dfb6cea1184b9e736d9fd0618024442b8d83
|
7
|
+
data.tar.gz: de4ea313f70e012ad7152a71dbfe459d62fa4988b43f6947791d00c1fa45eb377962331e8db7f504a96ca331d27d962933874af4afae405a4794be2c82c2d714
|
@@ -1,28 +1,32 @@
|
|
1
1
|
module GraphQL
|
2
2
|
module Execution
|
3
|
-
# GraphQL object `{value,
|
4
|
-
# - `
|
5
|
-
# - `
|
6
|
-
# - `
|
7
|
-
# - `
|
8
|
-
# - `
|
3
|
+
# GraphQL object `{value, current_type}` can be cast to `potential_type` when:
|
4
|
+
# - `current_type == potential_type`
|
5
|
+
# - `current_type` is a union and it contains `potential_type`
|
6
|
+
# - `potential_type` is a union and it contains `current_type`
|
7
|
+
# - `current_type` is an interface and `potential_type` implements it
|
8
|
+
# - `potential_type` is an interface and `current_type` implements it
|
9
9
|
module Typecast
|
10
10
|
# While `value` is exposed by GraphQL as an instance of `current_type`,
|
11
11
|
# should it _also_ be treated as an instance of `potential_type`?
|
12
12
|
#
|
13
13
|
# This is used for checking whether fragments apply to an object.
|
14
14
|
#
|
15
|
-
# @
|
16
|
-
|
17
|
-
|
15
|
+
# @param [Object] the value which GraphQL is currently exposing
|
16
|
+
# @param [GraphQL::BaseType] the type which GraphQL is using for `value` now
|
17
|
+
# @param [GraphQL::BaseType] can `value` be exposed using this type?
|
18
|
+
# @param [GraphQL::Query::Context] the context for the current query
|
19
|
+
# @return [Boolean] true if `value` be evaluated as a `potential_type`
|
20
|
+
def self.compatible?(current_type, potential_type, query_ctx)
|
21
|
+
if current_type == potential_type
|
18
22
|
true
|
19
23
|
elsif current_type.kind.union?
|
20
|
-
current_type.
|
24
|
+
current_type.possible_types.include?(potential_type)
|
21
25
|
elsif potential_type.kind.union?
|
22
26
|
potential_type.include?(current_type)
|
23
|
-
elsif current_type.kind.interface?
|
24
|
-
|
25
|
-
elsif potential_type.kind.interface?
|
27
|
+
elsif current_type.kind.interface? && potential_type.kind.object?
|
28
|
+
potential_type.interfaces.include?(current_type)
|
29
|
+
elsif potential_type.kind.interface? && current_type.kind.object?
|
26
30
|
current_type.interfaces.include?(potential_type)
|
27
31
|
else
|
28
32
|
false
|
@@ -13,7 +13,7 @@ module GraphQL
|
|
13
13
|
|
14
14
|
def result
|
15
15
|
irep_node.children.each_with_object({}) do |(name, irep_node), memo|
|
16
|
-
if GraphQL::Execution::DirectiveChecks.include?(irep_node, execution_context.query) && applies_to_type?(irep_node, type
|
16
|
+
if GraphQL::Execution::DirectiveChecks.include?(irep_node, execution_context.query) && applies_to_type?(irep_node, type)
|
17
17
|
field_result = execution_context.strategy.field_resolution.new(
|
18
18
|
irep_node,
|
19
19
|
type,
|
@@ -27,9 +27,9 @@ module GraphQL
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def applies_to_type?(irep_node,
|
31
|
-
irep_node.definitions.any? { |
|
32
|
-
GraphQL::Execution::Typecast.compatible?(
|
30
|
+
def applies_to_type?(irep_node, current_type)
|
31
|
+
irep_node.definitions.any? { |potential_type, field_defn|
|
32
|
+
GraphQL::Execution::Typecast.compatible?(current_type, potential_type, execution_context.query.context)
|
33
33
|
}
|
34
34
|
end
|
35
35
|
end
|
@@ -61,7 +61,7 @@ module GraphQL
|
|
61
61
|
# @param field [Object] The underlying field
|
62
62
|
# @param max_page_size [Int] The maximum number of results to return
|
63
63
|
# @param parent [Object] The object which this collection belongs to
|
64
|
-
def initialize(nodes, arguments, field
|
64
|
+
def initialize(nodes, arguments, field: nil, max_page_size: nil, parent: nil)
|
65
65
|
@nodes = nodes
|
66
66
|
@arguments = arguments
|
67
67
|
@max_page_size = max_page_size
|
data/lib/graphql/version.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe GraphQL::Execution::Typecast do
|
4
|
+
let(:milk_value) { MILKS[1] }
|
5
|
+
let(:cheese_value) { CHEESES[1] }
|
6
|
+
|
7
|
+
let(:schema) { DummySchema }
|
8
|
+
let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: nil) }
|
9
|
+
|
10
|
+
def compatible?(*args)
|
11
|
+
GraphQL::Execution::Typecast.compatible?(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "resolves correctly when both types are the same" do
|
15
|
+
assert compatible?(MilkType, MilkType, context)
|
16
|
+
|
17
|
+
assert !compatible?(MilkType, CheeseType, context)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "resolves a union type to a matching member" do
|
21
|
+
assert compatible?(DairyProductUnion, MilkType, context)
|
22
|
+
assert compatible?(DairyProductUnion, CheeseType, context)
|
23
|
+
|
24
|
+
assert !compatible?(DairyProductUnion, GraphQL::INT_TYPE, context)
|
25
|
+
assert !compatible?(DairyProductUnion, HoneyType, context)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "resolves correcty when potential type is UnionType and current type is a member of that union" do
|
29
|
+
assert compatible?(MilkType, DairyProductUnion, context)
|
30
|
+
assert compatible?(CheeseType, DairyProductUnion, context)
|
31
|
+
|
32
|
+
assert !compatible?(QueryType, DairyProductUnion, context)
|
33
|
+
assert !compatible?(EdibleInterface, DairyProductUnion, context)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "resolves an object type to one of its interfaces" do
|
37
|
+
assert compatible?(CheeseType, EdibleInterface, context)
|
38
|
+
assert compatible?(MilkType, EdibleInterface, context)
|
39
|
+
|
40
|
+
assert !compatible?(QueryType, EdibleInterface, context)
|
41
|
+
assert !compatible?(LocalProductInterface, EdibleInterface, context)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "resolves an interface to a matching member" do
|
45
|
+
assert compatible?(EdibleInterface, CheeseType, context)
|
46
|
+
assert compatible?(EdibleInterface, MilkType, context)
|
47
|
+
|
48
|
+
assert !compatible?(EdibleInterface, GraphQL::STRING_TYPE, context)
|
49
|
+
assert !compatible?(EdibleInterface, DairyProductInputType, context)
|
50
|
+
end
|
51
|
+
end
|
@@ -53,4 +53,53 @@ describe GraphQL::InterfaceType do
|
|
53
53
|
assert_equal(interface.resolve_type(123, nil), :custom_resolve)
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
describe "fragments" do
|
58
|
+
let(:query_string) {%|
|
59
|
+
{
|
60
|
+
favoriteEdible {
|
61
|
+
fatContent
|
62
|
+
... on LocalProduct {
|
63
|
+
origin
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|}
|
68
|
+
let(:result) { DummySchema.execute(query_string) }
|
69
|
+
|
70
|
+
it "can apply interface fragments to an interface" do
|
71
|
+
expected_result = { "data" => {
|
72
|
+
"favoriteEdible" => {
|
73
|
+
"fatContent" => 0.04,
|
74
|
+
"origin" => "Antiquity",
|
75
|
+
}
|
76
|
+
} }
|
77
|
+
|
78
|
+
assert_equal(expected_result, result)
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "filtering members by type" do
|
82
|
+
let(:query_string) {%|
|
83
|
+
{
|
84
|
+
allEdible {
|
85
|
+
__typename
|
86
|
+
... on LocalProduct {
|
87
|
+
origin
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|}
|
92
|
+
|
93
|
+
it "only applies fields to the right object" do
|
94
|
+
expected_data = [
|
95
|
+
{"__typename"=>"Cheese", "origin"=>"France"},
|
96
|
+
{"__typename"=>"Cheese", "origin"=>"Netherlands"},
|
97
|
+
{"__typename"=>"Cheese", "origin"=>"Spain"},
|
98
|
+
{"__typename"=>"Milk", "origin"=>"Antiquity"},
|
99
|
+
]
|
100
|
+
|
101
|
+
assert_equal expected_data, result["data"]["allEdible"]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
56
105
|
end
|
@@ -36,7 +36,8 @@ describe GraphQL::Introspection::TypeType do
|
|
36
36
|
"milkType"=>{
|
37
37
|
"interfaces"=>[
|
38
38
|
{"name"=>"Edible"},
|
39
|
-
{"name"=>"AnimalProduct"}
|
39
|
+
{"name"=>"AnimalProduct"},
|
40
|
+
{"name"=>"LocalProduct"},
|
40
41
|
],
|
41
42
|
"fields"=>[
|
42
43
|
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"Float"}}},
|
@@ -15,7 +15,7 @@ describe GraphQL::ObjectType do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "may have interfaces" do
|
18
|
-
assert_equal([EdibleInterface, AnimalProductInterface], type.interfaces)
|
18
|
+
assert_equal([EdibleInterface, AnimalProductInterface, LocalProductInterface], type.interfaces)
|
19
19
|
end
|
20
20
|
|
21
21
|
describe '#get_field ' do
|
@@ -5,7 +5,9 @@ describe GraphQL::Relay::Mutation do
|
|
5
5
|
mutation addBagel($clientMutationId: String) {
|
6
6
|
introduceShip(input: {shipName: "Bagel", factionId: "1", clientMutationId: $clientMutationId}) {
|
7
7
|
clientMutationId
|
8
|
-
|
8
|
+
shipEdge {
|
9
|
+
node { name, id }
|
10
|
+
}
|
9
11
|
faction { name }
|
10
12
|
}
|
11
13
|
}
|
@@ -28,9 +30,11 @@ describe GraphQL::Relay::Mutation do
|
|
28
30
|
expected = {"data" => {
|
29
31
|
"introduceShip" => {
|
30
32
|
"clientMutationId" => "1234",
|
31
|
-
"
|
32
|
-
"
|
33
|
-
|
33
|
+
"shipEdge" => {
|
34
|
+
"node" => {
|
35
|
+
"name" => "Bagel",
|
36
|
+
"id" => NodeIdentification.to_global_id("Ship", "9"),
|
37
|
+
},
|
34
38
|
},
|
35
39
|
"faction" => {"name" => STAR_WARS_DATA["Faction"]["1"].name }
|
36
40
|
}
|
@@ -40,16 +44,7 @@ describe GraphQL::Relay::Mutation do
|
|
40
44
|
|
41
45
|
it "doesn't require a clientMutationId to perform mutations" do
|
42
46
|
result = query(query_string)
|
43
|
-
|
44
|
-
|
45
|
-
"clientMutationId" => nil,
|
46
|
-
"ship" => {
|
47
|
-
"name" => "Bagel",
|
48
|
-
"id" => NodeIdentification.to_global_id("Ship", "9"),
|
49
|
-
},
|
50
|
-
"faction" => {"name" => STAR_WARS_DATA["Faction"]["1"].name }
|
51
|
-
}
|
52
|
-
}}
|
53
|
-
assert_equal(expected, result)
|
47
|
+
new_ship_name = result["data"]["introduceShip"]["shipEdge"]["node"]["name"]
|
48
|
+
assert_equal("Bagel", new_ship_name)
|
54
49
|
end
|
55
50
|
end
|
@@ -14,6 +14,7 @@ describe GraphQL::Schema::ReduceTypes do
|
|
14
14
|
"Int" => GraphQL::INT_TYPE,
|
15
15
|
"Edible" => EdibleInterface,
|
16
16
|
"AnimalProduct" => AnimalProductInterface,
|
17
|
+
"LocalProduct" => LocalProductInterface,
|
17
18
|
}
|
18
19
|
result = reduce_types([CheeseType])
|
19
20
|
assert_equal(expected.keys, result.keys)
|
@@ -12,11 +12,11 @@ describe GraphQL::UnionType do
|
|
12
12
|
possible_types(types)
|
13
13
|
}
|
14
14
|
}
|
15
|
+
|
15
16
|
it "has a name" do
|
16
17
|
assert_equal("MyUnion", union.name)
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
20
|
it "infers type from an object" do
|
21
21
|
assert_equal(CheeseType, DairyProductUnion.resolve_type(CHEESES[1], OpenStruct.new(schema: DummySchema)))
|
22
22
|
end
|
@@ -29,6 +29,33 @@ describe GraphQL::UnionType do
|
|
29
29
|
assert_equal(false, union.include?(type_3))
|
30
30
|
end
|
31
31
|
|
32
|
+
describe "typecasting from union to union" do
|
33
|
+
let(:result) { DummySchema.execute(query_string) }
|
34
|
+
let(:query_string) {%|
|
35
|
+
{
|
36
|
+
allDairy {
|
37
|
+
dairyName: __typename
|
38
|
+
... on Beverage {
|
39
|
+
bevName: __typename
|
40
|
+
... on Milk {
|
41
|
+
flavors
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|}
|
47
|
+
|
48
|
+
it "casts if the object belongs to both unions" do
|
49
|
+
expected_result = [
|
50
|
+
{"dairyName"=>"Cheese"},
|
51
|
+
{"dairyName"=>"Cheese"},
|
52
|
+
{"dairyName"=>"Cheese"},
|
53
|
+
{"dairyName"=>"Milk", "bevName"=>"Milk", "flavors"=>["Natural", "Chocolate", "Strawberry"]},
|
54
|
+
]
|
55
|
+
assert_equal expected_result, result["data"]["allDairy"]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
32
59
|
describe "list of union type" do
|
33
60
|
describe "fragment spreads" do
|
34
61
|
let(:result) { DummySchema.execute(query_string) }
|
data/spec/support/dairy_app.rb
CHANGED
@@ -5,6 +5,17 @@ class NoSuchDairyError < StandardError; end
|
|
5
5
|
GraphQL::Field.accepts_definitions(joins: GraphQL::Define.assign_metadata_key(:joins))
|
6
6
|
GraphQL::BaseType.accepts_definitions(class_names: GraphQL::Define.assign_metadata_key(:class_names))
|
7
7
|
|
8
|
+
LocalProductInterface = GraphQL::InterfaceType.define do
|
9
|
+
name "LocalProduct"
|
10
|
+
description "Something that comes from somewhere"
|
11
|
+
field :origin, !types.String, "Place the thing comes from"
|
12
|
+
# This is a "bug" in the dummy app:
|
13
|
+
# it should actually check the incoming object to determine the type.
|
14
|
+
# But this is here so we can check _where_ misbehaving resolve_type
|
15
|
+
# functions wreak their havoc.
|
16
|
+
resolve_type -> (o, c) { MilkType }
|
17
|
+
end
|
18
|
+
|
8
19
|
EdibleInterface = GraphQL::InterfaceType.define do
|
9
20
|
name "Edible"
|
10
21
|
description "Something you can eat, yum"
|
@@ -18,6 +29,12 @@ AnimalProductInterface = GraphQL::InterfaceType.define do
|
|
18
29
|
field :source, !types.String, "Animal which produced this product"
|
19
30
|
end
|
20
31
|
|
32
|
+
BeverageUnion = GraphQL::UnionType.define do
|
33
|
+
name "Beverage"
|
34
|
+
description "Something you can drink"
|
35
|
+
possible_types [MilkType]
|
36
|
+
end
|
37
|
+
|
21
38
|
DairyAnimalEnum = GraphQL::EnumType.define do
|
22
39
|
name "DairyAnimal"
|
23
40
|
description "An animal which can yield milk"
|
@@ -31,7 +48,7 @@ CheeseType = GraphQL::ObjectType.define do
|
|
31
48
|
name "Cheese"
|
32
49
|
class_names ["Cheese"]
|
33
50
|
description "Cultured dairy product"
|
34
|
-
interfaces [EdibleInterface, AnimalProductInterface]
|
51
|
+
interfaces [EdibleInterface, AnimalProductInterface, LocalProductInterface]
|
35
52
|
|
36
53
|
# Can have (name, type, desc)
|
37
54
|
field :id, !types.Int, "Unique identifier"
|
@@ -78,7 +95,7 @@ end
|
|
78
95
|
MilkType = GraphQL::ObjectType.define do
|
79
96
|
name "Milk"
|
80
97
|
description "Dairy beverage"
|
81
|
-
interfaces [EdibleInterface, AnimalProductInterface]
|
98
|
+
interfaces [EdibleInterface, AnimalProductInterface, LocalProductInterface]
|
82
99
|
field :id, !types.ID
|
83
100
|
field :source, DairyAnimalEnum, "Animal which produced this milk", hash_key: :source
|
84
101
|
field :origin, !types.String, "Place the milk comes from"
|
@@ -254,6 +271,10 @@ DairyAppQueryType = GraphQL::ObjectType.define do
|
|
254
271
|
resolve -> (obj, args, ctx) { CHEESES.values + MILKS.values }
|
255
272
|
end
|
256
273
|
|
274
|
+
field :allEdible, types[EdibleInterface] do
|
275
|
+
resolve -> (obj, args, ctx) { CHEESES.values + MILKS.values }
|
276
|
+
end
|
277
|
+
|
257
278
|
field :error do
|
258
279
|
description "Raise an error"
|
259
280
|
type GraphQL::STRING_TYPE
|
@@ -317,6 +338,6 @@ DummySchema = GraphQL::Schema.new(
|
|
317
338
|
mutation: DairyAppMutationType,
|
318
339
|
subscription: SubscriptionType,
|
319
340
|
max_depth: 5,
|
320
|
-
types: [HoneyType],
|
341
|
+
types: [HoneyType, BeverageUnion],
|
321
342
|
)
|
322
343
|
DummySchema.rescue_from(NoSuchDairyError) { |err| err.message }
|
@@ -177,7 +177,7 @@ IntroduceShipMutation = GraphQL::Relay::Mutation.define do
|
|
177
177
|
input_field :factionId, !types.ID
|
178
178
|
|
179
179
|
# Result may have access to these fields:
|
180
|
-
return_field :
|
180
|
+
return_field :shipEdge, Ship.edge_type
|
181
181
|
return_field :faction, Faction
|
182
182
|
|
183
183
|
# Here's the mutation operation:
|
@@ -185,7 +185,10 @@ IntroduceShipMutation = GraphQL::Relay::Mutation.define do
|
|
185
185
|
faction_id = inputs["factionId"]
|
186
186
|
ship = STAR_WARS_DATA.create_ship(inputs["shipName"], faction_id)
|
187
187
|
faction = STAR_WARS_DATA["Faction"][faction_id]
|
188
|
-
|
188
|
+
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(faction.ships)
|
189
|
+
ships_connection = connection_class.new(faction.ships, inputs)
|
190
|
+
ship_edge = GraphQL::Relay::Edge.new(ship, ships_connection)
|
191
|
+
{ shipEdge: ship_edge, faction: faction }
|
189
192
|
}
|
190
193
|
end
|
191
194
|
|
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.
|
4
|
+
version: 0.18.3
|
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-
|
11
|
+
date: 2016-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: codeclimate-test-reporter
|
@@ -346,7 +346,6 @@ files:
|
|
346
346
|
- lib/graphql/schema.rb
|
347
347
|
- lib/graphql/schema/catchall_middleware.rb
|
348
348
|
- lib/graphql/schema/invalid_type_error.rb
|
349
|
-
- lib/graphql/schema/middleware.rb
|
350
349
|
- lib/graphql/schema/middleware_chain.rb
|
351
350
|
- lib/graphql/schema/possible_types.rb
|
352
351
|
- lib/graphql/schema/printer.rb
|
@@ -397,6 +396,7 @@ files:
|
|
397
396
|
- spec/graphql/define/instance_definable_spec.rb
|
398
397
|
- spec/graphql/directive_spec.rb
|
399
398
|
- spec/graphql/enum_type_spec.rb
|
399
|
+
- spec/graphql/execution/typecast_spec.rb
|
400
400
|
- spec/graphql/execution_error_spec.rb
|
401
401
|
- spec/graphql/field_spec.rb
|
402
402
|
- spec/graphql/float_type_spec.rb
|
@@ -502,6 +502,7 @@ test_files:
|
|
502
502
|
- spec/graphql/define/instance_definable_spec.rb
|
503
503
|
- spec/graphql/directive_spec.rb
|
504
504
|
- spec/graphql/enum_type_spec.rb
|
505
|
+
- spec/graphql/execution/typecast_spec.rb
|
505
506
|
- spec/graphql/execution_error_spec.rb
|
506
507
|
- spec/graphql/field_spec.rb
|
507
508
|
- spec/graphql/float_type_spec.rb
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module GraphQL
|
2
|
-
class Schema
|
3
|
-
# - query_initialize
|
4
|
-
# - query_finalize
|
5
|
-
# - field_resolve
|
6
|
-
#
|
7
|
-
# @example Closing a socket when the query is finished
|
8
|
-
# SocketClosingMiddleware = GraphQL::Schema::Middleware.define do
|
9
|
-
# finalize_query -> (memo, env) {
|
10
|
-
# query.context[:socket].close
|
11
|
-
# }
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# @example Timing a query
|
15
|
-
# QueryTimerMiddleware = GraphQL::Schema::Middleware.define do
|
16
|
-
# initialize_query -> (env) {
|
17
|
-
# env.merge!({
|
18
|
-
# query_start_time: Time.now,
|
19
|
-
# field_times: [],
|
20
|
-
# })
|
21
|
-
# }
|
22
|
-
#
|
23
|
-
# resolve_field -> (env) {
|
24
|
-
# field_time = {
|
25
|
-
# start_time: Time.now,
|
26
|
-
# own_elapsed: nil,
|
27
|
-
# child_elapsed: 0,
|
28
|
-
# }
|
29
|
-
#
|
30
|
-
# memo[:field_times] << field_time
|
31
|
-
# memo
|
32
|
-
# }
|
33
|
-
#
|
34
|
-
# after_field { |memo, env|
|
35
|
-
# field_time = memo[:field_times].pop
|
36
|
-
# total_elapsed = Time.now - field_time[:start_time]
|
37
|
-
# own_elapsed = total_elapsed - field_time[:child_elapsed]
|
38
|
-
#
|
39
|
-
# field_name = "#{env[:parent_type].name}.#{env[:field_definition].name}(#{env[:arguments].to_h.to_json})"
|
40
|
-
# Logger.info("[GraphQL Field] #{field_name} #{own_elapsed}")
|
41
|
-
#
|
42
|
-
# parent_field_time = memo[:field_times].last
|
43
|
-
# if parent_field_time
|
44
|
-
# parent_field_time[:child_elapsed] += total_elapsed
|
45
|
-
# end
|
46
|
-
# }
|
47
|
-
#
|
48
|
-
# after_query { |memo, env|
|
49
|
-
# elapsed = Time.now - memo[:query_start_time]
|
50
|
-
# Logger.info("[GraphQL Elapsed] #{elapsed}")
|
51
|
-
# }
|
52
|
-
# end
|
53
|
-
class Middleware
|
54
|
-
EVENTS = [:before_query, :after_query, :before_field, :after_field]
|
55
|
-
class << self
|
56
|
-
attr_reader :handlers
|
57
|
-
def handlers
|
58
|
-
@handlers ||= {}
|
59
|
-
end
|
60
|
-
|
61
|
-
def on(event_name, &handler)
|
62
|
-
if EVENTS.include?(event_name)
|
63
|
-
handlers[event_name] = handler
|
64
|
-
else
|
65
|
-
raise("Can't attach handler to #{event_name} (must be one of: #{EVENTS})")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def trigger(event_name, *args)
|
71
|
-
self.class.handlers[event_name].call(*args)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|