Last active
August 29, 2015 14:01
-
-
Save vierarb/8a69f04b2fe009a78a0d to your computer and use it in GitHub Desktop.
Metaprogramming the metrics
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# coach = Coach.first | |
# coach.sessions_count(:started_at) | |
# coach.coachees_count(:created_at) | |
# coach.sessions_sum(:price, :started_at) | |
class Coach < ActiveRecord::Base | |
include Metric | |
metrics_for :sessions, :coachees | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Metric | |
extend ActiveSupport::Concern | |
module ClassMethods | |
def metrics_for(*tables) | |
tables.each do |table| | |
define_method("#{table}_count") do |column, options = {}| | |
send(:count, table, column, options) | |
end | |
define_method("#{table}_sum") do |field, column, options = {}| | |
send(:sum, table, column, field, options) | |
end | |
end | |
end | |
end | |
extend ClassMethods | |
private | |
def count(table, column, options) | |
aggregate = 'count(id)' | |
find(table, column, aggregate, options) | |
end | |
def sum(table, field, column, options) | |
aggregate = "sum(#{field})" | |
find(table, column, aggregate, options) | |
end | |
def find(table, column, aggregate, options = {}) | |
period, quantity = format_period(options[:period]) | |
options = options.merge(id: id, | |
period: period, | |
quantity: quantity, | |
where: "#{self.class.name.downcase}_id") | |
query = sql(table, column, aggregate, options) | |
ActiveRecord::Base.connection.execute(query) | |
end | |
def format_period(period) | |
if period =~ /\A(\d+\s(week|month|year))\z/ | |
[$2, $1] | |
else | |
['month', '1 month'] | |
end | |
end | |
def sql(table, column, aggregate, options) | |
%Q{ | |
WITH results AS | |
( | |
SELECT | |
#{aggregate} AS amount, | |
date_trunc('#{options[:period]}', #{column}) AS date | |
FROM #{table} | |
WHERE #{options[:where]} = #{options[:id]} | |
GROUP BY date | |
) | |
SELECT date, COALESCE(sum(amount), 0) AS amount | |
FROM | |
( | |
SELECT | |
generate_series( | |
min(date), max(date), '#{options[:quantity]}' | |
) | |
AS date | |
FROM results | |
) x | |
LEFT JOIN results | |
USING (date) | |
GROUP BY date | |
ORDER BY date DESC | |
} | |
end | |
end |
oinak
commented
May 12, 2014
There are two lines that contradict each other. Line 8 states that |column = nil|
while line 47 states that 'First argument (column) must be present'
. Get the conditional lines out and just remove the = nil
part from line 8.
Pues lo voy a sacar a una gema, no?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment