ProductPromotion
Logo

Ruby

made by https://0x3d.site

GitHub - Shopify/graphql-batch: A query batching executor for the graphql gem
A query batching executor for the graphql gem. Contribute to Shopify/graphql-batch development by creating an account on GitHub.
Visit Site

GitHub - Shopify/graphql-batch: A query batching executor for the graphql gem

GitHub - Shopify/graphql-batch: A query batching executor for the graphql gem

GraphQL::Batch

Build Status Gem Version

Provides an executor for the graphql gem which allows queries to be batched.

Installation

Add this line to your application's Gemfile:

gem 'graphql-batch'

And then execute:

$ bundle

Or install it yourself as:

$ gem install graphql-batch

Usage

Basic Usage

Schema Configuration

Require the library

require 'graphql/batch'

Define a custom loader, which is initialized with arguments that are used for grouping and a perform method for performing the batch load.

class RecordLoader < GraphQL::Batch::Loader
  def initialize(model)
    @model = model
  end

  def perform(ids)
    @model.where(id: ids).each { |record| fulfill(record.id, record) }
    ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
  end
end

Use GraphQL::Batch as a plugin in your schema after specifying the mutation so that GraphQL::Batch can extend the mutation fields to clear the cache after they are resolved.

class MySchema < GraphQL::Schema
  query MyQueryType
  mutation MyMutationType

  use GraphQL::Batch
end

Field Usage

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.

field :product, Types::Product, null: true do
  argument :id, ID, required: true
end

def product(id:)
  RecordLoader.for(Product).load(id)
end

The loader also supports batch loading an array of records instead of just a single record, via load_many. For example:

field :products, [Types::Product, null: true], null: false do
  argument :ids, [ID], required: true
end

def products(ids:)
  RecordLoader.for(Product).load_many(ids)
end

Although this library doesn't have a dependency on active record, the examples directory has record and association loaders for active record which handles edge cases like type casting ids and overriding GraphQL::Batch::Loader#cache_key to load associations on records with the same id.

Promises

GraphQL::Batch::Loader#load returns a Promise using the promise.rb gem to provide a promise based API, so you can transform the query results using .then

def product_title(id:)
  RecordLoader.for(Product).load(id).then do |product|
    product.title
  end
end

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.

def product_image(id:)
  RecordLoader.for(Product).load(id).then do |product|
    RecordLoader.for(Image).load(product.image_id)
  end
end

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.

def all_collections
  Promise.all([
    CountLoader.for(Shop, :smart_collections).load(context.shop_id),
    CountLoader.for(Shop, :custom_collections).load(context.shop_id),
  ]).then(&:sum)
end

.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

def product(id:)
  # Try the cache first ...
  CacheLoader.for(Product).load(id).then(nil, lambda do |exc|
    # But if there's a connection error, go to the underlying database
    raise exc unless exc.is_a?(Redis::BaseConnectionError)
    logger.warn err.message
    RecordLoader.for(Product).load(id)
  end)
end

Priming the Cache

You can prime the loader cache with a specific value, which can be useful in certain situations.

def liked_products
  liked_products = Product.where(liked: true).load
  liked_products.each do |product|
    RecordLoader.for(Product).prime(product.id, product)
  end
end

Priming will add key/value to the loader cache only if it didn't exist before.

Unit Testing

Your loaders can be tested outside of a GraphQL query by doing the batch loads in a block passed to GraphQL::Batch.batch. That method will set up thread-local state to store the loaders, batch load any promise returned from the block then clear the thread-local state to avoid leaking state between tests.

def test_single_query
  product = products(:snowboard)
  title = GraphQL::Batch.batch do
    RecordLoader.for(Product).load(product.id).then(&:title)
  end
  assert_equal product.title, title
end

Development

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.

Contributing

See our contributing guidelines for more information.

License

The gem is available as open source under the terms of the MIT License.

More Resources
to explore the angular.

mail [email protected] to add your project or resources here 🔥.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory