app/interactors/api/filter_events.rb

Summary

Maintainability
A
35 mins
Test Coverage
require 'role_playing'
require 'interpipe/interactor'
require 'core_ext/then'
require 'corefines'
require 'axiom/types'
require 'virtus'

require 'date_filtered_dataset'

module Interactors
  module Api
    ##
    # Filters events by page (offset, limit)
    # also depending on a requested format.
    class FilterEvents
      include RolePlaying::Context
      include Interpipe::Interactor

      using Corefines::Hash[:only, :rekey]
      using Sequel::CoreRefinements

      attr_reader :events

      def perform(events: , params: {}, format: :jsonapi)
        @format = format

        # XXX: This is a hack for backward compatibility. Parameter "deleted"
        # used to be a Boolean and we added additional value "all".
        # In next version of API, "cancelled" and "deleted" should be two
        # separate parameters.
        param_deleted = coerce_param_deleted(params[:deleted])
        @deleted = param_deleted == :all
        @cancelled = @deleted || param_deleted

        @type = params[:event_type]
        @events = DateFilteredDataset.played_by(events) do |dataset|
          dataset
            .filter_by_date(**params.only(:from, :to, :with_original_date).to_h.rekey!)
            .then_if(hide_deleted?) { |q|
              # XXX: Temporary(?) hack until separate "cancelled" attribute is added.
              if hide_cancelled?
                q.where(deleted: false)
              else
                q.where('deleted IS FALSE OR deleted IS TRUE AND applied_schedule_exception_ids IS NOT NULL'.lit)
              end
            }
            .then_if(@type) { |q| q.where(event_type: @type) }
            .then { |q| q.order(:starts_at, :id) }
        end
      end

      def to_h
        { events: events }
      end

      protected

      # @param value [String]
      # @return [Boolean|Symbol] true, false, or :all
      def coerce_param_deleted(value)
        return false if value.nil?
        return :all if value.to_s.downcase == 'all'
        @boolean_coercer ||= Virtus::Attribute.build(Axiom::Types::Boolean)
        @boolean_coercer.coerce(value)
      end

      private

      def hide_cancelled?
        (@format == :ical) || !@cancelled
      end

      def hide_deleted?
        (@format == :ical) || !@deleted
      end

    end
  end
end