Skip to content

Instantly share code, notes, and snippets.

@jparker
Last active December 26, 2015 03:19
Show Gist options
  • Save jparker/7085219 to your computer and use it in GitHub Desktop.
Save jparker/7085219 to your computer and use it in GitHub Desktop.
Representing query parameters as a first-class object that is interchangeable with an ActiveModel object
QuoteReport.new(:quarter, ReportFilter.new)
# => Quote.all
QuoteReport.new(:quarter, Composer.find(42))
# => Composer.find(42).quotes
QuoteReport.new(:quarter, ReportFilter.new(composer_id: 42))
# => Quote.joins(cue: :composer).where(cue: {composer_id: 42})
QuoteReport.new(:quarter, ReportFilter.new(composer_id: [42, 101]))
# => Quote.joins(cue: :composer).where(cue: {composer_id: [42, 101]})
class Composer
has_many :cues
has_many :quotes, through: :cues
end
class Cue
belongs_to :composer
has_many :quotes
end
class Quote
# properties: date => Date, rate => BigDecimal
belongs_to :cue
end
QuoteReport = Struct.new(period, filter) do
def [](date)
data.fetch(date) { 0.to_d }
end
private
def data
@data ||= filter.quotes.group("date_trunc('#{period}', (quotes.date)::timestamp)::date").sum(:rate)
end
end
class ReportFilter
def initialize(parameters = {})
@parameters = parameters
end
def quotes
if @parameters.empty?
Quote.all
else
Quote.joins(:cue).where(cues: @parameters.slice(:composer_id))
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment