batch-loader 1.1.1 → 1.2.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 +4 -4
 - data/CHANGELOG.md +5 -1
 - data/README.md +44 -0
 - data/lib/batch_loader.rb +5 -3
 - data/lib/batch_loader/executor_proxy.rb +2 -2
 - data/lib/batch_loader/version.rb +1 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: aa05684af093fc9efd4873f256fd0a173179609c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 9e7e5751b5bba6b43f0cf8bce0e32fd64885a194
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: '08d5499226c25e153e4587358e8f38cd88950fe4d216578ea5b82b71f77ca381bd07f0383bda26e54edd56ffb4c92b458028857f1db7d770101039c548d0838e'
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: '02913dc9ee5cc57e952ecd49a7636d275d7343990c574a3f14ff0ddf7ed662991cfdd4f8b722c0dcca54b86996d9a4377ebf4f5582075bf54670657dc8c0c30d'
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -8,10 +8,14 @@ one of the following labels: `Added`, `Changed`, `Deprecated`, 
     | 
|
| 
       8 
8 
     | 
    
         
             
            to manage the versions of this gem so
         
     | 
| 
       9 
9 
     | 
    
         
             
            that you can set version constraints properly.
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
            #### [Unreleased](https://github.com/exAspArk/batch-loader/compare/v1. 
     | 
| 
      
 11 
     | 
    
         
            +
            #### [Unreleased](https://github.com/exAspArk/batch-loader/compare/v1.2.0...HEAD)
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
            * WIP
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
            #### [v1.2.0](https://github.com/exAspArk/batch-loader/compare/v1.1.1...v1.2.0)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            * `Added`: `key` argument for the `BatchLoader#batch` method. [#12](https://github.com/exAspArk/batch-loader/pull/12)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       15 
19 
     | 
    
         
             
            #### [v1.1.1](https://github.com/exAspArk/batch-loader/compare/v1.1.0...v1.1.1)
         
     | 
| 
       16 
20 
     | 
    
         | 
| 
       17 
21 
     | 
    
         
             
            * `Fixed`: `loader`, made it thread-safe again. [#10](https://github.com/exAspArk/batch-loader/pull/10)
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -18,8 +18,10 @@ This gem provides a generic lazy batching mechanism to avoid N+1 DB queries, HTT 
     | 
|
| 
       18 
18 
     | 
    
         
             
              * [RESTful API example](#restful-api-example)
         
     | 
| 
       19 
19 
     | 
    
         
             
              * [GraphQL example](#graphql-example)
         
     | 
| 
       20 
20 
     | 
    
         
             
              * [Loading multiple items](#loading-multiple-items)
         
     | 
| 
      
 21 
     | 
    
         
            +
              * [Batch key](#batch-key)
         
     | 
| 
       21 
22 
     | 
    
         
             
              * [Caching](#caching)
         
     | 
| 
       22 
23 
     | 
    
         
             
            * [Installation](#installation)
         
     | 
| 
      
 24 
     | 
    
         
            +
            * [API](#api)
         
     | 
| 
       23 
25 
     | 
    
         
             
            * [Implementation details](#implementation-details)
         
     | 
| 
       24 
26 
     | 
    
         
             
            * [Development](#development)
         
     | 
| 
       25 
27 
     | 
    
         
             
            * [Contributing](#contributing)
         
     | 
| 
         @@ -300,6 +302,30 @@ BatchLoader.for(user.id).batch(default_value: []) do |comment_ids, loader| 
     | 
|
| 
       300 
302 
     | 
    
         
             
            end
         
     | 
| 
       301 
303 
     | 
    
         
             
            ```
         
     | 
| 
       302 
304 
     | 
    
         | 
| 
      
 305 
     | 
    
         
            +
            ### Batch key
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
            It's possible to reuse the same `BatchLoader#batch` block for loading different types of data by specifying a unique `key`.
         
     | 
| 
      
 308 
     | 
    
         
            +
            For example, with polymorphic associations:
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 311 
     | 
    
         
            +
            def lazy_association(post)
         
     | 
| 
      
 312 
     | 
    
         
            +
              id = post.association_id
         
     | 
| 
      
 313 
     | 
    
         
            +
              key = post.association_type
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
              BatchLoader.for(id).batch(key: key) do |ids, loader, args|
         
     | 
| 
      
 316 
     | 
    
         
            +
                model = Object.const_get(args[:key])
         
     | 
| 
      
 317 
     | 
    
         
            +
                model.where(id: ids).each { |record| record.call(record.id, record) }
         
     | 
| 
      
 318 
     | 
    
         
            +
              end
         
     | 
| 
      
 319 
     | 
    
         
            +
            end
         
     | 
| 
      
 320 
     | 
    
         
            +
            post1 = Post.save(association_id: 1, association_type: 'Tag')
         
     | 
| 
      
 321 
     | 
    
         
            +
            post2 = Post.save(association_id: 1, association_type: 'Category')
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
            lazy_association(post1) # SELECT * FROM tags WHERE id IN (1)
         
     | 
| 
      
 324 
     | 
    
         
            +
            lazy_association(post2) # SELECT * FROM categories WHERE id IN (1)
         
     | 
| 
      
 325 
     | 
    
         
            +
            ```
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
            It's also required to pass custom `key` when using `BatchLoader` with metaprogramming (e.g. `eval`).
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
       303 
329 
     | 
    
         
             
            ### Caching
         
     | 
| 
       304 
330 
     | 
    
         | 
| 
       305 
331 
     | 
    
         
             
            By default `BatchLoader` caches the loaded values. You can test it by running something like:
         
     | 
| 
         @@ -364,6 +390,24 @@ Or install it yourself as: 
     | 
|
| 
       364 
390 
     | 
    
         | 
| 
       365 
391 
     | 
    
         
             
                $ gem install batch-loader
         
     | 
| 
       366 
392 
     | 
    
         | 
| 
      
 393 
     | 
    
         
            +
            ## API
         
     | 
| 
      
 394 
     | 
    
         
            +
             
     | 
| 
      
 395 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 396 
     | 
    
         
            +
            BatchLoader.for(item).batch(default_value: default_value, cache: cache, key: key) do |items, loader, args|
         
     | 
| 
      
 397 
     | 
    
         
            +
              # ...
         
     | 
| 
      
 398 
     | 
    
         
            +
            end
         
     | 
| 
      
 399 
     | 
    
         
            +
            ```
         
     | 
| 
      
 400 
     | 
    
         
            +
             
     | 
| 
      
 401 
     | 
    
         
            +
            | Argument Key    | Default                                       | Description                                                   |
         
     | 
| 
      
 402 
     | 
    
         
            +
            | --------------- | --------------------------------------------- | ------------------------------------------------------------- |
         
     | 
| 
      
 403 
     | 
    
         
            +
            | `item`          | -                                             | Item which will be collected and used for batching.           |
         
     | 
| 
      
 404 
     | 
    
         
            +
            | `default_value` | `nil`                                         | Value returned by default after batching.                     |
         
     | 
| 
      
 405 
     | 
    
         
            +
            | `cache`         | `true`                                        | Set `false` to disable caching between the same executions.   |
         
     | 
| 
      
 406 
     | 
    
         
            +
            | `key`           | `nil`                                         | Pass custom key to uniquely identify the batch block.         |
         
     | 
| 
      
 407 
     | 
    
         
            +
            | `items`         | -                                             | List of collected items for batching.                         |
         
     | 
| 
      
 408 
     | 
    
         
            +
            | `loader`        | -                                             | Lambda which should be called to load values loaded in batch. |
         
     | 
| 
      
 409 
     | 
    
         
            +
            | `args`          | `{default_value: nil, cache: true, key: nil}` | Arguments passed to the `batch` method.                       |
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
       367 
411 
     | 
    
         
             
            ## Implementation details
         
     | 
| 
       368 
412 
     | 
    
         | 
| 
       369 
413 
     | 
    
         
             
            See the [slides](https://speakerdeck.com/exaspark/batching-a-powerful-way-to-solve-n-plus-1-queries) [37-42].
         
     | 
    
        data/lib/batch_loader.rb
    CHANGED
    
    | 
         @@ -23,9 +23,10 @@ class BatchLoader 
     | 
|
| 
       23 
23 
     | 
    
         
             
                @__executor_proxy = executor_proxy
         
     | 
| 
       24 
24 
     | 
    
         
             
              end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
              def batch(default_value: nil, cache: true, &batch_block)
         
     | 
| 
      
 26 
     | 
    
         
            +
              def batch(default_value: nil, cache: true, key: nil, &batch_block)
         
     | 
| 
       27 
27 
     | 
    
         
             
                @default_value = default_value
         
     | 
| 
       28 
28 
     | 
    
         
             
                @cache = cache
         
     | 
| 
      
 29 
     | 
    
         
            +
                @key = key
         
     | 
| 
       29 
30 
     | 
    
         
             
                @batch_block = batch_block
         
     | 
| 
       30 
31 
     | 
    
         
             
                __executor_proxy.add(item: @item)
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
         @@ -78,7 +79,8 @@ class BatchLoader 
     | 
|
| 
       78 
79 
     | 
    
         | 
| 
       79 
80 
     | 
    
         
             
                items = __executor_proxy.list_items
         
     | 
| 
       80 
81 
     | 
    
         
             
                loader = __loader
         
     | 
| 
       81 
     | 
    
         
            -
                @ 
     | 
| 
      
 82 
     | 
    
         
            +
                args = {default_value: @default_value, cache: @cache, key: @key}
         
     | 
| 
      
 83 
     | 
    
         
            +
                @batch_block.call(items, loader, args)
         
     | 
| 
       82 
84 
     | 
    
         
             
                items.each do |item|
         
     | 
| 
       83 
85 
     | 
    
         
             
                  next if __executor_proxy.value_loaded?(item: item)
         
     | 
| 
       84 
86 
     | 
    
         
             
                  loader.call(item, @default_value)
         
     | 
| 
         @@ -126,7 +128,7 @@ class BatchLoader 
     | 
|
| 
       126 
128 
     | 
    
         
             
              def __executor_proxy
         
     | 
| 
       127 
129 
     | 
    
         
             
                @__executor_proxy ||= begin
         
     | 
| 
       128 
130 
     | 
    
         
             
                  raise NoBatchError.new("Please provide a batch block first") unless @batch_block
         
     | 
| 
       129 
     | 
    
         
            -
                  BatchLoader::ExecutorProxy.new(@default_value, &@batch_block)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  BatchLoader::ExecutorProxy.new(@default_value, @key, &@batch_block)
         
     | 
| 
       130 
132 
     | 
    
         
             
                end
         
     | 
| 
       131 
133 
     | 
    
         
             
              end
         
     | 
| 
       132 
134 
     | 
    
         | 
| 
         @@ -6,10 +6,10 @@ class BatchLoader 
     | 
|
| 
       6 
6 
     | 
    
         
             
              class ExecutorProxy
         
     | 
| 
       7 
7 
     | 
    
         
             
                attr_reader :default_value, :block, :global_executor
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                def initialize(default_value, &block)
         
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(default_value, key, &block)
         
     | 
| 
       10 
10 
     | 
    
         
             
                  @default_value = default_value
         
     | 
| 
       11 
11 
     | 
    
         
             
                  @block = block
         
     | 
| 
       12 
     | 
    
         
            -
                  @block_hash_key = block.source_location
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @block_hash_key = "#{key}#{block.source_location}"
         
     | 
| 
       13 
13 
     | 
    
         
             
                  @global_executor = BatchLoader::Executor.ensure_current
         
     | 
| 
       14 
14 
     | 
    
         
             
                end
         
     | 
| 
       15 
15 
     | 
    
         | 
    
        data/lib/batch_loader/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: batch-loader
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.2.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - exAspArk
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2017-11- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2017-11-16 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bundler
         
     |