Class: Pipeloader::Batch::Relationship
- Inherits:
-
Object
- Object
- Pipeloader::Batch::Relationship
- Defined in:
- lib/pipeloader/batch/relationship.rb
Overview
Builds the pieces an aggregate Fetcher needs: a ‘getter` (the owner key read off each sibling), a `loader` lambda (one GROUP BY query returning a { key => scalar } hash), and a `default` for keys with no rows.
The child class and keys are resolved with this precedence:
explicit option > AR reflection (if the source names a real association) > convention.
The target class constant is resolved lazily so autoload order doesn’t matter.
Instance Attribute Summary collapse
-
#default ⇒ Object
readonly
Returns the value of attribute default.
-
#getter ⇒ Object
readonly
Returns the value of attribute getter.
-
#loader ⇒ Object
readonly
Returns the value of attribute loader.
Class Method Summary collapse
- .aggregate(owner, name, of:, function:, column:, class_name:, foreign_key:, primary_key:, default:) ⇒ Object
-
.child_keys(owner, assoc_name, class_name, foreign_key, primary_key) ⇒ Object
Resolve [class-resolver, foreign-key, owner-getter] for a has_many-style source rooted at ‘assoc_name` on `owner`.
-
.class_resolver(class_name, reflection, &convention) ⇒ Object
Memoized lambda producing the target class constant.
-
.default_source(name, function) ⇒ Object
For ‘batch_count :books_count`, derive the source association (“books”) by stripping the function suffix when present.
Instance Method Summary collapse
-
#initialize(getter, loader, default) ⇒ Relationship
constructor
A new instance of Relationship.
Constructor Details
#initialize(getter, loader, default) ⇒ Relationship
Returns a new instance of Relationship.
61 62 63 64 65 |
# File 'lib/pipeloader/batch/relationship.rb', line 61 def initialize(getter, loader, default) @getter = getter @loader = loader @default = default end |
Instance Attribute Details
#default ⇒ Object (readonly)
Returns the value of attribute default.
15 16 17 |
# File 'lib/pipeloader/batch/relationship.rb', line 15 def default @default end |
#getter ⇒ Object (readonly)
Returns the value of attribute getter.
15 16 17 |
# File 'lib/pipeloader/batch/relationship.rb', line 15 def getter @getter end |
#loader ⇒ Object (readonly)
Returns the value of attribute loader.
15 16 17 |
# File 'lib/pipeloader/batch/relationship.rb', line 15 def loader @loader end |
Class Method Details
.aggregate(owner, name, of:, function:, column:, class_name:, foreign_key:, primary_key:, default:) ⇒ Object
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/pipeloader/batch/relationship.rb', line 17 def self.aggregate(owner, name, of:, function:, column:, class_name:, foreign_key:, primary_key:, default:) source = of || default_source(name, function) resolve, fk, getter = child_keys(owner, source, class_name, foreign_key, primary_key) derived = lambda do |ids, _fetcher| scope = resolve.call.where(fk => ids).group(fk) function == :count ? scope.count : scope.public_send(function, column) end new(getter, derived, default) end |
.child_keys(owner, assoc_name, class_name, foreign_key, primary_key) ⇒ Object
Resolve [class-resolver, foreign-key, owner-getter] for a has_many-style source rooted at ‘assoc_name` on `owner`.
30 31 32 33 34 35 36 |
# File 'lib/pipeloader/batch/relationship.rb', line 30 def self.child_keys(owner, assoc_name, class_name, foreign_key, primary_key) reflection = owner.reflect_on_association(assoc_name) fk = (foreign_key || reflection&.foreign_key || owner.model_name.element.foreign_key).to_s getter = (primary_key || reflection&.active_record_primary_key || owner.primary_key).to_sym resolve = class_resolver(class_name, reflection) { assoc_name.to_s.singularize.camelize.constantize } [resolve, fk, getter] end |
.class_resolver(class_name, reflection, &convention) ⇒ Object
Memoized lambda producing the target class constant. The convention block is only used when neither class_name nor a reflection is available.
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/pipeloader/batch/relationship.rb', line 47 def self.class_resolver(class_name, reflection, &convention) resolved = nil lambda do resolved ||= if class_name class_name.to_s.constantize elsif reflection reflection.klass else convention.call end end end |
.default_source(name, function) ⇒ Object
For ‘batch_count :books_count`, derive the source association (“books”) by stripping the function suffix when present.
40 41 42 43 |
# File 'lib/pipeloader/batch/relationship.rb', line 40 def self.default_source(name, function) suffix = "_#{function}" name.to_s.end_with?(suffix) ? name.to_s.delete_suffix(suffix) : name.to_s end |