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 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 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Pues lo voy a sacar a una gema, no?