graphql-batch-edge 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f1cfb067d3ce1cf15b038bf8557342b45cdfa047
4
+ data.tar.gz: 2bf333fa584937a3e7b73ee5fd4e6921f167fe8b
5
+ SHA512:
6
+ metadata.gz: f293f1fb48b1f1480655db9b0bf6f3a7851c3250f627d3c0ddc7b48e2bfcfed6d0378fedfa94a8fb65f6cfcb19066a4927a976dbe1b03ded76d6d2b52b5ccef7
7
+ data.tar.gz: d987a5823ace6f8d79bb8c17e257bc86f88c2da8369a623519d742297d8ab60edcb62251f6ca2bf4ad854aa3f30cab68ab2c9812c4437dd6afff25a379ef2a32
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile*.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3
4
+ - 2.6
5
+ env:
6
+ - TESTING_INTERPRETER=true
7
+ - TESTING_INTERPRETER=false
@@ -0,0 +1,28 @@
1
+ # Contributing
2
+
3
+ Types of contributions we welcome:
4
+
5
+ * Reporting issues with existing features
6
+ * Bug fixes
7
+ * Performance improvements
8
+ * Documentation and/or clearer interfaces
9
+
10
+ ## Proposing Features
11
+
12
+ The main use case for this project is around batching queries
13
+ for GraphQL requests, but is open to changes that make it more
14
+ generic. This includes supporting concurrent or parallel executors.
15
+
16
+ When in doubt about whether we will be interested in including a
17
+ new feature in this project, please open an issue to propose the
18
+ feature so we can confirm the feature should be in scope for the
19
+ project before it is implemented.
20
+
21
+ ## How To Contribute
22
+
23
+ 1. Fork the [repository in github](https://github.com/Shopify/graphql-batch)
24
+ 2. Create your feature branch (`git checkout -b fix-feature`)
25
+ 3. Commit your changes (`git commit -am 'fix: Summarize change'`)
26
+ 3. Make sure all tests pass (`bundle exec rake`)
27
+ 4. Push to the branch (`git push origin fix-feature`)
28
+ 5. [Create new pull request](https://github.com/Shopify/graphql-batch/pulls)
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ if ENV["TESTING_INTERPRETER"] == "true"
6
+ gem "graphql", "1.9.0.pre4"
7
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Shopify Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,183 @@
1
+ # GraphQL::Batch
2
+
3
+ [![Build Status](https://travis-ci.org/Shopify/graphql-batch.svg?branch=master)](https://travis-ci.org/Shopify/graphql-batch)
4
+ [![Gem Version](https://badge.fury.io/rb/graphql-batch.svg)](https://rubygems.org/gems/graphql-batch)
5
+
6
+ Provides an executor for the [`graphql` gem](https://github.com/rmosolgo/graphql-ruby) which allows queries to be batched.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'graphql-batch'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install graphql-batch
23
+
24
+ ## Usage
25
+
26
+ ### Basic Usage
27
+
28
+ #### Schema Configuration
29
+
30
+ Require the library
31
+
32
+ ```ruby
33
+ require 'graphql/batch'
34
+ ```
35
+
36
+ Define a custom loader, which is initialized with arguments that are used for grouping and a perform method for performing the batch load.
37
+
38
+ ```ruby
39
+ class RecordLoader < GraphQL::Batch::Loader
40
+ def initialize(model)
41
+ @model = model
42
+ end
43
+
44
+ def perform(ids)
45
+ @model.where(id: ids).each { |record| fulfill(record.id, record) }
46
+ ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
47
+ end
48
+ end
49
+ ```
50
+
51
+ Use `GraphQL::Batch` as a plugin in your schema _after_ specifying the mutation
52
+ so that `GraphQL::Batch` can extend the mutation fields to clear the cache after
53
+ they are resolved (for graphql >= `1.5.0`).
54
+
55
+ ```ruby
56
+ class MySchema < GraphQL::Schema
57
+ query MyQueryType
58
+ mutation MyMutationType
59
+
60
+ use GraphQL::Batch
61
+ end
62
+ ```
63
+
64
+ For pre `1.5.0` versions:
65
+
66
+ ```ruby
67
+ MySchema = GraphQL::Schema.define do
68
+ query MyQueryType
69
+
70
+ GraphQL::Batch.use(self)
71
+ end
72
+ ```
73
+
74
+ #### Field Usage
75
+
76
+ 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.
77
+
78
+ ```ruby
79
+ field :product, Types::Product, null: true do
80
+ argument :id, ID, required: true
81
+ end
82
+
83
+ def product(id:)
84
+ RecordLoader.for(Product).load(id)
85
+ end
86
+ ```
87
+
88
+ The loader also supports batch loading an array of records instead of just a single record, via `load_many`. For example:
89
+
90
+ ```ruby
91
+ field :products, [Types::Product, null: true], null: false do
92
+ argument :ids, [ID], required: true
93
+ end
94
+
95
+ def products(ids:)
96
+ RecordLoader.for(Product).load_many(ids)
97
+ end
98
+ ```
99
+
100
+ Although this library doesn't have a dependency on active record,
101
+ the [examples directory](examples) has record and association loaders
102
+ for active record which handles edge cases like type casting ids
103
+ and overriding GraphQL::Batch::Loader#cache_key to load associations
104
+ on records with the same id.
105
+
106
+ ### Promises
107
+
108
+ 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`
109
+
110
+ ```ruby
111
+ def product_title(id:)
112
+ RecordLoader.for(Product).load(id).then do |product|
113
+ product.title
114
+ end
115
+ end
116
+ ```
117
+
118
+ 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.
119
+
120
+ ```ruby
121
+ def product_image(id:)
122
+ RecordLoader.for(Product).load(id).then do |product|
123
+ RecordLoader.for(Image).load(product.image_id)
124
+ end
125
+ end
126
+ ```
127
+
128
+ 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.
129
+
130
+ ```ruby
131
+ def all_collections
132
+ Promise.all([
133
+ CountLoader.for(Shop, :smart_collections).load(context.shop_id),
134
+ CountLoader.for(Shop, :custom_collections).load(context.shop_id),
135
+ ]).then do |results|
136
+ results.reduce(&:+)
137
+ end
138
+ end
139
+ ```
140
+
141
+ `.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
142
+
143
+ ```ruby
144
+ def product(id:)
145
+ # Try the cache first ...
146
+ CacheLoader.for(Product).load(args["id"]).then(nil, lambda do |exc|
147
+ # But if there's a connection error, go to the underlying database
148
+ raise exc unless exc.is_a?(Redis::BaseConnectionError)
149
+ logger.warn err.message
150
+ RecordLoader.for(Product).load(args["id"])
151
+ end)
152
+ end
153
+ ```
154
+
155
+ ## Unit Testing
156
+
157
+ Your loaders can be tested outside of a GraphQL query by doing the
158
+ batch loads in a block passed to GraphQL::Batch.batch. That method
159
+ will set up thread-local state to store the loaders, batch load any
160
+ promise returned from the block then clear the thread-local state
161
+ to avoid leaking state between tests.
162
+
163
+ ```ruby
164
+ def test_single_query
165
+ product = products(:snowboard)
166
+ title = GraphQL::Batch.batch do
167
+ RecordLoader.for(Product).load(product.id).then(&:title)
168
+ end
169
+ assert_equal product.title, title
170
+ end
171
+ ```
172
+
173
+ ## Development
174
+
175
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
176
+
177
+ ## Contributing
178
+
179
+ See our [contributing guidelines](CONTRIBUTING.md) for more information.
180
+
181
+ ## License
182
+
183
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "graphql/batch"
5
+
6
+ require "irb"
7
+ IRB.start
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
@@ -0,0 +1,48 @@
1
+ class AssociationLoader < GraphQL::Batch::Loader
2
+ def self.validate(model, association_name)
3
+ new(model, association_name)
4
+ nil
5
+ end
6
+
7
+ def initialize(model, association_name)
8
+ @model = model
9
+ @association_name = association_name
10
+ validate
11
+ end
12
+
13
+ def load(record)
14
+ raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
15
+ return Promise.resolve(read_association(record)) if association_loaded?(record)
16
+ super
17
+ end
18
+
19
+ # We want to load the associations on all records, even if they have the same id
20
+ def cache_key(record)
21
+ record.object_id
22
+ end
23
+
24
+ def perform(records)
25
+ preload_association(records)
26
+ records.each { |record| fulfill(record, read_association(record)) }
27
+ end
28
+
29
+ private
30
+
31
+ def validate
32
+ unless @model.reflect_on_association(@association_name)
33
+ raise ArgumentError, "No association #{@association_name} on #{@model}"
34
+ end
35
+ end
36
+
37
+ def preload_association(records)
38
+ ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
39
+ end
40
+
41
+ def read_association(record)
42
+ record.public_send(@association_name)
43
+ end
44
+
45
+ def association_loaded?(record)
46
+ record.association(@association_name).loaded?
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ class RecordLoader < GraphQL::Batch::Loader
2
+ def initialize(model, column: model.primary_key, where: nil)
3
+ @model = model
4
+ @column = column.to_s
5
+ @column_type = model.type_for_attribute(@column)
6
+ @where = where
7
+ end
8
+
9
+ def load(key)
10
+ super(@column_type.cast(key))
11
+ end
12
+
13
+ def perform(keys)
14
+ query(keys).each { |record| fulfill(record.public_send(@column), record) }
15
+ keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
16
+ end
17
+
18
+ private
19
+
20
+ def query(keys)
21
+ scope = @model
22
+ scope = scope.where(@where) if @where
23
+ scope.where(@column => keys)
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'graphql/batch/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "graphql-batch-edge"
8
+ spec.version = GraphQL::Batch::VERSION
9
+ spec.authors = ["Dylan Thacker-Smith"]
10
+ spec.email = ["gems@shopify.com"]
11
+
12
+ spec.summary = "A query batching executor for the graphql gem (Unofficial Edge Releases)"
13
+ spec.homepage = "https://github.com/Shopify/graphql-batch"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "graphql", ">= 1.3", "< 2"
22
+ spec.add_runtime_dependency "promise.rb", "~> 0.7.2"
23
+
24
+ spec.add_development_dependency "byebug" if RUBY_ENGINE == 'ruby'
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ end
@@ -0,0 +1,49 @@
1
+ require "graphql"
2
+ require "promise.rb"
3
+
4
+ module GraphQL
5
+ module Batch
6
+ BrokenPromiseError = ::Promise::BrokenError
7
+ class NoExecutorError < StandardError; end
8
+
9
+ def self.batch(executor_class: GraphQL::Batch::Executor)
10
+ begin
11
+ GraphQL::Batch::Executor.start_batch(executor_class)
12
+ ::Promise.sync(yield)
13
+ ensure
14
+ GraphQL::Batch::Executor.end_batch
15
+ end
16
+ end
17
+
18
+ def self.use(schema_defn, executor_class: GraphQL::Batch::Executor)
19
+ schema = schema_defn.target
20
+ if GraphQL::VERSION >= "1.6.0"
21
+ instrumentation = GraphQL::Batch::SetupMultiplex.new(schema, executor_class: executor_class)
22
+ schema_defn.instrument(:multiplex, instrumentation)
23
+ if schema.mutation
24
+ if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.9.0.pre3') &&
25
+ schema.mutation.metadata[:type_class]
26
+ require_relative "batch/mutation_field_extension"
27
+ schema.mutation.fields.each do |name, f|
28
+ field = f.metadata[:type_class]
29
+ field.extension(GraphQL::Batch::MutationFieldExtension)
30
+ end
31
+ else
32
+ schema_defn.instrument(:field, instrumentation)
33
+ end
34
+ end
35
+ else
36
+ instrumentation = GraphQL::Batch::Setup.new(schema, executor_class: executor_class)
37
+ schema_defn.instrument(:query, instrumentation)
38
+ schema_defn.instrument(:field, instrumentation)
39
+ end
40
+ schema_defn.lazy_resolve(::Promise, :sync)
41
+ end
42
+ end
43
+ end
44
+
45
+ require_relative "batch/version"
46
+ require_relative "batch/loader"
47
+ require_relative "batch/executor"
48
+ require_relative "batch/setup"
49
+ require_relative "batch/setup_multiplex"
@@ -0,0 +1,86 @@
1
+ module GraphQL::Batch
2
+ class Executor
3
+ THREAD_KEY = :"#{name}.batched_queries"
4
+ private_constant :THREAD_KEY
5
+
6
+ class << self
7
+ def current
8
+ Thread.current[THREAD_KEY]
9
+ end
10
+
11
+ def current=(executor)
12
+ Thread.current[THREAD_KEY] = executor
13
+ end
14
+
15
+ def start_batch(executor_class)
16
+ executor = Thread.current[THREAD_KEY] ||= executor_class.new
17
+ executor.increment_level
18
+ end
19
+
20
+ def end_batch
21
+ executor = current
22
+ unless executor
23
+ raise NoExecutorError, 'Cannot end a batch without an Executor.'
24
+ end
25
+ return unless executor.decrement_level < 1
26
+ self.current = nil
27
+ end
28
+ end
29
+
30
+ # Set to true when performing a batch query, otherwise, it is false.
31
+ #
32
+ # Can be used to detect unbatched queries in an ActiveSupport::Notifications.subscribe block.
33
+ attr_reader :loading
34
+
35
+ def initialize
36
+ @loaders = {}
37
+ @loading = false
38
+ @nesting_level = 0
39
+ end
40
+
41
+ def loader(key)
42
+ @loaders[key] ||= yield.tap do |loader|
43
+ loader.executor = self
44
+ loader.loader_key = key
45
+ end
46
+ end
47
+
48
+ def resolve(loader)
49
+ was_loading = @loading
50
+ @loading = true
51
+ loader.resolve
52
+ ensure
53
+ @loading = was_loading
54
+ end
55
+
56
+ def tick
57
+ resolve(@loaders.shift.last)
58
+ end
59
+
60
+ def wait_all
61
+ tick until @loaders.empty?
62
+ end
63
+
64
+ def clear
65
+ @loaders.clear
66
+ end
67
+
68
+ def increment_level
69
+ @nesting_level += 1
70
+ end
71
+
72
+ def decrement_level
73
+ @nesting_level -= 1
74
+ end
75
+
76
+ def around_promise_callbacks
77
+ # We need to set #loading to false so that any queries that happen in the promise
78
+ # callback aren't interpreted as being performed in GraphQL::Batch::Loader#perform
79
+ was_loading = @loading
80
+ @loading = false
81
+ yield
82
+ ensure
83
+ @loading = was_loading
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,133 @@
1
+ module GraphQL::Batch
2
+ class Loader
3
+ def self.for(*group_args)
4
+ loader_key = loader_key_for(*group_args)
5
+ executor = Executor.current
6
+
7
+ unless executor
8
+ raise GraphQL::Batch::NoExecutorError, 'Cannot create loader without'\
9
+ ' an Executor. Wrap the call to `for` with `GraphQL::Batch.batch`'\
10
+ ' or use `GraphQL::Batch::Setup` as a query instrumenter if'\
11
+ ' using with `graphql-ruby`'
12
+ end
13
+
14
+ executor.loader(loader_key) { new(*group_args) }
15
+ end
16
+
17
+ def self.loader_key_for(*group_args)
18
+ [self].concat(group_args)
19
+ end
20
+
21
+ def self.load(key)
22
+ self.for.load(key)
23
+ end
24
+
25
+ def self.load_many(keys)
26
+ self.for.load_many(keys)
27
+ end
28
+
29
+ attr_accessor :loader_key, :executor
30
+
31
+ def load(key)
32
+ cache[cache_key(key)] ||= begin
33
+ queue << key
34
+ ::Promise.new.tap { |promise| promise.source = self }
35
+ end
36
+ end
37
+
38
+ def load_many(keys)
39
+ ::Promise.all(keys.map { |key| load(key) })
40
+ end
41
+
42
+ def resolve #:nodoc:
43
+ return if resolved?
44
+ load_keys = queue
45
+ @queue = nil
46
+ perform(load_keys)
47
+ check_for_broken_promises(load_keys)
48
+ rescue => err
49
+ reject_pending_promises(load_keys, err)
50
+ end
51
+
52
+ # For Promise#sync
53
+ def wait #:nodoc:
54
+ if executor
55
+ executor.resolve(self)
56
+ else
57
+ resolve
58
+ end
59
+ end
60
+
61
+ def resolved?
62
+ @queue.nil? || @queue.empty?
63
+ end
64
+
65
+ protected
66
+
67
+ # Fulfill the key with provided value, for use in #perform
68
+ def fulfill(key, value)
69
+ finish_resolve(key) do |promise|
70
+ promise.fulfill(value)
71
+ end
72
+ end
73
+
74
+ def reject(key, reason)
75
+ finish_resolve(key) do |promise|
76
+ promise.reject(reason)
77
+ end
78
+ end
79
+
80
+ # Returns true when the key has already been fulfilled, otherwise returns false
81
+ def fulfilled?(key)
82
+ promise_for(key).fulfilled?
83
+ end
84
+
85
+ # Must override to load the keys and call #fulfill for each key
86
+ def perform(keys)
87
+ raise NotImplementedError
88
+ end
89
+
90
+ # Override to use a different key for the cache than the load key
91
+ def cache_key(load_key)
92
+ load_key
93
+ end
94
+
95
+ private
96
+
97
+ def finish_resolve(key)
98
+ promise = promise_for(key)
99
+ return yield(promise) unless executor
100
+ executor.around_promise_callbacks do
101
+ yield promise
102
+ end
103
+ end
104
+
105
+ def cache
106
+ @cache ||= {}
107
+ end
108
+
109
+ def queue
110
+ @queue ||= []
111
+ end
112
+
113
+ def promise_for(load_key)
114
+ cache.fetch(cache_key(load_key))
115
+ end
116
+
117
+ def reject_pending_promises(load_keys, err)
118
+ load_keys.each do |key|
119
+ next unless promise_for(key).pending?
120
+
121
+ reject(key, err)
122
+ end
123
+ end
124
+
125
+ def check_for_broken_promises(load_keys)
126
+ load_keys.each do |key|
127
+ next unless promise_for(key).pending?
128
+
129
+ reject(key, ::Promise::BrokenError.new("#{self.class} didn't fulfill promise for key #{key.inspect}"))
130
+ end
131
+ end
132
+ end
133
+ end
@@ -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
@@ -0,0 +1,45 @@
1
+ module GraphQL::Batch
2
+ class Setup
3
+ class << self
4
+ def start_batching(executor_class)
5
+ GraphQL::Batch::Executor.start_batch(executor_class)
6
+ end
7
+
8
+ def end_batching
9
+ GraphQL::Batch::Executor.end_batch
10
+ end
11
+
12
+ def instrument_field(schema, type, field)
13
+ return field unless type == schema.mutation
14
+ old_resolve_proc = field.resolve_proc
15
+ field.redefine do
16
+ resolve ->(obj, args, ctx) {
17
+ GraphQL::Batch::Executor.current.clear
18
+ begin
19
+ ::Promise.sync(old_resolve_proc.call(obj, args, ctx))
20
+ ensure
21
+ GraphQL::Batch::Executor.current.clear
22
+ end
23
+ }
24
+ end
25
+ end
26
+ end
27
+
28
+ def initialize(schema, executor_class:)
29
+ @schema = schema
30
+ @executor_class = executor_class
31
+ end
32
+
33
+ def before_query(query)
34
+ Setup.start_batching(@executor_class)
35
+ end
36
+
37
+ def after_query(query)
38
+ Setup.end_batching
39
+ end
40
+
41
+ def instrument(type, field)
42
+ Setup.instrument_field(@schema, type, field)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module GraphQL::Batch
2
+ class SetupMultiplex
3
+ def initialize(schema, executor_class:)
4
+ @schema = schema
5
+ @executor_class = executor_class
6
+ end
7
+
8
+ def before_multiplex(multiplex)
9
+ Setup.start_batching(@executor_class)
10
+ end
11
+
12
+ def after_multiplex(multiplex)
13
+ Setup.end_batching
14
+ end
15
+
16
+ def instrument(type, field)
17
+ Setup.instrument_field(@schema, type, field)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module GraphQL
2
+ module Batch
3
+ VERSION = "0.4.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphql-batch-edge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Dylan Thacker-Smith
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: promise.rb
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.7.2
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.7.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: byebug
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: minitest
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description:
90
+ email:
91
+ - gems@shopify.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - ".gitignore"
97
+ - ".travis.yml"
98
+ - CONTRIBUTING.md
99
+ - Gemfile
100
+ - LICENSE.txt
101
+ - README.md
102
+ - Rakefile
103
+ - bin/console
104
+ - bin/setup
105
+ - examples/association_loader.rb
106
+ - examples/record_loader.rb
107
+ - graphql-batch.gemspec
108
+ - lib/graphql/batch.rb
109
+ - lib/graphql/batch/executor.rb
110
+ - lib/graphql/batch/loader.rb
111
+ - lib/graphql/batch/mutation_field_extension.rb
112
+ - lib/graphql/batch/setup.rb
113
+ - lib/graphql/batch/setup_multiplex.rb
114
+ - lib/graphql/batch/version.rb
115
+ homepage: https://github.com/Shopify/graphql-batch
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.4.6
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: A query batching executor for the graphql gem (Unofficial Edge Releases)
139
+ test_files: []