groupdate 5.1.0 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 163a969c3eb174890b78b4512c6a6631e02722a43f1fbcc30926f3e48cdba461
4
- data.tar.gz: 256ee01a6e991c7513390e8cdf6d27b3e4458018e0980d63e9506bccfc6923d8
3
+ metadata.gz: 448e7901aa2448bca591568110960048d18ac0f21faa5c3cae566fc4a6de30c4
4
+ data.tar.gz: ba242e41103ae9d2542ff0509de1f454f58142957f0da190482769a42a152887
5
5
  SHA512:
6
- metadata.gz: 37093986846259dc59a17187af24097a2ed9d881de6a48ff9a394883e5a936a569fd758daf820cc9444e69212d29548ab21a816f7fac0cba1b7e502ac2d99198
7
- data.tar.gz: d1639375454ed0d1d33600226287a484ae7001c3759446b2c196dd24f1e003f3fce7f0c8f2253d90819bc280260bedfed2fa6f622f24ad46c590c05739177df2
6
+ metadata.gz: 91b008f8ee0d9ad419ec042ee2f417b621fba09793b223705a2898fe21083a09527885ead3be2d3b8003427473d1f996938098c9bd7139bcb9bffdad2810734c
7
+ data.tar.gz: d4eb493bdf4b7f40eda2733003263bee49e62f9f69fb6239bec118d1768ce0630c21244e819147ca6b5b1556a9b5e125ed69748e2ee69d3c325f31a2740a6ec5
@@ -1,3 +1,13 @@
1
+ ## 5.2.1 (2020-09-09)
2
+
3
+ - Improved error message for invalid ranges
4
+ - Fixed bug with date string ranges
5
+
6
+ ## 5.2.0 (2020-09-07)
7
+
8
+ - Added warning for non-attribute argument
9
+ - Added support for beginless and endless ranges in `range` option
10
+
1
11
  ## 5.1.0 (2020-07-30)
2
12
 
3
13
  - 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.begin, @time_range.end]
198
+ else
199
+ ["#{column} #{op} ?", @time_range.end]
200
+ end
201
+ else
202
+ ["#{column} >= ?", @time_range.begin]
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,35 @@ 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
+
145
+ if time_range.is_a?(Range)
146
+ # check types
147
+ [time_range.begin, time_range.end].each do |v|
148
+ case v
149
+ when nil, Date, Time
150
+ # good
151
+ when String
152
+ # TODO raise error in Groupdate 6
153
+ warn "[groupdate] Range bounds should be Date or Time, not #{v.class.name}. This will raise an error in Groupdate 6"
154
+ break
155
+ else
156
+ raise ArgumentError, "Range bounds should be Date or Time, not #{v.class.name}"
157
+ end
158
+ end
159
+
160
+ start = time_range.begin
161
+ start = start.in_time_zone(time_zone) if start
162
+
163
+ exclude_end = time_range.exclude_end?
164
+
165
+ finish = time_range.end
166
+ finish = finish.in_time_zone(time_zone) if finish
167
+ if time_range.end.is_a?(Date) && !exclude_end
168
+ finish += 1.day
169
+ exclude_end = true
170
+ end
171
+
172
+ time_range = Range.new(start, finish, exclude_end)
150
173
  elsif !time_range && options[:last]
151
174
  if period == :quarter
152
175
  step = 3.months
@@ -200,7 +223,7 @@ module Groupdate
200
223
  else
201
224
  time_range = self.time_range
202
225
  time_range =
203
- if time_range.is_a?(Range)
226
+ if time_range.is_a?(Range) && time_range.begin && time_range.end
204
227
  time_range
205
228
  else
206
229
  # use first and last values
@@ -211,11 +234,23 @@ module Groupdate
211
234
  data.keys.sort
212
235
  end
213
236
 
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)
237
+ if time_range.is_a?(Range)
238
+ if sorted_keys.any?
239
+ if time_range.begin
240
+ time_range.begin..sorted_keys.last
241
+ else
242
+ Range.new(sorted_keys.first, time_range.end, time_range.exclude_end?)
243
+ end
244
+ else
245
+ nil..nil
246
+ end
247
+ else
248
+ tr = sorted_keys.first..sorted_keys.last
249
+ if options[:current] == false && sorted_keys.any? && round_time(now) >= tr.last
250
+ tr = tr.first...round_time(now)
251
+ end
252
+ tr
217
253
  end
218
- tr
219
254
  end
220
255
 
221
256
  if time_range.begin
@@ -1,3 +1,3 @@
1
1
  module Groupdate
2
- VERSION = "5.1.0"
2
+ VERSION = "5.2.1"
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.1
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-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport