require "active_reporter/inflector" require "active_reporter/dimension/bin" module ActiveReporter module Dimension class Time < Bin STEPS = %i(seconds minutes hours days weeks months years) BIN_STEPS = (STEPS - [:seconds]).map { |step| step.to_s.singularize(:_gem_active_reporter) } DURATION_PATTERN = /\A\d+ (?:#{STEPS.map{ |step| "#{step}?" }.join("|")})\z/ def validate_params! super invalid_param!(:bin_width, "must be a valid width value or a hash where each hash keys is a valid value and each hash value\n is interger representing the count of the key width\n valid :bin_width values include #{STEPS.to_sentence}.") if params.key?(:bin_width) && !valid_duration?(params[:bin_width]) end def bin_width @bin_width ||= case when params.key?(:bin_width) custom_bin_width when params.key?(:bin_count) && domain > 0 (domain / params[:bin_count].to_f).seconds else default_bin_width end end def bin_start # ensure that each autogenerated bin represents a correctly aligned # day/week/month/year bin_start = super return if bin_start.nil? step = BIN_STEPS.detect { |step| bin_width == 1.send(step) } step.present? ? bin_start.send(:"beginning_of_#{step}") : bin_start end private def custom_bin_width case params[:bin_width] when Hash params[:bin_width].map { |step, n| n.send(step) }.sum when String, Symbol n, step = params[:bin_width].to_s.split.map(&:strip) if step.nil? step = n n = 1 end n.to_i.send(step) end end def valid_duration?(duration) case duration when Hash duration.all? { |step, n| step.to_s.pluralize(:_gem_active_reporter).to_sym.in?(STEPS) && n.is_a?(Numeric) } when String, Symbol duration.to_s.pluralize(:_gem_active_reporter).to_sym.in?(STEPS) || duration =~ DURATION_PATTERN else false end end def default_bin_width case domain when 0 then 1.day when 0..1.minute then 1.second when 0..2.hours then 1.minute when 0..2.days then 1.hour when 0..2.weeks then 1.day when 0..2.months then 1.week when 0..2.years then 1.month else 1.year end end class Set < Bin::Set def parse(value) ::Time.zone.parse(value.to_s.gsub('"', "")) end def cast(value) case ActiveReporter.database_type when :postgres "CAST(#{super} AS timestamp with time zone)" when :sqlite "DATETIME(#{super})" else "CAST(#{super} AS DATETIME)" end end end end end end