Class: Pluckr::Batch

Inherits:
Object
  • Object
show all
Defined in:
lib/pluckr/batch.rb

Overview

Runs several unrelated aggregates over ActiveRecord relations in one statement:

stats = Pluckr.batch do |b|
b.count  user.videos,                        as: :video_count
b.sum    user.videos.where(size: 100..), :size, as: :big_video_bytes
b.exists user.photos,                        as: :has_photos
b.avg    user.videos, :size,                 as: :average_size
b.count  Account.active,                     as: :active_accounts
end

stats.video_count  # => 3

Each entry is whatever SQL the relation already compiles to, so default scopes, association scopes, :through, polymorphic and STI conditions are respected - ActiveRecord applied them before Pluckr saw the relation.

This is the ad-hoc counterpart to Pluckr::Query: no class, no reuse, and bound to concrete records rather than to a row of a result set.

Constant Summary collapse

IGNORED_RELATION_VALUES =

Eager loading is pointless inside a scalar aggregate subquery and joining the associated tables can change the row count; row locks are not allowed alongside an aggregate.

%i[includes eager_load preload lock].freeze
COLUMNLESS_OPERATIONS =
%i[count exists].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBatch

Returns a new instance of Batch.



39
40
41
# File 'lib/pluckr/batch.rb', line 39

def initialize
  @nodes = []
end

Class Method Details

.build(&block) ⇒ Object

Raises:



31
32
33
34
35
36
37
# File 'lib/pluckr/batch.rb', line 31

def self.build(&block)
  raise ConfigurationError, "`Pluckr.batch` requires a block" unless block

  batch = new
  block.call(batch)
  batch
end

Instance Method Details

#avg(source, column, as:) ⇒ Object Also known as: average



53
54
55
# File 'lib/pluckr/batch.rb', line 53

def avg(source, column, as:)
  add(:avg, source, column, as)
end

#count(source, column = nil, as:) ⇒ Object

---------------------------------------------------------------- DSL --



45
46
47
# File 'lib/pluckr/batch.rb', line 45

def count(source, column = nil, as:)
  add(:count, source, column, as)
end

#entriesObject



85
86
87
# File 'lib/pluckr/batch.rb', line 85

def entries
  @nodes.map(&:output)
end

#exists(source, as:) ⇒ Object



66
67
68
# File 'lib/pluckr/batch.rb', line 66

def exists(source, as:)
  add(:exists, source, nil, as)
end

#fetchObject



76
77
78
79
80
81
82
83
# File 'lib/pluckr/batch.rb', line 76

def fetch
  scope = schema
  compiler = Compiler::Sql.new(schema: scope)
  row = Pluckr.select_all(compiler.connection, compiler.aggregate_only_sql,
                          name: "Pluckr::Batch", label: "Pluckr Batch").first

  Result::Builder.new(scope, label: "Pluckr::Batch").build(row)
end

#inspectObject



89
90
91
# File 'lib/pluckr/batch.rb', line 89

def inspect
  "#<Pluckr::Batch #{entries.join(", ")}>"
end

#max(source, column, as:) ⇒ Object



62
63
64
# File 'lib/pluckr/batch.rb', line 62

def max(source, column, as:)
  add(:max, source, column, as)
end

#min(source, column, as:) ⇒ Object



58
59
60
# File 'lib/pluckr/batch.rb', line 58

def min(source, column, as:)
  add(:min, source, column, as)
end

#sum(source, column, as:) ⇒ Object



49
50
51
# File 'lib/pluckr/batch.rb', line 49

def sum(source, column, as:)
  add(:sum, source, column, as)
end

#to_sqlObject

----------------------------------------------------------- execution --



72
73
74
# File 'lib/pluckr/batch.rb', line 72

def to_sql
  compiler.aggregate_only_sql
end