lib/groupdate/series_builder.rb in groupdate-4.0.2 vs lib/groupdate/series_builder.rb in groupdate-4.1.0
- old
+ new
@@ -1,15 +1,18 @@
module Groupdate
class SeriesBuilder
attr_reader :period, :time_zone, :day_start, :week_start, :options
+ CHECK_PERIODS = [:day, :week, :month, :quarter, :year]
+
def initialize(period:, time_zone:, day_start:, week_start:, **options)
@period = period
@time_zone = time_zone
@week_start = week_start
@day_start = day_start
@options = options
+ @round_time = {}
end
def generate(data, default_value:, series_default: true, multiple_groups: false, group_index: nil)
series = generate_series(data, multiple_groups, group_index)
series = handle_multiple(data, series, multiple_groups, group_index)
@@ -17,26 +20,37 @@
unless entire_series?(series_default)
series = series.select { |k| data[k] }
end
value = 0
- Hash[series.map do |k|
- value = data[k] || (@options[:carry_forward] && value) || default_value
+ result = Hash[series.map do |k|
+ value = data.delete(k) || (@options[:carry_forward] && value) || default_value
key =
if multiple_groups
k[0...group_index] + [key_format.call(k[group_index])] + k[(group_index + 1)..-1]
else
key_format.call(k)
end
[key, value]
end]
+
+ # only check for database
+ # only checks remaining keys to avoid expensive calls to round_time
+ if series_default && CHECK_PERIODS.include?(period)
+ check_consistent_time_zone_info(data, multiple_groups, group_index)
+ end
+
+ result
end
def round_time(time)
- time = time.to_time.in_time_zone(time_zone) - day_start.seconds
+ time = time.to_time.in_time_zone(time_zone)
+ # only if day_start != 0 for performance
+ time -= day_start.seconds if day_start != 0
+
time =
case period
when :second
time.change(usec: 0)
when :minute
@@ -67,11 +81,14 @@
time.month
else
raise Groupdate::Error, "Invalid period"
end
- time.is_a?(Time) ? time + day_start.seconds : time
+ # only if day_start != 0 for performance
+ time += day_start.seconds if day_start != 0 && time.is_a?(Time)
+
+ time
end
def time_range
@time_range ||= begin
time_range = options[:range]
@@ -155,11 +172,15 @@
else
step = 1.send(period)
end
last_step = series.last
- while (next_step = round_time(last_step + step)) && time_range.cover?(next_step)
+ loop do
+ next_step = last_step + step
+ next_step = round_time(next_step) if next_step.hour != 0 # add condition to speed up
+ break unless time_range.cover?(next_step)
+
if next_step == last_step
last_step += step
next
end
series << next_step
@@ -216,9 +237,24 @@
end
elsif reverse
series.to_a.reverse
else
series
+ end
+ end
+
+ def check_consistent_time_zone_info(data, multiple_groups, group_index)
+ keys = data.keys
+ if multiple_groups
+ keys.map! { |k| k[group_index] }
+ keys.uniq!
+ end
+
+ keys.each do |key|
+ if key != round_time(key)
+ # only need to show what database returned since it will cast in Ruby time zone
+ raise Groupdate::Error, "Database and Ruby have inconsistent time zone info. Database returned #{key}"
+ end
end
end
def entire_series?(series_default)
options.key?(:series) ? options[:series] : series_default