SpeciesFileGroup/taxonworks

View on GitHub
lib/queries/concerns/users.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Helpers for queries that reference created/updated fields
#
# !! You must have `#base_query` defined in the module to use this concern
# !! You must call set_user_dates in initialize()
# * TODO: Isolate code to a gem
# * TODO: validate User/Project relationships
#
# Concern specs are in
#   spec/lib/queries/person/filter_spec.rb
#   spec/lib/queries/collection_object/filter_spec.rb (housekeeping extensions)
module Queries::Concerns::Users

  extend ActiveSupport::Concern

  def self.params
    [
      :user_id,
      :user_target,
      :user_date_start,
      :user_date_end,
      :updated_since,
      :extend_housekeeping,
      user_id: [],
    ]
  end

  included do

    # @param user_id [Array, Integer, String, nil]
    # @return [Array]
    attr_accessor :user_id

    # @return 'String'
    #   one of 'updated', 'created'
    attr_accessor :user_target

    # @param user_date_start [String]
    #  In format 'yyyy-mm-dd'
    attr_accessor :user_date_start

    # @return [String, nil]
    # @param user_date_end [String]
    #   In format 'yyyy-mm-dd'
    attr_accessor :user_date_end

    # @return [Date, nil]
    # @param updated_since [String] in format yyyy-mm-dd
    #   Records updated (.updated_at) since this date
    attr_accessor :updated_since

    # @return [Boolean, nil]
    # @param extend_housekeeping
    #   if true and pertinent models have 'HOUSEKEEPING_EXTENSIONS = [:relation1, :relation2]'
    #     then include records that have changed in the extended models as well
    attr_accessor :extend_housekeeping

    def user_id
      [@user_id].flatten.compact
    end

    def user_target
      @user_target&.to_s
    end

    def updated_since
      return nil if @updated_since.blank?
      Date.parse(@updated_since)
    end
  end

  def set_user_dates(params)
    @extend_housekeeping = boolean_param(params, :extend_housekeeping)
    @updated_since = params[:updated_since]
    @user_date_end = params[:user_date_end]
    @user_date_start = params[:user_date_start]
    @user_id = params[:user_id]
    @user_target = params[:user_target] # Add validation ?
  end

  def self.merge_clauses
    [ :created_updated_facet ]
  end

  def self.and_clauses
    [ :updated_since_facet ]
  end

  def updated_since_facet
    return nil if updated_since.blank?
    table[:updated_at].gteq(updated_since)
  end

  def created_updated_facet(target: base_query, disable_extension: false)
    return nil if user_id.empty? && user_target.nil? && user_date_start.nil? && user_date_end.nil?

    if !user_date_start.nil? || !user_date_end.nil?
      q = time_scope(target:)
    else
      q = target || base_query
    end

   if !user_id.empty?
     q = user_scope(target: q)
   end

   if !disable_extension && extend_housekeeping && !housekeeping_extensions.empty?
     q = referenced_klass_union( [q] + housekeeping_extensions )
   end

    q
  end

  # Defined in Filters
  def housekeeping_extensions
    []
  end

  # @param target [the joined class]
  # @param joins [Array] to add to join()
  def housekeeping_extension_query(target: nil, joins: [])
    raise 'no target' if target.nil?

    id_name = "hkx_#{target.name.downcase}_id"
    query_name = "query_#{target.name}_hkx"
    tbl = table.name

    b = created_updated_facet(
      target: target.all,
      disable_extension: true
    ).select("id #{id_name}")

    q = referenced_klass
    q = q.joins(joins) if !joins.empty?
    q = q.joins("JOIN #{query_name} as #{query_name}1 on #{query_name}1.#{id_name} = #{target.arel_table.name}.id")

    s = "WITH #{query_name} AS (" + b.to_sql + ') ' + q.to_sql

    referenced_klass.from('(' + s + ") as #{tbl}").distinct
  end

  def time_scope(target: base_query)
    return nil if user_date_start.nil? && user_date_end.nil?

    s, e = Utilities::Dates.normalize_and_order_dates(
      user_date_start,
      user_date_end)

    # TODO: this is ultimately going to require hourly scope
    s += ' 00:00:00' # adjust dates to beginning
    e += ' 23:59:59' # and end of date days

    q = nil

    # handle date range

    # What date?
    if !user_date_start.nil? || !user_date_end.nil?
      case user_target
      when 'updated'
        q = target.updated_in_date_range(s, e)
      when 'created'
        q = target.created_in_date_range(s, e)
      else
        # TODO: UNION !!!
        q = target.updated_in_date_range(s, e).or(target.created_in_date_range(s,e))
      end
    end

    q
  end

  def user_scope(target: base_user)
    return nil if user_id.empty? && user_target.nil?

    q = target

    # handle user_id
    if !user_id.empty?
      case user_target
      when 'updated'
        q = q.where(updated_by_id: user_id)
      when 'created'
        q = q.where(created_by_id: user_id)
      else
        # TODO: UNION
        q = q.where(created_by_id: user_id).or(q.where(updated_by_id: user_id))
      end
    end
    q
  end

end