Module: Pipeloader::Batch::BatchLoader
- Defined in:
- lib/pipeloader/batch/batch_loader.rb
Overview
Runs ONE query for a BatchProxy’s accumulated scope across every live sibling of the owner, partitions rows by foreign key, applies per-group limit/offset, and caches each sibling’s slice (keyed by the scope) so the other siblings’ identical access is free.
Class Method Summary collapse
-
.apply_window!(grouped, proxy) ⇒ Object
limit/offset are per group: the batched query is ordered but unlimited, and each owner’s slice is taken in Ruby (so “5 per author”, not 5 overall).
- .load(proxy) ⇒ Object
- .relevant_siblings(proxy) ⇒ Object
- .run(proxy, siblings) ⇒ Object
Class Method Details
.apply_window!(grouped, proxy) ⇒ Object
limit/offset are per group: the batched query is ordered but unlimited, and each owner’s slice is taken in Ruby (so “5 per author”, not 5 overall).
52 53 54 55 56 57 58 59 60 |
# File 'lib/pipeloader/batch/batch_loader.rb', line 52 def apply_window!(grouped, proxy) offset = proxy.offset_value || 0 limit = proxy.limit_value grouped.each_key do |key| windowed = grouped[key].drop(offset) windowed = windowed.first(limit) if limit grouped[key] = windowed end end |
.load(proxy) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/pipeloader/batch/batch_loader.rb', line 12 def load(proxy) owner = proxy.owner cache_key = [proxy.name, proxy.cache_signature] cache = owner._pipeloader_batch_scope_cache return cache[cache_key] if cache.key?(cache_key) siblings = relevant_siblings(proxy) grouped = run(proxy, siblings) siblings.each do |sibling| sibling._pipeloader_batch_scope_cache[cache_key] = grouped[sibling.send(proxy.owner_key)] end grouped[owner.send(proxy.owner_key)] end |
.relevant_siblings(proxy) ⇒ Object
27 28 29 30 31 32 |
# File 'lib/pipeloader/batch/batch_loader.rb', line 27 def relevant_siblings(proxy) owner = proxy.owner siblings = owner._pipeloader_batch_context.all(owner.class).select(&:persisted?) siblings << owner if owner.persisted? && siblings.none? { |sibling| sibling.equal?(owner) } siblings end |
.run(proxy, siblings) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/pipeloader/batch/batch_loader.rb', line 34 def run(proxy, siblings) foreign_key = proxy.foreign_key ids = siblings.map { |sibling| sibling.send(proxy.owner_key) }.compact.uniq grouped = Hash.new { |hash, key| hash[key] = [] } return grouped if ids.empty? scope = proxy.relation.where(foreign_key => ids) # A custom .select must still include the FK so we can partition the rows. scope = scope.select(foreign_key) if scope.select_values.any? scope.to_a.each { |record| grouped[record[foreign_key]] << record } apply_window!(grouped, proxy) if proxy.limit_value || proxy.offset_value grouped end |