# frozen_string_literal: true class Trends::History include Enumerable class Aggregate include Redisable def initialize(prefix, id, date_range) @days = date_range.map { |date| Day.new(prefix, id, date.to_time(:utc)) } end def uses redis.mget(*@days.map { |day| day.key_for(:uses) }).map(&:to_i).sum end def accounts redis.pfcount(*@days.map { |day| day.key_for(:accounts) }) end end class Day include Redisable EXPIRE_AFTER = 14.days.seconds def initialize(prefix, id, day) @prefix = prefix @id = id @day = day.beginning_of_day end attr_reader :day def accounts redis.pfcount(key_for(:accounts)) end def uses redis.get(key_for(:uses))&.to_i || 0 end def add(account_id) redis.pipelined do redis.incrby(key_for(:uses), 1) redis.pfadd(key_for(:accounts), account_id) redis.expire(key_for(:uses), EXPIRE_AFTER) redis.expire(key_for(:accounts), EXPIRE_AFTER) end end def as_json { day: day.to_i.to_s, accounts: accounts.to_s, uses: uses.to_s } end def key_for(suffix) case suffix when :accounts "#{key_prefix}:#{suffix}" when :uses key_prefix end end def key_prefix "activity:#{@prefix}:#{@id}:#{day.to_i}" end end def initialize(prefix, id) @prefix = prefix @id = id end def get(date) Day.new(@prefix, @id, date) end def add(account_id, at_time = Time.now.utc) Day.new(@prefix, @id, at_time).add(account_id) end def aggregate(date_range) Aggregate.new(@prefix, @id, date_range) end def each(&block) if block_given? (0...7).map { |i| block.call(get(i.days.ago)) } else to_enum(:each) end end def as_json(*) map(&:as_json) end end