graphql-batch 0.3.10 → 0.4.0
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 +5 -5
- data/.travis.yml +4 -4
- data/Gemfile +4 -0
- data/README.md +38 -10
- data/graphql-batch.gemspec +2 -5
- data/lib/graphql/batch.rb +11 -8
- data/lib/graphql/batch/loader.rb +0 -3
- data/lib/graphql/batch/mutation_field_extension.rb +12 -0
- data/lib/graphql/batch/setup.rb +0 -9
- data/lib/graphql/batch/version.rb +1 -1
- metadata +6 -22
- data/lib/graphql/batch/execution_strategy.rb +0 -67
- data/lib/graphql/batch/mutation_execution_strategy.rb +0 -23
- data/lib/graphql/batch/promise.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c1f52d43c7f189fab24b5e00f8b34435e99c03ae23ba4c99dfaa7a94d67271ed
|
4
|
+
data.tar.gz: 0ceb7b68519b2e1bd0f94686376d26590cebb9697fd50e80272d0770a85c4784
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '091fe19e752f10751216374384346e2c4bb0d8fbe35e86248b3584396531ff2775b4732380da5109968b402320ca22e0cc2f1f772ca26f9d12b4b2bfc5a5a049'
|
7
|
+
data.tar.gz: 6890562c5b66004bf10b886ba6370cf7c544ab796f2e29ac279b49c93003079b1722c068155a168f5ee9f3194b34395a2d26ac2e8e3013cecd6e74db2286d8ad
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -25,6 +25,8 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
### Basic Usage
|
27
27
|
|
28
|
+
#### Schema Configuration
|
29
|
+
|
28
30
|
Require the library
|
29
31
|
|
30
32
|
```ruby
|
@@ -49,8 +51,9 @@ end
|
|
49
51
|
Use `GraphQL::Batch` as a plugin in your schema (for graphql >= `1.5.0`).
|
50
52
|
|
51
53
|
```ruby
|
52
|
-
MySchema
|
54
|
+
class MySchema < GraphQL::Schema
|
53
55
|
query MyQueryType
|
56
|
+
mutation MyMutationType
|
54
57
|
|
55
58
|
use GraphQL::Batch
|
56
59
|
end
|
@@ -66,16 +69,39 @@ MySchema = GraphQL::Schema.define do
|
|
66
69
|
end
|
67
70
|
```
|
68
71
|
|
69
|
-
|
72
|
+
##### With `1.9.0`'s `Interpreter` runtime
|
73
|
+
|
74
|
+
Add `GraphQL::Batch` _after_ the interpreter, so that `GraphQL::Batch` can detect the interpreter and attach the right integrations:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
use GraphQL::Execution::Interpreter
|
78
|
+
use GraphQL::Batch
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Field Usage
|
82
|
+
|
83
|
+
The loader class can be used from the resolver for a graphql field by calling `.for` with the grouping arguments to get a loader instance, then call `.load` on that instance with the key to load.
|
70
84
|
|
71
85
|
```ruby
|
72
|
-
|
86
|
+
field :product, Types::Product, null: true do
|
87
|
+
argument :id, ID, required: true
|
88
|
+
end
|
89
|
+
|
90
|
+
def product(id:)
|
91
|
+
RecordLoader.for(Product).load(id)
|
92
|
+
end
|
73
93
|
```
|
74
94
|
|
75
95
|
The loader also supports batch loading an array of records instead of just a single record, via `load_many`. For example:
|
76
96
|
|
77
97
|
```ruby
|
78
|
-
|
98
|
+
field :products, [Types::Product, null: true], null: false do
|
99
|
+
argument :ids, [ID], required: true
|
100
|
+
end
|
101
|
+
|
102
|
+
def product(ids:)
|
103
|
+
RecordLoader.for(Product).load_many(ids)
|
104
|
+
end
|
79
105
|
```
|
80
106
|
|
81
107
|
Although this library doesn't have a dependency on active record,
|
@@ -89,8 +115,8 @@ on records with the same id.
|
|
89
115
|
GraphQL::Batch::Loader#load returns a Promise using the [promise.rb gem](https://rubygems.org/gems/promise.rb) to provide a promise based API, so you can transform the query results using `.then`
|
90
116
|
|
91
117
|
```ruby
|
92
|
-
|
93
|
-
RecordLoader.for(Product).load(
|
118
|
+
def product_title(id:)
|
119
|
+
RecordLoader.for(Product).load(id).then do |product|
|
94
120
|
product.title
|
95
121
|
end
|
96
122
|
end
|
@@ -99,8 +125,8 @@ end
|
|
99
125
|
You may also need to do another query that depends on the first one to get the result, in which case the query block can return another query.
|
100
126
|
|
101
127
|
```ruby
|
102
|
-
|
103
|
-
RecordLoader.for(Product).load(
|
128
|
+
def product_image(id:)
|
129
|
+
RecordLoader.for(Product).load(id).then do |product|
|
104
130
|
RecordLoader.for(Image).load(product.image_id)
|
105
131
|
end
|
106
132
|
end
|
@@ -109,7 +135,7 @@ end
|
|
109
135
|
If the second query doesn't depend on the first one, then you can use Promise.all, which allows each query in the group to be batched with other queries.
|
110
136
|
|
111
137
|
```ruby
|
112
|
-
|
138
|
+
def all_collections
|
113
139
|
Promise.all([
|
114
140
|
CountLoader.for(Shop, :smart_collections).load(context.shop_id),
|
115
141
|
CountLoader.for(Shop, :custom_collections).load(context.shop_id),
|
@@ -122,8 +148,10 @@ end
|
|
122
148
|
`.then` can optionally take two lambda arguments, the first of which is equivalent to passing a block to `.then`, and the second one handles exceptions. This can be used to provide a fallback
|
123
149
|
|
124
150
|
```ruby
|
125
|
-
|
151
|
+
def product(id:)
|
152
|
+
# Try the cache first ...
|
126
153
|
CacheLoader.for(Product).load(args["id"]).then(nil, lambda do |exc|
|
154
|
+
# But if there's a connection error, go to the underlying database
|
127
155
|
raise exc unless exc.is_a?(Redis::BaseConnectionError)
|
128
156
|
logger.warn err.message
|
129
157
|
RecordLoader.for(Product).load(args["id"])
|
data/graphql-batch.gemspec
CHANGED
@@ -18,13 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_runtime_dependency "graphql", ">=
|
21
|
+
spec.add_runtime_dependency "graphql", ">= 1.3", "< 2"
|
22
22
|
spec.add_runtime_dependency "promise.rb", "~> 0.7.2"
|
23
23
|
|
24
|
-
if RUBY_ENGINE == 'ruby'
|
25
|
-
spec.add_development_dependency "byebug"
|
26
|
-
end
|
27
|
-
spec.add_development_dependency "bundler", "~> 1.10"
|
24
|
+
spec.add_development_dependency "byebug" if RUBY_ENGINE == 'ruby'
|
28
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
29
26
|
spec.add_development_dependency "minitest"
|
30
27
|
end
|
data/lib/graphql/batch.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
1
|
require "graphql"
|
2
|
-
if Gem::Version.new(GraphQL::VERSION) < Gem::Version.new("1.3")
|
3
|
-
warn "graphql gem versions less than 1.3 are deprecated for use with graphql-batch, upgrade so lazy_resolve can be used"
|
4
|
-
end
|
5
2
|
require "promise.rb"
|
6
3
|
|
7
4
|
module GraphQL
|
@@ -20,7 +17,17 @@ module GraphQL
|
|
20
17
|
|
21
18
|
def self.use(schema_defn, executor_class: GraphQL::Batch::Executor)
|
22
19
|
schema = schema_defn.target
|
23
|
-
if GraphQL::VERSION >=
|
20
|
+
if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.9.0.pre3')
|
21
|
+
require_relative "batch/mutation_field_extension"
|
22
|
+
if schema.mutation
|
23
|
+
schema.mutation.fields.each do |name, f|
|
24
|
+
field = f.metadata[:type_class]
|
25
|
+
field.extension(GraphQL::Batch::MutationFieldExtension)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
instrumentation = GraphQL::Batch::SetupMultiplex.new(schema, executor_class: executor_class)
|
29
|
+
schema_defn.instrument(:multiplex, instrumentation)
|
30
|
+
elsif GraphQL::VERSION >= "1.6.0"
|
24
31
|
instrumentation = GraphQL::Batch::SetupMultiplex.new(schema, executor_class: executor_class)
|
25
32
|
schema_defn.instrument(:multiplex, instrumentation)
|
26
33
|
schema_defn.instrument(:field, instrumentation)
|
@@ -31,15 +38,11 @@ module GraphQL
|
|
31
38
|
end
|
32
39
|
schema_defn.lazy_resolve(::Promise, :sync)
|
33
40
|
end
|
34
|
-
|
35
|
-
autoload :ExecutionStrategy, 'graphql/batch/execution_strategy'
|
36
|
-
autoload :MutationExecutionStrategy, 'graphql/batch/mutation_execution_strategy'
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
44
|
require_relative "batch/version"
|
41
45
|
require_relative "batch/loader"
|
42
46
|
require_relative "batch/executor"
|
43
|
-
require_relative "batch/promise"
|
44
47
|
require_relative "batch/setup"
|
45
48
|
require_relative "batch/setup_multiplex"
|
data/lib/graphql/batch/loader.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
module GraphQL::Batch
|
2
2
|
class Loader
|
3
|
-
NoExecutorError = GraphQL::Batch::NoExecutorError
|
4
|
-
deprecate_constant :NoExecutorError if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3")
|
5
|
-
|
6
3
|
def self.for(*group_args)
|
7
4
|
loader_key = loader_key_for(*group_args)
|
8
5
|
executor = Executor.current
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module GraphQL::Batch
|
2
|
+
class MutationFieldExtension < GraphQL::Schema::FieldExtension
|
3
|
+
def resolve(object:, arguments:, **_rest)
|
4
|
+
GraphQL::Batch::Executor.current.clear
|
5
|
+
begin
|
6
|
+
::Promise.sync(yield(object, arguments))
|
7
|
+
ensure
|
8
|
+
GraphQL::Batch::Executor.current.clear
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/graphql/batch/setup.rb
CHANGED
@@ -23,15 +23,6 @@ module GraphQL::Batch
|
|
23
23
|
}
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
def before_query(query)
|
28
|
-
warn "Deprecated graphql-batch setup `instrument(:query, GraphQL::Batch::Setup)`, replace with `use GraphQL::Batch`"
|
29
|
-
start_batching(GraphQL::Batch::Executor)
|
30
|
-
end
|
31
|
-
|
32
|
-
def after_query(query)
|
33
|
-
end_batching
|
34
|
-
end
|
35
26
|
end
|
36
27
|
|
37
28
|
def initialize(schema, executor_class:)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-batch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dylan Thacker-Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.3'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '2'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '1.3'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '2'
|
@@ -58,20 +58,6 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: bundler
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '1.10'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '1.10'
|
75
61
|
- !ruby/object:Gem::Dependency
|
76
62
|
name: rake
|
77
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,11 +106,9 @@ files:
|
|
120
106
|
- examples/record_loader.rb
|
121
107
|
- graphql-batch.gemspec
|
122
108
|
- lib/graphql/batch.rb
|
123
|
-
- lib/graphql/batch/execution_strategy.rb
|
124
109
|
- lib/graphql/batch/executor.rb
|
125
110
|
- lib/graphql/batch/loader.rb
|
126
|
-
- lib/graphql/batch/
|
127
|
-
- lib/graphql/batch/promise.rb
|
111
|
+
- lib/graphql/batch/mutation_field_extension.rb
|
128
112
|
- lib/graphql/batch/setup.rb
|
129
113
|
- lib/graphql/batch/setup_multiplex.rb
|
130
114
|
- lib/graphql/batch/version.rb
|
@@ -148,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
132
|
version: '0'
|
149
133
|
requirements: []
|
150
134
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.6
|
135
|
+
rubygems_version: 2.7.6
|
152
136
|
signing_key:
|
153
137
|
specification_version: 4
|
154
138
|
summary: A query batching executor for the graphql gem
|
@@ -1,67 +0,0 @@
|
|
1
|
-
warn "GraphQL::Batch::ExecutionStrategy is deprecated, instead add `use GraphQL::Batch` in GraphQL::Schema.define"
|
2
|
-
|
3
|
-
module GraphQL::Batch
|
4
|
-
class ExecutionStrategy < GraphQL::Query::SerialExecution
|
5
|
-
def execute(_, _, query)
|
6
|
-
GraphQL::Batch.batch do
|
7
|
-
as_promise_unless_resolved(super)
|
8
|
-
end
|
9
|
-
rescue GraphQL::InvalidNullError => err
|
10
|
-
err.parent_error? || query.context.errors.push(err)
|
11
|
-
nil
|
12
|
-
end
|
13
|
-
|
14
|
-
# Needed for MutationExecutionStrategy
|
15
|
-
def deep_sync(result) #:nodoc:
|
16
|
-
::Promise.sync(as_promise_unless_resolved(result))
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def as_promise_unless_resolved(result)
|
22
|
-
all_promises = []
|
23
|
-
each_promise(result) do |obj, key, promise|
|
24
|
-
obj[key] = nil
|
25
|
-
all_promises << promise.then do |value|
|
26
|
-
obj[key] = value
|
27
|
-
as_promise_unless_resolved(value)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
return result if all_promises.empty?
|
31
|
-
::Promise.all(all_promises).then { result }
|
32
|
-
end
|
33
|
-
|
34
|
-
def each_promise(obj, &block)
|
35
|
-
case obj
|
36
|
-
when Array
|
37
|
-
obj.each_with_index do |value, idx|
|
38
|
-
each_promise_in_entry(obj, idx, value, &block)
|
39
|
-
end
|
40
|
-
when Hash
|
41
|
-
obj.each do |key, value|
|
42
|
-
each_promise_in_entry(obj, key, value, &block)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def each_promise_in_entry(obj, key, value, &block)
|
48
|
-
if value.is_a?(::Promise)
|
49
|
-
yield obj, key, value
|
50
|
-
else
|
51
|
-
each_promise(value, &block)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class FieldResolution < GraphQL::Query::SerialExecution::FieldResolution
|
56
|
-
def get_finished_value(raw_value)
|
57
|
-
if raw_value.is_a?(::Promise)
|
58
|
-
raw_value.then(->(result) { super(result) }, lambda do |error|
|
59
|
-
error.is_a?(GraphQL::ExecutionError) ? super(error) : raise(error)
|
60
|
-
end)
|
61
|
-
else
|
62
|
-
super
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require_relative "execution_strategy"
|
2
|
-
|
3
|
-
module GraphQL::Batch
|
4
|
-
class MutationExecutionStrategy < GraphQL::Batch::ExecutionStrategy
|
5
|
-
attr_accessor :enable_batching
|
6
|
-
|
7
|
-
class FieldResolution < GraphQL::Batch::ExecutionStrategy::FieldResolution
|
8
|
-
def get_finished_value(raw_value)
|
9
|
-
strategy = execution_context.strategy
|
10
|
-
return super if strategy.enable_batching
|
11
|
-
|
12
|
-
GraphQL::Batch::Executor.current.clear
|
13
|
-
begin
|
14
|
-
strategy.enable_batching = true
|
15
|
-
strategy.deep_sync(::Promise.sync(super))
|
16
|
-
ensure
|
17
|
-
strategy.enable_batching = false
|
18
|
-
GraphQL::Batch::Executor.current.clear
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|