Skip to content

Commit

Permalink
Merge pull request #4186 from rmosolgo/merge-into-dataloader
Browse files Browse the repository at this point in the history
Add .merge for pre-filling dataloader caches
  • Loading branch information
rmosolgo authored Sep 8, 2022
2 parents 9cc79a9 + 81f103c commit 99e7906
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
13 changes: 13 additions & 0 deletions guides/dataloader/sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,16 @@ end
For a more robust asynchronous task primitive, check out [`Concurrent::Future`](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Future.html).

Ruby 3.0 added built-in support for yielding Fibers that make I/O calls -- hopefully a future GraphQL-Ruby version will work with that!

## Filling the Dataloader Cache

If you load records from the database, you can use them to populate a source's cache by using {{ "Dataloader::Source#merge" | api_doc }}. For example:

```ruby
# Build a `{ key => value }` map to populate the cache
comments_by_id = post.comments.each_with_object({}) { |comment, hash| hash[comment.id] = comment }
# Merge the map into the source's cache
dataloader.with(Sources::ActiveRecordObject, Comment).merge(comments_by_id)
```

After that, any calls to `.load(id)` will use those already-loaded records if they're available.
9 changes: 9 additions & 0 deletions lib/graphql/dataloader/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ def pending?
!@pending_keys.empty?
end

# Add these key-value pairs to this source's cache
# (future loads will use these merged values).
# @param results [Hash<Object => Object>] key-value pairs to cache in this source
# @return [void]
def merge(results)
@results.merge!(results)
nil
end

# Called by {GraphQL::Dataloader} to resolve and pending requests to this source.
# @api private
# @return [void]
Expand Down
16 changes: 15 additions & 1 deletion spec/graphql/dataloader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,6 @@ def self.included(child_class)
assert_equal expected_log, database_log
end


it "supports general usage" do
a = b = c = nil

Expand Down Expand Up @@ -773,6 +772,21 @@ def self.included(child_class)
]
assert_equal expected_log, database_log
end

it "uses cached values from .merge" do
query_str = "{ ingredient(id: 1) { id name } }"
assert_equal "Wheat", schema.execute(query_str)["data"]["ingredient"]["name"]
assert_equal [[:mget, ["1"]]], database_log
database_log.clear

dataloader = schema.dataloader_class.new
data_source = dataloader.with(FiberSchema::DataObject)
data_source.merge({ "1" => { name: "Kamut", id: "1", type: "Grain" } })
assert_equal "Kamut", data_source.load("1")[:name]
res = schema.execute(query_str, context: { dataloader: dataloader })
assert_equal [], database_log
assert_equal "Kamut", res["data"]["ingredient"]["name"]
end
end
end
end
Expand Down

0 comments on commit 99e7906

Please sign in to comment.