Class: GoodJob::PerformanceRange
- Inherits:
-
Object
- Object
- GoodJob::PerformanceRange
- Defined in:
- app/charts/good_job/performance_range.rb
Constant Summary collapse
- PARAMETER_KEYS =
%w[chart_range chart_start chart_end].freeze
- TIME_ZONE_PARAMETER_KEY =
"chart_time_zone"- INPUT_PARAMETER_KEYS =
[*PARAMETER_KEYS, TIME_ZONE_PARAMETER_KEY].freeze
- DEFAULT_KEY =
"24h"- MAXIMUM_TIME_SERIES_COORDINATES =
30- MAXIMUM_TIME_ZONE_LENGTH =
255- MINIMUM_YEAR =
Restrict custom bounds to portable four-digit years in the timezone used by the page.
1000- MAXIMUM_YEAR =
9999- MINIMUM_LOCAL_VALUE =
"1000-01-01T00:00:00"- MAXIMUM_LOCAL_VALUE =
"9999-12-31T23:59:59"- TIMESTAMP_PATTERN =
/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})\z/- LOCAL_TIMESTAMP_PATTERN =
/\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?\z/- OPTIONS =
{ "1h" => { label: "1h", duration: 1.hour, interval_seconds: 5.minutes.to_i, label_format: "%H:%M", label_style: "time", }, "6h" => { label: "6h", duration: 6.hours, interval_seconds: 15.minutes.to_i, label_format: "%H:%M", label_style: "time", }, "24h" => { label: "24h", duration: 24.hours, interval_seconds: 1.hour.to_i, label_format: "%H:%M", label_style: "time", }, "7d" => { label: "7d", duration: 24.hours * 7, interval_seconds: 6.hours.to_i, label_format: "%b %-d %H:%M", label_style: "date_time", }, }.freeze
- SEMANTIC_INTERVALS =
All candidates become integer seconds. The 30-day and 365-day scales are fixed elapsed durations for readable long-range charts, not calendar month or year aggregation.
[ *[1, 2, 5, 10, 15, 30].map(&:seconds), *[1, 2, 5, 10, 15, 30].map(&:minutes), *[1, 2, 3, 6, 12].map(&:hours), *[1, 2, 3, 5, 7, 14].map(&:days), *[1, 2, 3, 6].map { |multiple| multiple * 30.days }, *[1, 2, 5, 10, 20, 50, 100, 200, 500].map { |multiple| multiple * 365.days }, ].map(&:to_i).uniq.sort.freeze
Instance Attribute Summary collapse
-
#end_time ⇒ Object
readonly
Returns the value of attribute end_time.
-
#interval_seconds ⇒ Object
readonly
Returns the value of attribute interval_seconds.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#label_format ⇒ Object
readonly
Returns the value of attribute label_format.
-
#label_style ⇒ Object
readonly
Returns the value of attribute label_style.
-
#start_time ⇒ Object
readonly
Returns the value of attribute start_time.
Instance Method Summary collapse
- #apply(relation) ⇒ Object
- #canonical_parameters?(query_parameters) ⇒ Boolean
- #canonical_timestamp(timestamp) ⇒ Object
- #chart_timestamp_label(timestamp) ⇒ Object
- #chart_timestamp_labels(timestamps) ⇒ Object
- #custom? ⇒ Boolean
- #custom_params ⇒ Object
- #default? ⇒ Boolean
- #end_label ⇒ Object
- #end_local_value ⇒ Object
-
#initialize(params = nil, query_string: nil, **parameter_keywords) ⇒ PerformanceRange
constructor
A new instance of PerformanceRange.
- #navigation_params ⇒ Object
- #options ⇒ Object
- #reload_params ⇒ Object
- #start_end_binds ⇒ Object
- #start_label ⇒ Object
- #start_local_value ⇒ Object
-
#time_series_binds ⇒ Object
Keep this order in sync with the $1/$2/$3 placeholders in PerformanceIndexChart.
- #time_series_bucket_sql(column_name, start_expression:, interval_expression:) ⇒ Object
- #time_series_coordinate_count ⇒ Object
- #to_params ⇒ Object
Constructor Details
#initialize(params = nil, query_string: nil, **parameter_keywords) ⇒ PerformanceRange
Returns a new instance of PerformanceRange.
63 64 65 66 67 68 |
# File 'app/charts/good_job/performance_range.rb', line 63 def initialize(params = nil, query_string: nil, **parameter_keywords) @params = params || parameter_keywords @repeated_parameter_keys = repeated_parameter_keys(query_string) @local_time_zone = local_time_zone resolve end |
Instance Attribute Details
#end_time ⇒ Object (readonly)
Returns the value of attribute end_time.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def end_time @end_time end |
#interval_seconds ⇒ Object (readonly)
Returns the value of attribute interval_seconds.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def interval_seconds @interval_seconds end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def key @key end |
#label_format ⇒ Object (readonly)
Returns the value of attribute label_format.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def label_format @label_format end |
#label_style ⇒ Object (readonly)
Returns the value of attribute label_style.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def label_style @label_style end |
#start_time ⇒ Object (readonly)
Returns the value of attribute start_time.
61 62 63 |
# File 'app/charts/good_job/performance_range.rb', line 61 def start_time @start_time end |
Instance Method Details
#apply(relation) ⇒ Object
70 71 72 |
# File 'app/charts/good_job/performance_range.rb', line 70 def apply(relation) relation.where(scheduled_at: start_time...end_time) end |
#canonical_parameters?(query_parameters) ⇒ Boolean
74 75 76 |
# File 'app/charts/good_job/performance_range.rb', line 74 def canonical_parameters?(query_parameters) query_parameters.slice(*INPUT_PARAMETER_KEYS) == to_params end |
#canonical_timestamp(timestamp) ⇒ Object
99 100 101 102 103 |
# File 'app/charts/good_job/performance_range.rb', line 99 def () = .in_time_zone # ISO 8601 cannot preserve the sub-minute historical offsets present in some IANA zones. .utc_offset.remainder(60).zero? ? .iso8601 : .utc.iso8601 end |
#chart_timestamp_label(timestamp) ⇒ Object
78 79 80 |
# File 'app/charts/good_job/performance_range.rb', line 78 def () .in_time_zone.strftime(label_format) end |
#chart_timestamp_labels(timestamps) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'app/charts/good_job/performance_range.rb', line 82 def () labels = .map { || () } labels.each_index.group_by { |index| labels[index] }.each_value do |indices| next unless indices.many? offsets = indices.map { |index| [index].in_time_zone.formatted_offset } next unless offsets.uniq.many? indices.zip(offsets).each do |index, offset| labels[index] = "#{labels[index]} #{offset}" end end labels end |
#custom? ⇒ Boolean
105 106 107 |
# File 'app/charts/good_job/performance_range.rb', line 105 def custom? key.nil? end |
#custom_params ⇒ Object
109 110 111 112 113 114 |
# File 'app/charts/good_job/performance_range.rb', line 109 def custom_params { "chart_start" => (start_time), "chart_end" => (end_time), } end |
#default? ⇒ Boolean
116 117 118 |
# File 'app/charts/good_job/performance_range.rb', line 116 def default? to_params.empty? end |
#end_label ⇒ Object
120 121 122 |
# File 'app/charts/good_job/performance_range.rb', line 120 def end_label range_label(end_time) end |
#end_local_value ⇒ Object
124 125 126 |
# File 'app/charts/good_job/performance_range.rb', line 124 def end_local_value local_value(end_time) end |
#navigation_params ⇒ Object
128 129 130 131 132 133 134 135 136 137 |
# File 'app/charts/good_job/performance_range.rb', line 128 def return to_params unless key # A preset is a relative definition; navigation also carries this evaluated instance. { "chart_range" => key, "chart_start" => (start_time), "chart_end" => (end_time), } end |
#options ⇒ Object
139 140 141 |
# File 'app/charts/good_job/performance_range.rb', line 139 def OPTIONS.map { |option_key, option| { key: option_key, label: option.fetch(:label) } } end |
#reload_params ⇒ Object
143 144 145 146 147 |
# File 'app/charts/good_job/performance_range.rb', line 143 def reload_params return to_params if custom? || default? { "chart_range" => key } end |
#start_end_binds ⇒ Object
149 150 151 152 153 154 |
# File 'app/charts/good_job/performance_range.rb', line 149 def start_end_binds [ query_attribute("start_time", start_time, ActiveRecord::Type::DateTime.new), query_attribute("end_time", end_time, ActiveRecord::Type::DateTime.new), ] end |
#start_label ⇒ Object
156 157 158 |
# File 'app/charts/good_job/performance_range.rb', line 156 def start_label range_label(start_time) end |
#start_local_value ⇒ Object
160 161 162 |
# File 'app/charts/good_job/performance_range.rb', line 160 def start_local_value local_value(start_time) end |
#time_series_binds ⇒ Object
Keep this order in sync with the $1/$2/$3 placeholders in PerformanceIndexChart.
165 166 167 168 169 170 171 |
# File 'app/charts/good_job/performance_range.rb', line 165 def time_series_binds [ query_attribute("series_start_time", series_start_time, ActiveRecord::Type::DateTime.new), query_attribute("series_end_time", series_end_time, ActiveRecord::Type::DateTime.new), query_attribute("interval_seconds", interval_seconds, ActiveRecord::Type::Integer.new(limit: 8)), ] end |
#time_series_bucket_sql(column_name, start_expression:, interval_expression:) ⇒ Object
173 174 175 176 177 178 179 180 181 |
# File 'app/charts/good_job/performance_range.rb', line 173 def time_series_bucket_sql(column_name, start_expression:, interval_expression:) column_sql = GoodJob::Job.adapter_class.quote_column_name(column_name) <<~SQL.squish #{start_expression} + FLOOR(EXTRACT(EPOCH FROM (#{column_sql} - #{start_expression})) / #{interval_expression}) * #{interval_expression} * INTERVAL '1 second' SQL end |
#time_series_coordinate_count ⇒ Object
183 184 185 |
# File 'app/charts/good_job/performance_range.rb', line 183 def time_series_coordinate_count coordinate_count(interval_seconds) end |
#to_params ⇒ Object
187 188 189 |
# File 'app/charts/good_job/performance_range.rb', line 187 def to_params @canonical_params.dup end |