groupdate 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 163a969c3eb174890b78b4512c6a6631e02722a43f1fbcc30926f3e48cdba461
4
- data.tar.gz: 256ee01a6e991c7513390e8cdf6d27b3e4458018e0980d63e9506bccfc6923d8
3
+ metadata.gz: 0d18870af57fc18006c5f176fa3138dfe36a715b16e5a6113f447aee6d3b7468
4
+ data.tar.gz: 889870a1a2db8784e28413c6071a784dff66d00b4aaf05a323e70e5d16f09fd8
5
5
  SHA512:
6
- metadata.gz: 37093986846259dc59a17187af24097a2ed9d881de6a48ff9a394883e5a936a569fd758daf820cc9444e69212d29548ab21a816f7fac0cba1b7e502ac2d99198
7
- data.tar.gz: d1639375454ed0d1d33600226287a484ae7001c3759446b2c196dd24f1e003f3fce7f0c8f2253d90819bc280260bedfed2fa6f622f24ad46c590c05739177df2
6
+ metadata.gz: 2ae29a1e8d0eb14c4ef904fbe366cb5f7029d9e94429a74f6f70073a880f2910f62d5161d39618808c09dc937185cc79ba233ac3fc7e34f983a8e32d60e0be70
7
+ data.tar.gz: 6348f6853cf2015f6777bcc63e1e416a31456a0e779678164992bd6424daca73272bb5fcb12016d1f3c085b4e14e991afa067f4f93354982e7229699f3ea2eab
@@ -1,3 +1,8 @@
1
+ ## 5.2.0 (2020-09-07)
2
+
3
+ - Added warning for non-attribute argument
4
+ - Added support for beginless and endless ranges in `range` option
5
+
1
6
  ## 5.1.0 (2020-07-30)
2
7
 
3
8
  - Added `n` option to minute and second for custom durations
data/README.md CHANGED
@@ -60,7 +60,7 @@ and
60
60
  - day_of_year
61
61
  - month_of_year
62
62
 
63
- Use it anywhere you can use `group`. Works with `count`, `sum`, `minimum`, `maximum`, and `average`. For `median`, check out [ActiveMedian](https://github.com/ankane/active_median).
63
+ Use it anywhere you can use `group`. Works with `count`, `sum`, `minimum`, `maximum`, and `average`. For `median` and `percentile`, check out [ActiveMedian](https://github.com/ankane/active_median).
64
64
 
65
65
  ### Time Zones
66
66
 
@@ -47,7 +47,6 @@ module Groupdate
47
47
  # TODO better messages
48
48
  raise ArgumentError, "Unrecognized time zone" unless time_zone
49
49
  raise ArgumentError, "Unrecognized :week_start option" unless week_start
50
- raise ArgumentError, "Cannot use endless range for :range option" if options[:range].is_a?(Range) && !options[:range].end
51
50
  raise ArgumentError, ":day_start must be between 0 and 24" if (day_start / 3600) < 0 || (day_start / 3600) >= 24
52
51
  end
53
52
 
@@ -3,6 +3,9 @@ module Groupdate
3
3
  attr_reader :period, :column, :day_start, :week_start, :n_seconds
4
4
 
5
5
  def initialize(relation, column:, period:, time_zone:, time_range:, week_start:, day_start:, n_seconds:)
6
+ # very important
7
+ validate_column(column)
8
+
6
9
  @relation = relation
7
10
  @column = resolve_column(relation, column)
8
11
  @period = period
@@ -188,13 +191,30 @@ module Groupdate
188
191
 
189
192
  def where_clause
190
193
  if @time_range.is_a?(Range)
191
- op = @time_range.exclude_end? ? "<" : "<="
192
- ["#{column} >= ? AND #{column} #{op} ?", @time_range.first, @time_range.last]
194
+ if @time_range.end
195
+ op = @time_range.exclude_end? ? "<" : "<="
196
+ if @time_range.begin
197
+ ["#{column} >= ? AND #{column} #{op} ?", @time_range.first, @time_range.last]
198
+ else
199
+ ["#{column} #{op} ?", @time_range.last]
200
+ end
201
+ else
202
+ ["#{column} >= ?", @time_range.first]
203
+ end
193
204
  else
194
205
  ["#{column} IS NOT NULL"]
195
206
  end
196
207
  end
197
208
 
209
+ # basic version of Active Record disallow_raw_sql!
210
+ # symbol = column (safe), Arel node = SQL (safe), other = untrusted
211
+ def validate_column(column)
212
+ # matches table.column and column
213
+ unless column.is_a?(Symbol) || column.is_a?(Arel::Nodes::SqlLiteral) || /\A\w+(\.\w+)?\z/i.match(column.to_s)
214
+ warn "[groupdate] Non-attribute argument: #{column}. Use Arel.sql() for known-safe values. This will raise an error in Groupdate 6"
215
+ end
216
+ end
217
+
198
218
  # resolves eagerly
199
219
  # need to convert both where_clause (easy)
200
220
  # and group_clause (not easy) if want to avoid this
@@ -11,7 +11,6 @@ module Groupdate
11
11
  @day_start = day_start
12
12
  @n_seconds = n_seconds
13
13
  @options = options
14
- @round_time = {}
15
14
  @week_start_key = Groupdate::Magic::DAYS[@week_start] if @week_start
16
15
  end
17
16
 
@@ -142,11 +141,16 @@ module Groupdate
142
141
  def time_range
143
142
  @time_range ||= begin
144
143
  time_range = options[:range]
145
- if time_range.is_a?(Range) && time_range.first.is_a?(Date)
146
- # convert range of dates to range of times
147
- last = time_range.last.in_time_zone(time_zone)
148
- last += 1.day unless time_range.exclude_end?
149
- time_range = Range.new(time_range.first.in_time_zone(time_zone), last, true)
144
+ # entire range must be Date if begin or end is Date
145
+ if time_range.is_a?(Range) && (time_range.begin.is_a?(Date) || time_range.end.is_a?(Date))
146
+ if time_range.begin
147
+ start = time_zone.parse(time_range.first.to_s)
148
+ end
149
+ if time_range.end
150
+ last = time_zone.parse(time_range.last.to_s)
151
+ last += 1.day unless time_range.exclude_end?
152
+ end
153
+ time_range = Range.new(start, last, true)
150
154
  elsif !time_range && options[:last]
151
155
  if period == :quarter
152
156
  step = 3.months
@@ -200,7 +204,7 @@ module Groupdate
200
204
  else
201
205
  time_range = self.time_range
202
206
  time_range =
203
- if time_range.is_a?(Range)
207
+ if time_range.is_a?(Range) && time_range.begin && time_range.end
204
208
  time_range
205
209
  else
206
210
  # use first and last values
@@ -211,11 +215,23 @@ module Groupdate
211
215
  data.keys.sort
212
216
  end
213
217
 
214
- tr = sorted_keys.first..sorted_keys.last
215
- if options[:current] == false && sorted_keys.any? && round_time(now) >= tr.last
216
- tr = tr.first...round_time(now)
218
+ if time_range.is_a?(Range)
219
+ if sorted_keys.any?
220
+ if time_range.begin
221
+ time_range.begin..sorted_keys.last
222
+ else
223
+ Range.new(sorted_keys.first, time_range.end, time_range.exclude_end?)
224
+ end
225
+ else
226
+ nil..nil
227
+ end
228
+ else
229
+ tr = sorted_keys.first..sorted_keys.last
230
+ if options[:current] == false && sorted_keys.any? && round_time(now) >= tr.last
231
+ tr = tr.first...round_time(now)
232
+ end
233
+ tr
217
234
  end
218
- tr
219
235
  end
220
236
 
221
237
  if time_range.begin
@@ -1,3 +1,3 @@
1
1
  module Groupdate
2
- VERSION = "5.1.0"
2
+ VERSION = "5.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groupdate
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-31 00:00:00.000000000 Z
11
+ date: 2020-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport