Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom preloads with multiple keys #133

Merged
merged 3 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,28 @@ class Post < ActiveRecord::Base
end
```

If you want to preload something that is based on multiple keys, you can also pass an array:

```ruby
class Meeting < ActiveRecord::Base
def organizer_notes
goldiload(key: [:organizer_id, :room_id]) do |id_sets|
# +id_sets+ will be a two dimensional array with the
# organizer_id and room_id for each item, e.g.
# [
# [<organizer_id_1>, <room_id_1>],
# [<organizer_id_2>, <room_id_2>]
# ]
notes = logic_for_fetching_organizer_notes
notes.group_by {|report|
[report.organizer_id, report.room_id]
}
end
end
end
```


**Note:** The `goldiload` method will use the `source_location` of the given block as a cache name to distinguish between multiple defined preloads. If this causes an issue for you, you can also pass a cache name explicitly as the first argument to the `goldiload` method.


Expand Down
15 changes: 13 additions & 2 deletions lib/goldiloader/custom_preloads.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize
def preloaded(model, cache_name:, key:, &block)
unless preloaded?(cache_name)
ids = models.map do |record|
record.public_send(key)
key_from_record(record, key)
end

# We're using instance_exec instead of a simple yield to make sure that the
Expand All @@ -26,13 +26,24 @@ def preloaded(model, cache_name:, key:, &block)

private

def key_from_record(record, key_or_key_list)
if key_or_key_list.is_a?(Array)
# allow passing an array of keys that will be collected from the record
key_or_key_list.map do |key|
record.public_send(key)
end
else
record.public_send(key_or_key_list)
end
end

def store_preloaded(cache_name, preloaded_hash)
@custom_preloads ||= {}
@custom_preloads[cache_name] = preloaded_hash
end

def fetch_preloaded(cache_name, instance, key:)
@custom_preloads&.dig(cache_name, instance.public_send(key))
@custom_preloads&.dig(cache_name, key_from_record(instance, key))
end

def preloaded?(cache_name)
Expand Down
15 changes: 15 additions & 0 deletions spec/goldiloader/goldiloader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,21 @@
expect(posts.map(&:author_via_global_id)).to eq expected_authors
end.to execute_queries(User => 1)
end

it "can use an array as key argument" do
yielded_values = nil
result = blog1.goldiload(key: [:id, :name]) do |key_set|
yielded_values = key_set
key_set.to_h do |keys|
[keys, 123]
end
end

expect(yielded_values).to eq [
[blog1.id, blog1.name]
]
expect(result).to eq 123
end
end

describe "#globally_enabled" do
Expand Down