class Insights::API::Common::PaginatedResponseV2

Constants

ASSOCIATION_COUNT_ATTR

GraphQL name regex: /[_A-Za-z]*/

Attributes

limit[R]
offset[R]
sort_by[R]

Public Instance Methods

compact_parameter(param) click to toggle source

Condenses parameter values for handling multi-level associations and returns an array of key, value pairs.

Examples:

Input: { “association” => { “attribute” => “value” }, “direct_attribute” => “value2” } Output: [[“association.attribute”, “value”], [“direct_attribute”, “value2”]]

Input: { “association” => { “attribute” => “value” }, “association2” => { “attribute2” => “value2” } } Output: [[“association.attribute”, “value”], [“association2.attribute2”, “value2”]]

Input: { “association” => { “attribute1” => “value1”, “attribute2” => “value2” } } Output: [[“association.attribute1”, “value1”], [“association.attribute2”, “value2”]]

# File lib/insights/api/common/paginated_response_v2.rb, line 39
def compact_parameter(param)
  result = []
  return result if param.blank?

  param.each do |k, v|
    result += if v.kind_of?(Hash) || v.kind_of?(ActionController::Parameters)
                Hash(v).map { |ak, av| ["#{k}.#{ak}", av] }
              else
                [[k, v]]
              end
  end
  result
end
records() click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 10
def records
  @records ||= begin
    res = @base_query.order(:id).limit(limit).offset(offset)

    select_for_associations, group_by_associations = sort_by_associations_query_parameters
    res = res.select(*select_for_associations)          if select_for_associations.present?
    res = res.left_outer_joins(*sort_by_associations)   if sort_by_associations.present?
    res = res.group(group_by_associations)              if group_by_associations.present?

    order_options = sort_by_options(res.klass)
    res = res.reorder(order_options) if order_options.present?
    res
  end
end

Private Instance Methods

sort_by_associations() click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 75
def sort_by_associations
  @sort_by_associations ||= begin
    compact_parameter(sort_by).collect do |sort_attr, sort_order|
      next unless sort_attr.include?('.')

      sort_attr.split('.').first.to_sym
    end.compact.uniq
  end
end
sort_by_associations_query_parameters() click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 85
def sort_by_associations_query_parameters
  select_for_associations = []
  group_by_associations   = []
  count_selects           = []

  compact_parameter(sort_by).each do |sort_attr, _sort_order|
    next unless sort_attr.include?('.')

    association, attr = sort_attr.split('.')

    base_id  = "#{@base_query.table_name}.id"
    base_all = "#{@base_query.table_name}.*"
    select_for_associations << base_id << base_all if select_for_associations.empty?
    group_by_associations   << base_id << base_all if group_by_associations.empty?

    if attr == ASSOCIATION_COUNT_ATTR
      count_selects << Arel.sql("COUNT (#{association.classify.constantize.table_name}.id)")
    else
      arel_attr = association.classify.constantize.arel_attribute(attr)
      association_attr = "#{association}_#{attr}"
      select_for_associations << arel_attr.as(association_attr)
      group_by_associations   << association_attr
    end
  end
  select_for_associations.append(*count_selects) unless count_selects.empty?

  [select_for_associations.compact.uniq, group_by_associations.compact.uniq]
end
sort_by_options(model) click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 55
def sort_by_options(model)
  @sort_by_options ||= begin
    compact_parameter(sort_by).collect do |sort_attr, sort_order|
      sort_order = "asc" if sort_order.blank?
      arel = if sort_attr.include?('.')
               association, sort_attr = sort_attr.split('.')
               association_class = association.classify.constantize
               if sort_attr == ASSOCIATION_COUNT_ATTR
                 Arel.sql("COUNT (#{association_class.table_name}.id)")
               else
                 association_class.arel_attribute(sort_attr)
               end
             else
               model.arel_attribute(sort_attr)
             end
      (sort_order == "desc") ? arel.desc : arel.asc
    end
  end
end
validate_sort_by() click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 114
def validate_sort_by
  return unless sort_by.present?
  raise ArgumentError, "Invalid sort_by parameter specified \"#{sort_by}\"" unless sort_by.kind_of?(ActionController::Parameters) || sort_by.kind_of?(Hash)

  compact_parameter(sort_by).each { |sort_attr, sort_order| validate_sort_by_directive(sort_attr, sort_order) }
end
validate_sort_by_directive(sort_attr, sort_order) click to toggle source
# File lib/insights/api/common/paginated_response_v2.rb, line 121
def validate_sort_by_directive(sort_attr, sort_order)
  order = sort_order.blank? ? "asc" : sort_order
  raise ArgumentError, "Invalid sort_by directive specified \"#{sort_attr}=#{sort_order}\"" unless sort_attr.match?(/^[a-z\-_\.]+$/) && order.match?(/^(asc|desc)$/)
end