anyone-oslo/pages

View on GitHub
lib/pages_core/archive_finder.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
94%
# frozen_string_literal: true

module PagesCore
  class ArchiveFinder
    def initialize(relation, options = {})
      @relation = relation
      @options = options
    end

    def by_year(year)
      filter_by_time(range_for_year(year))
    end

    def by_year_and_maybe_month(year, month = nil)
      return by_year(year) unless month

      by_year_and_month(year, month)
    end

    def by_year_and_month(year, month)
      filter_by_time(range_for_year_and_month(year, month))
    end

    def latest_year
      latest_year_and_month&.first
    end

    def latest_year_and_month
      ordered_relation.first.try do |record|
        [record[timestamp_attribute].year,
         record[timestamp_attribute].month]
      end
    end

    def months_in_year(year)
      select_months(by_year(year)).map(&:to_i).sort
    end

    def months_in_year_with_count(year)
      group_by_month(by_year(year))
        .count
        .to_a
        .sort_by(&:first)
    end

    def timestamp_attribute
      @options[:timestamp] || :created_at
    end

    def years
      select_years(@relation).map(&:to_i).sort
    end

    def years_with_count
      years.map { |year| [year, by_year(year).count] }
    end

    private

    def group_by_month(relation)
      relation.reorder("").group(Arel.sql(month_part))
    end

    def filter_by_time(range)
      @relation.where(
        "#{timestamp_attribute} >= ? AND #{timestamp_attribute} <= ?",
        range.first,
        range.last
      )
    end

    def month_part
      "date_part('month', #{timestamp_attribute})::integer"
    end

    def range_for_year(year)
      start_time = Time.zone.local(year.to_i, 1, 1)
      end_time = start_time.end_of_year
      (start_time.in_time_zone)..(end_time.in_time_zone)
    end

    def range_for_year_and_month(year, month)
      start_time = Time.zone.local(year.to_i, month, 1)
      end_time = start_time.end_of_month
      (start_time.in_time_zone)..(end_time.in_time_zone)
    end

    def select_months(relation)
      relation.reorder("").pluck(Arel.sql("DISTINCT #{month_part}"))
    end

    def select_years(relation)
      relation.reorder("").pluck(Arel.sql("DISTINCT #{year_part}"))
    end

    def ordered_relation
      @relation.reorder("#{timestamp_attribute} DESC")
    end

    def year_part
      "date_part('year', #{timestamp_attribute})"
    end
  end
end