130 lines
3.1 KiB
Ruby
130 lines
3.1 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
class PrometheusMetricsFinder
|
||
|
ACCEPTED_PARAMS = [
|
||
|
:project,
|
||
|
:group,
|
||
|
:title,
|
||
|
:y_label,
|
||
|
:identifier,
|
||
|
:id,
|
||
|
:common,
|
||
|
:ordered
|
||
|
].freeze
|
||
|
|
||
|
# Cautiously preferring a memoized class method over a constant
|
||
|
# so that the DB connection is accessed after the class is loaded.
|
||
|
def self.indexes
|
||
|
@indexes ||= PrometheusMetric
|
||
|
.connection
|
||
|
.indexes(:prometheus_metrics)
|
||
|
.map { |index| index.columns.map(&:to_sym) }
|
||
|
end
|
||
|
|
||
|
def initialize(params = {})
|
||
|
@params = params.slice(*ACCEPTED_PARAMS)
|
||
|
end
|
||
|
|
||
|
# @return [PrometheusMetric, PrometheusMetric::ActiveRecord_Relation]
|
||
|
def execute
|
||
|
validate_params!
|
||
|
|
||
|
metrics = by_project(::PrometheusMetric.all)
|
||
|
metrics = by_group(metrics)
|
||
|
metrics = by_title(metrics)
|
||
|
metrics = by_y_label(metrics)
|
||
|
metrics = by_common(metrics)
|
||
|
metrics = by_ordered(metrics)
|
||
|
metrics = by_identifier(metrics)
|
||
|
metrics = by_id(metrics)
|
||
|
|
||
|
metrics
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
attr_reader :params
|
||
|
|
||
|
def by_project(metrics)
|
||
|
return metrics unless params[:project]
|
||
|
|
||
|
metrics.for_project(params[:project])
|
||
|
end
|
||
|
|
||
|
def by_group(metrics)
|
||
|
return metrics unless params[:group]
|
||
|
|
||
|
metrics.for_group(params[:group])
|
||
|
end
|
||
|
|
||
|
def by_title(metrics)
|
||
|
return metrics unless params[:title]
|
||
|
|
||
|
metrics.for_title(params[:title])
|
||
|
end
|
||
|
|
||
|
def by_y_label(metrics)
|
||
|
return metrics unless params[:y_label]
|
||
|
|
||
|
metrics.for_y_label(params[:y_label])
|
||
|
end
|
||
|
|
||
|
def by_common(metrics)
|
||
|
return metrics unless params[:common]
|
||
|
|
||
|
metrics.common
|
||
|
end
|
||
|
|
||
|
def by_ordered(metrics)
|
||
|
return metrics unless params[:ordered]
|
||
|
|
||
|
metrics.ordered
|
||
|
end
|
||
|
|
||
|
def by_identifier(metrics)
|
||
|
return metrics unless params[:identifier]
|
||
|
|
||
|
metrics.for_identifier(params[:identifier])
|
||
|
end
|
||
|
|
||
|
def by_id(metrics)
|
||
|
return metrics unless params[:id]
|
||
|
|
||
|
metrics.id_in(params[:id])
|
||
|
end
|
||
|
|
||
|
def validate_params!
|
||
|
validate_params_present!
|
||
|
validate_id_params!
|
||
|
validate_indexes!
|
||
|
end
|
||
|
|
||
|
# Ensure all provided params are supported
|
||
|
def validate_params_present!
|
||
|
raise ArgumentError, "Please provide one or more of: #{ACCEPTED_PARAMS}" if params.blank?
|
||
|
end
|
||
|
|
||
|
# Protect against the caller "finding" the wrong metric
|
||
|
def validate_id_params!
|
||
|
raise ArgumentError, 'Only one of :identifier, :id is permitted' if params[:identifier] && params[:id]
|
||
|
raise ArgumentError, ':identifier must be scoped to a :project or :common' if params[:identifier] && !(params[:project] || params[:common])
|
||
|
end
|
||
|
|
||
|
# Protect against unaccounted-for, complex/slow queries.
|
||
|
# This is not a hard and fast rule, but is meant to encourage
|
||
|
# mindful inclusion of new queries.
|
||
|
def validate_indexes!
|
||
|
indexable_params = params.except(:ordered, :id, :project).keys
|
||
|
indexable_params << :project_id if params[:project]
|
||
|
indexable_params.sort!
|
||
|
|
||
|
raise ArgumentError, "An index should exist for params: #{indexable_params}" unless appropriate_index?(indexable_params)
|
||
|
end
|
||
|
|
||
|
def appropriate_index?(indexable_params)
|
||
|
return true if indexable_params.blank?
|
||
|
|
||
|
self.class.indexes.any? { |index| (index - indexable_params).empty? }
|
||
|
end
|
||
|
end
|