groupdate 1.0.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +6 -0
- data/README.md +53 -147
- data/lib/groupdate.rb +2 -2
- data/lib/groupdate/scopes.rb +17 -13
- data/lib/groupdate/series.rb +36 -28
- data/lib/groupdate/version.rb +1 -1
- data/test/mysql_test.rb +1 -1
- data/test/postgresql_test.rb +1 -1
- data/test/test_helper.rb +134 -26
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00f2a25fe5b1a02e4b8a6e2b483e407ed4d5d76e
|
4
|
+
data.tar.gz: 5f6c81ee95f601a8ad189d706c53b5e57cf6d483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3f980694ad4a61ae5a3915720f8e90a4d01fd62e865aa5db751f06c3fb4bc87b3b91f0681cf0d49ba39287b08aeb1ba7bbfe78b86d1fe3d8554b3f4754e6113
|
7
|
+
data.tar.gz: 6700771e7de2ad8e0153e58efaa417fcbc73e5fd8f55beaa5af5314fc54d46425ea2d9ecacbed8a28a71f49931fa64f717f657b51da26e9203c2ed2b3f99fae9
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,10 +4,8 @@ The simplest way to group by:
|
|
4
4
|
|
5
5
|
- day
|
6
6
|
- week
|
7
|
-
- month
|
8
|
-
- day of the week
|
9
7
|
- hour of the day
|
10
|
-
- and more (complete list
|
8
|
+
- and more (complete list below)
|
11
9
|
|
12
10
|
:tada: Time zones supported!! **the best part**
|
13
11
|
|
@@ -21,7 +19,9 @@ Supports PostgreSQL and MySQL
|
|
21
19
|
|
22
20
|
:cupid: Goes hand in hand with [Chartkick](http://ankane.github.io/chartkick/)
|
23
21
|
|
24
|
-
##
|
22
|
+
## Get Started
|
23
|
+
|
24
|
+
Group by day
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
User.group_by_day(:created_at).count
|
@@ -30,141 +30,76 @@ User.group_by_day(:created_at).count
|
|
30
30
|
# 2013-04-17 00:00:00 UTC => 100,
|
31
31
|
# 2013-04-18 00:00:00 UTC => 34
|
32
32
|
# }
|
33
|
-
|
34
|
-
Task.group_by_month(:updated_at).count
|
35
|
-
# {
|
36
|
-
# 2013-02-01 00:00:00 UTC => 84,
|
37
|
-
# 2013-03-01 00:00:00 UTC => 23,
|
38
|
-
# 2013-04-01 00:00:00 UTC => 44
|
39
|
-
# }
|
40
|
-
|
41
|
-
Goal.group_by_year(:accomplished_at).count
|
42
|
-
# {
|
43
|
-
# 2011-01-01 00:00:00 UTC => 7,
|
44
|
-
# 2012-01-01 00:00:00 UTC => 11,
|
45
|
-
# 2013-01-01 00:00:00 UTC => 3
|
46
|
-
# }
|
47
33
|
```
|
48
34
|
|
49
|
-
|
35
|
+
Results are returned in ascending order, so no need to sort.
|
50
36
|
|
51
|
-
|
52
|
-
User.group_by_week(:created_at, "Pacific Time (US & Canada)").count
|
53
|
-
# {
|
54
|
-
# 2013-03-03 08:00:00 UTC => 80,
|
55
|
-
# 2013-03-10 08:00:00 UTC => 70,
|
56
|
-
# 2013-03-17 07:00:00 UTC => 54
|
57
|
-
# }
|
37
|
+
You can also group by:
|
58
38
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
39
|
+
- second
|
40
|
+
- minute
|
41
|
+
- hour
|
42
|
+
- week
|
43
|
+
- month
|
44
|
+
- year
|
63
45
|
|
64
|
-
|
46
|
+
and
|
65
47
|
|
66
|
-
|
67
|
-
|
48
|
+
- hour_of_day
|
49
|
+
- day_of_week (Sunday = 0, Monday = 1, etc)
|
50
|
+
|
51
|
+
### Time Zones
|
68
52
|
|
69
|
-
|
70
|
-
User.group_by_week(:created_at, time_zone, :start => :sat)
|
53
|
+
The default time zone is `Time.zone`. Change this with:
|
71
54
|
|
72
|
-
|
73
|
-
Groupdate.
|
55
|
+
```ruby
|
56
|
+
Groupdate.time_zone = "Pacific Time (US & Canada)"
|
74
57
|
```
|
75
58
|
|
76
|
-
|
59
|
+
or
|
77
60
|
|
78
61
|
```ruby
|
79
|
-
|
80
|
-
User.group_by_day_of_week(:created_at).count
|
62
|
+
User.group_by_week(:created_at, time_zone: "Pacific Time (US & Canada)").count
|
81
63
|
# {
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# 6 => 3 # Saturday
|
86
|
-
# }
|
87
|
-
|
88
|
-
# hour of the day
|
89
|
-
User.group_by_hour_of_day(:created_at, "Pacific Time (US & Canada)").count
|
90
|
-
# {
|
91
|
-
# 0 => 34,
|
92
|
-
# 1 => 61,
|
93
|
-
# ...
|
94
|
-
# 23 => 12
|
64
|
+
# 2013-03-03 08:00:00 UTC => 80,
|
65
|
+
# 2013-03-10 08:00:00 UTC => 70,
|
66
|
+
# 2013-03-17 07:00:00 UTC => 54
|
95
67
|
# }
|
96
68
|
```
|
97
69
|
|
98
|
-
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
User.group_by_day(:created_at).order("day asc").count
|
102
|
-
|
103
|
-
User.group_by_week(:created_at).order("week desc").count
|
70
|
+
Time zone objects also work.
|
104
71
|
|
105
|
-
|
106
|
-
```
|
72
|
+
### Week Start
|
107
73
|
|
108
|
-
|
74
|
+
Weeks start on Sunday by default. Change this with:
|
109
75
|
|
110
76
|
```ruby
|
111
|
-
|
77
|
+
Groupdate.week_start = :mon # first three letters of day
|
112
78
|
```
|
113
79
|
|
114
|
-
|
80
|
+
or
|
115
81
|
|
116
82
|
```ruby
|
117
|
-
|
83
|
+
User.group_by_week(:created_at, week_start: :mon).count
|
118
84
|
```
|
119
85
|
|
120
|
-
###
|
86
|
+
### Day Start
|
121
87
|
|
122
|
-
You
|
88
|
+
You can change the hour days start with:
|
123
89
|
|
124
90
|
```ruby
|
125
|
-
|
126
|
-
# {
|
127
|
-
# 2013-05-02 00:00:00 UTC => 1,
|
128
|
-
# 2013-05-05 00:00:00 UTC => 1
|
129
|
-
# }
|
91
|
+
Groupdate.day_start = 2 # 2 am - 2 am
|
130
92
|
```
|
131
93
|
|
132
|
-
|
94
|
+
or
|
133
95
|
|
134
96
|
```ruby
|
135
|
-
|
136
|
-
time_range = 6.days.ago..Time.now
|
137
|
-
|
138
|
-
User.group_by_day(:created_at, Time.zone, time_range).count
|
139
|
-
# {
|
140
|
-
# 2013-05-01 00:00:00 UTC => 0,
|
141
|
-
# 2013-05-02 00:00:00 UTC => 1,
|
142
|
-
# 2013-05-03 00:00:00 UTC => 0,
|
143
|
-
# 2013-05-04 00:00:00 UTC => 0,
|
144
|
-
# 2013-05-05 00:00:00 UTC => 1,
|
145
|
-
# 2013-05-06 00:00:00 UTC => 0,
|
146
|
-
# 2013-05-07 00:00:00 UTC => 0
|
147
|
-
# }
|
148
|
-
|
149
|
-
User.group_by_day_of_week(:created_at, Time.zone, time_range).count
|
150
|
-
# {
|
151
|
-
# 0 => 0,
|
152
|
-
# 1 => 1,
|
153
|
-
# 2 => 0,
|
154
|
-
# 3 => 0,
|
155
|
-
# 4 => 1,
|
156
|
-
# 5 => 0,
|
157
|
-
# 6 => 0
|
158
|
-
# }
|
97
|
+
User.group_by_day(:created_at, day_start: 2).count
|
159
98
|
```
|
160
99
|
|
161
|
-
Results are returned in ascending order, so no need to sort.
|
162
|
-
|
163
|
-
Also, this form of the method returns a Groupdate::Series instead of an ActiveRecord::Relation. ActiveRecord::Relation method calls (like `where` and `joins`) should come before this.
|
164
|
-
|
165
100
|
## Installation
|
166
101
|
|
167
|
-
Add this line to your application
|
102
|
+
Add this line to your application’s Gemfile:
|
168
103
|
|
169
104
|
```ruby
|
170
105
|
gem 'groupdate'
|
@@ -190,60 +125,31 @@ gem "activerecord-jdbcpostgresql-adapter", :github => "jruby/activerecord-jdbc-a
|
|
190
125
|
gem "activerecord-jdbcmysql-adapter", :github => "jruby/activerecord-jdbc-adapter"
|
191
126
|
```
|
192
127
|
|
193
|
-
##
|
194
|
-
|
195
|
-
The default time zone is `Time.zone`. To change this, use:
|
196
|
-
|
197
|
-
```ruby
|
198
|
-
Groupdate.time_zone = "Pacific Time (US & Canada)"
|
199
|
-
```
|
200
|
-
|
201
|
-
## Complete list
|
202
|
-
|
203
|
-
group_by_?
|
204
|
-
|
205
|
-
- second
|
206
|
-
- minute
|
207
|
-
- hour
|
208
|
-
- day
|
209
|
-
- week
|
210
|
-
- month
|
211
|
-
- year
|
212
|
-
- hour_of_day
|
213
|
-
- day_of_week
|
214
|
-
|
215
|
-
## Note
|
128
|
+
## Upgrading to 2.0
|
216
129
|
|
217
|
-
|
218
|
-
[This is fixed on activerecord master](https://github.com/rails/rails/commit/2cc09441c2de57b024b11ba666ba1e72c2b20cfe)
|
130
|
+
Groupdate 2.0 brings a number a great improvements.
|
219
131
|
|
220
|
-
|
221
|
-
|
132
|
+
- the entire series is returned by default
|
133
|
+
- the `day_start` option
|
134
|
+
- an improved interface
|
222
135
|
|
223
|
-
|
224
|
-
# pg and activerecord master
|
225
|
-
{2013-04-22 00:00:00 UTC => 1} # Time object
|
136
|
+
However, there are a few things to be aware of when upgrading.
|
226
137
|
|
227
|
-
|
228
|
-
{"2013-04-22 00:00:00+00" => 1} # String
|
229
|
-
```
|
230
|
-
|
231
|
-
Another data type inconsistency
|
138
|
+
1. Groupdate methods must come after any `where`, `joins`, or `includes`.
|
232
139
|
|
233
|
-
|
234
|
-
User.group_by_day_of_week(:created_at).count
|
140
|
+
Throws error
|
235
141
|
|
236
|
-
|
237
|
-
|
142
|
+
```ruby
|
143
|
+
User.group_by_day(:created_at).where(company_id: 1).count
|
144
|
+
```
|
238
145
|
|
239
|
-
|
240
|
-
{"0" => 1, "4" => 1} # String
|
146
|
+
:moneybag:
|
241
147
|
|
242
|
-
|
243
|
-
|
244
|
-
```
|
148
|
+
```ruby
|
149
|
+
User.where(company_id: 1).group_by_day(:created_at).count
|
150
|
+
```
|
245
151
|
|
246
|
-
|
152
|
+
2. `Time` keys are now returned for every database adapter. Some older adapters previously returned `String` keys.
|
247
153
|
|
248
154
|
## History
|
249
155
|
|
data/lib/groupdate.rb
CHANGED
data/lib/groupdate/scopes.rb
CHANGED
@@ -11,7 +11,7 @@ module Groupdate
|
|
11
11
|
args = args.dup
|
12
12
|
options = args[-1].is_a?(Hash) ? args.pop : {}
|
13
13
|
column = connection.quote_table_name(args[0])
|
14
|
-
time_zone = args[1] || Groupdate.time_zone || Time.zone || "Etc/UTC"
|
14
|
+
time_zone = args[1] || options[:time_zone] || Groupdate.time_zone || Time.zone || "Etc/UTC"
|
15
15
|
if time_zone.is_a?(ActiveSupport::TimeZone) or time_zone = ActiveSupport::TimeZone[time_zone]
|
16
16
|
time_zone = time_zone.tzinfo.name
|
17
17
|
else
|
@@ -19,22 +19,25 @@ module Groupdate
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# for week
|
22
|
-
week_start = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].index((options[:start] || Groupdate.week_start).to_sym)
|
22
|
+
week_start = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].index((options[:week_start] || options[:start] || Groupdate.week_start).to_sym)
|
23
23
|
if field == "week" and !week_start
|
24
24
|
raise "Unrecognized :start option"
|
25
25
|
end
|
26
26
|
|
27
|
+
# for day
|
28
|
+
day_start = (options[:day_start] || Groupdate.day_start).to_i
|
29
|
+
|
27
30
|
query =
|
28
31
|
case connection.adapter_name
|
29
32
|
when "MySQL", "Mysql2"
|
30
33
|
case field
|
31
34
|
when "day_of_week" # Sunday = 0, Monday = 1, etc
|
32
35
|
# use CONCAT for consistent return type (String)
|
33
|
-
["DAYOFWEEK(CONVERT_TZ(#{column}, '+00:00', ?)) - 1", time_zone]
|
36
|
+
["DAYOFWEEK(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?)) - 1", time_zone]
|
34
37
|
when "hour_of_day"
|
35
|
-
["EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?))", time_zone]
|
38
|
+
["(EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?)) + 24 - #{day_start}) % 24", time_zone]
|
36
39
|
when "week"
|
37
|
-
["CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL ((#{7 - week_start} + WEEKDAY(CONVERT_TZ(#{column}, '+00:00', ?))) % 7) DAY), '+00:00', ?), '%Y-%m-%d 00:00:00'), ?, '+00:00')", time_zone, time_zone, time_zone]
|
40
|
+
["CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL ((#{7 - week_start} + WEEKDAY(CONVERT_TZ(#{column}, '+00:00', ?) - INTERVAL #{day_start} HOUR)) % 7) DAY) - INTERVAL #{day_start} HOUR, '+00:00', ?), '%Y-%m-%d 00:00:00') + INTERVAL #{day_start} HOUR, ?, '+00:00')", time_zone, time_zone, time_zone]
|
38
41
|
else
|
39
42
|
format =
|
40
43
|
case field
|
@@ -50,28 +53,29 @@ module Groupdate
|
|
50
53
|
"%Y-%m-01 00:00:00"
|
51
54
|
else # year
|
52
55
|
"%Y-01-01 00:00:00"
|
53
|
-
|
56
|
+
end
|
54
57
|
|
55
|
-
["CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(#{column}, '+00:00', ?), '#{format}'), ?, '+00:00')", time_zone, time_zone]
|
58
|
+
["DATE_ADD(CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?), '#{format}'), ?, '+00:00'), INTERVAL #{day_start} HOUR)", time_zone, time_zone]
|
56
59
|
end
|
57
60
|
when "PostgreSQL", "PostGIS"
|
58
61
|
case field
|
59
62
|
when "day_of_week"
|
60
|
-
["EXTRACT(DOW from #{column}::timestamptz AT TIME ZONE ?)::integer", time_zone]
|
63
|
+
["EXTRACT(DOW from (#{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour'))::integer", time_zone]
|
61
64
|
when "hour_of_day"
|
62
|
-
["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ?)::integer", time_zone]
|
65
|
+
["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour')::integer", time_zone]
|
63
66
|
when "week" # start on Sunday, not PostgreSQL default Monday
|
64
|
-
["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{week_start} day') AT TIME ZONE ?) + INTERVAL '#{week_start} day') AT TIME ZONE ?", time_zone, time_zone]
|
67
|
+
["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{week_start} day' - INTERVAL '#{day_start}' hour) AT TIME ZONE ?) + INTERVAL '#{week_start} day' + INTERVAL '#{day_start}' hour) AT TIME ZONE ?", time_zone, time_zone]
|
65
68
|
else
|
66
|
-
["DATE_TRUNC('#{field}', #{column}::timestamptz AT TIME ZONE ?) AT TIME ZONE ?", time_zone, time_zone]
|
69
|
+
["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{day_start} hour') AT TIME ZONE ?) + INTERVAL '#{day_start} hour') AT TIME ZONE ?", time_zone, time_zone]
|
67
70
|
end
|
68
71
|
else
|
69
72
|
raise "Connection adapter not supported: #{connection.adapter_name}"
|
70
73
|
end
|
71
74
|
|
72
75
|
group = group(Groupdate::OrderHack.new(sanitize_sql_array(query), field, time_zone))
|
73
|
-
|
74
|
-
|
76
|
+
range = args[2] || options[:range] || true
|
77
|
+
unless options[:series] == false
|
78
|
+
Series.new(group, field, column, time_zone, range, week_start, day_start)
|
75
79
|
else
|
76
80
|
group
|
77
81
|
end
|
data/lib/groupdate/series.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Groupdate
|
2
2
|
class Series
|
3
3
|
|
4
|
-
def initialize(relation, field, column, time_zone, time_range, week_start)
|
4
|
+
def initialize(relation, field, column, time_zone, time_range, week_start, day_start)
|
5
5
|
if time_range.is_a?(Range)
|
6
6
|
# doesn't matter whether we include the end of a ... range - it will be excluded later
|
7
7
|
@relation = relation.where("#{column} >= ? AND #{column} <= ?", time_range.first, time_range.last)
|
@@ -12,6 +12,7 @@ module Groupdate
|
|
12
12
|
@time_zone = time_zone
|
13
13
|
@time_range = time_range
|
14
14
|
@week_start = week_start
|
15
|
+
@day_start = day_start
|
15
16
|
end
|
16
17
|
|
17
18
|
def build_series(count)
|
@@ -43,37 +44,42 @@ module Groupdate
|
|
43
44
|
sorted_keys.first..sorted_keys.last
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
47
|
+
if time_range.first
|
48
|
+
# determine start time
|
49
|
+
time = time_range.first.to_time.in_time_zone(@time_zone) - @day_start.hours
|
50
|
+
starts_at =
|
51
|
+
case @field
|
52
|
+
when "second"
|
53
|
+
time.change(:usec => 0)
|
54
|
+
when "minute"
|
55
|
+
time.change(:sec => 0)
|
56
|
+
when "hour"
|
57
|
+
time.change(:min => 0)
|
58
|
+
when "day"
|
59
|
+
time.beginning_of_day
|
60
|
+
when "week"
|
61
|
+
# same logic as MySQL group
|
62
|
+
weekday = (time.wday - 1) % 7
|
63
|
+
(time - ((7 - @week_start + weekday) % 7).days).midnight
|
64
|
+
when "month"
|
65
|
+
time.beginning_of_month
|
66
|
+
else # year
|
67
|
+
time.beginning_of_year
|
68
|
+
end
|
67
69
|
|
68
|
-
|
70
|
+
starts_at += @day_start.hours
|
71
|
+
series = [starts_at]
|
69
72
|
|
70
|
-
|
73
|
+
step = 1.send(@field)
|
71
74
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
+
while time_range.cover?(series.last + step)
|
76
|
+
series << series.last + step
|
77
|
+
end
|
75
78
|
|
76
|
-
|
79
|
+
series.map{|s| s.to_time.utc }
|
80
|
+
else
|
81
|
+
[]
|
82
|
+
end
|
77
83
|
end
|
78
84
|
|
79
85
|
Hash[series.map do |k|
|
@@ -85,6 +91,8 @@ module Groupdate
|
|
85
91
|
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/calculations.rb
|
86
92
|
if ActiveRecord::Calculations.method_defined?(method)
|
87
93
|
build_series(@relation.send(method, *args, &block))
|
94
|
+
elsif [:joins, :includes, :where].include?(method)
|
95
|
+
raise NoMethodError, "#{method} must come before the group_by_#{@field} method"
|
88
96
|
else
|
89
97
|
raise NoMethodError, "valid methods are: #{ActiveRecord::Calculations.instance_methods.join(", ")}"
|
90
98
|
end
|
data/lib/groupdate/version.rb
CHANGED
data/test/mysql_test.rb
CHANGED
data/test/postgresql_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -84,6 +84,24 @@ module TestGroupdate
|
|
84
84
|
assert_result_time :day, "2013-05-03 00:00:00 PDT", "2013-05-03 07:00:00", true
|
85
85
|
end
|
86
86
|
|
87
|
+
# day hour starts at 2 am
|
88
|
+
|
89
|
+
def test_test_day_end_of_day_day_start_2am
|
90
|
+
assert_result_time :day, "2013-05-03 02:00:00 UTC", "2013-05-04 01:59:59", false, :day_start => 2
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_test_day_start_of_day_day_start_2am
|
94
|
+
assert_result_time :day, "2013-05-03 02:00:00 UTC", "2013-05-03 02:00:00", false, :day_start => 2
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_test_day_end_of_day_with_time_zone_day_start_2am
|
98
|
+
assert_result_time :day, "2013-05-03 02:00:00 PDT", "2013-05-04 07:59:59", true, :day_start => 2
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_test_day_start_of_day_with_time_zone_day_start_2am
|
102
|
+
assert_result_time :day, "2013-05-03 02:00:00 PDT", "2013-05-03 09:00:00", true, :day_start => 2
|
103
|
+
end
|
104
|
+
|
87
105
|
# week
|
88
106
|
|
89
107
|
def test_week_end_of_week
|
@@ -105,37 +123,55 @@ module TestGroupdate
|
|
105
123
|
# week starting on monday
|
106
124
|
|
107
125
|
def test_week_end_of_week_mon
|
108
|
-
assert_result_time :week, "2013-03-18 00:00:00 UTC", "2013-03-24 23:59:59", false, :
|
126
|
+
assert_result_time :week, "2013-03-18 00:00:00 UTC", "2013-03-24 23:59:59", false, week_start: :mon
|
109
127
|
end
|
110
128
|
|
111
129
|
def test_week_start_of_week_mon
|
112
|
-
assert_result_time :week, "2013-03-25 00:00:00 UTC", "2013-03-25 00:00:00", false, :
|
130
|
+
assert_result_time :week, "2013-03-25 00:00:00 UTC", "2013-03-25 00:00:00", false, week_start: :mon
|
113
131
|
end
|
114
132
|
|
115
133
|
def test_week_end_of_week_with_time_zone_mon
|
116
|
-
assert_result_time :week, "2013-03-11 00:00:00 PDT", "2013-03-18 06:59:59", true, :
|
134
|
+
assert_result_time :week, "2013-03-11 00:00:00 PDT", "2013-03-18 06:59:59", true, week_start: :mon
|
117
135
|
end
|
118
136
|
|
119
137
|
def test_week_start_of_week_with_time_zone_mon
|
120
|
-
assert_result_time :week, "2013-03-18 00:00:00 PDT", "2013-03-18 07:00:00", true, :
|
138
|
+
assert_result_time :week, "2013-03-18 00:00:00 PDT", "2013-03-18 07:00:00", true, week_start: :mon
|
121
139
|
end
|
122
140
|
|
123
141
|
# week starting on saturday
|
124
142
|
|
125
143
|
def test_week_end_of_week_sat
|
126
|
-
assert_result_time :week, "2013-03-16 00:00:00 UTC", "2013-03-22 23:59:59", false, :
|
144
|
+
assert_result_time :week, "2013-03-16 00:00:00 UTC", "2013-03-22 23:59:59", false, week_start: :sat
|
127
145
|
end
|
128
146
|
|
129
147
|
def test_week_start_of_week_sat
|
130
|
-
assert_result_time :week, "2013-03-23 00:00:00 UTC", "2013-03-23 00:00:00", false, :
|
148
|
+
assert_result_time :week, "2013-03-23 00:00:00 UTC", "2013-03-23 00:00:00", false, week_start: :sat
|
131
149
|
end
|
132
150
|
|
133
151
|
def test_week_end_of_week_with_time_zone_sat
|
134
|
-
assert_result_time :week, "2013-03-09 00:00:00 PST", "2013-03-16 06:59:59", true, :
|
152
|
+
assert_result_time :week, "2013-03-09 00:00:00 PST", "2013-03-16 06:59:59", true, week_start: :sat
|
135
153
|
end
|
136
154
|
|
137
155
|
def test_week_start_of_week_with_time_zone_sat
|
138
|
-
assert_result_time :week, "2013-03-16 00:00:00 PDT", "2013-03-16 07:00:00", true, :
|
156
|
+
assert_result_time :week, "2013-03-16 00:00:00 PDT", "2013-03-16 07:00:00", true, week_start: :sat
|
157
|
+
end
|
158
|
+
|
159
|
+
# week starting at 2am
|
160
|
+
|
161
|
+
def test_week_end_of_week_day_start_2am
|
162
|
+
assert_result_time :week, "2013-03-17 02:00:00 UTC", "2013-03-24 01:59:59", false, :day_start => 2
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_week_start_of_week_day_start_2am
|
166
|
+
assert_result_time :week, "2013-03-17 02:00:00 UTC", "2013-03-17 02:00:00", false, :day_start => 2
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_week_end_of_week_day_with_time_zone_start_2am
|
170
|
+
assert_result_time :week, "2013-03-17 02:00:00 PDT", "2013-03-24 08:59:59", true, :day_start => 2
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_week_start_of_week_day_with_time_zone_start_2am
|
174
|
+
assert_result_time :week, "2013-03-17 02:00:00 PDT", "2013-03-17 09:00:00", true, :day_start => 2
|
139
175
|
end
|
140
176
|
|
141
177
|
# month
|
@@ -156,6 +192,24 @@ module TestGroupdate
|
|
156
192
|
assert_result_time :month, "2013-06-01 00:00:00 PDT", "2013-06-01 07:00:00", true
|
157
193
|
end
|
158
194
|
|
195
|
+
# month starts at 2am
|
196
|
+
|
197
|
+
def test_month_end_of_month_day_start_2am
|
198
|
+
assert_result_time :month, "2013-03-01 02:00:00 UTC", "2013-04-01 01:59:59", false, :day_start => 2
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_month_start_of_month_day_start_2am
|
202
|
+
assert_result_time :month, "2013-03-01 02:00:00 UTC", "2013-03-01 02:00:00", false, :day_start => 2
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_month_end_of_month_with_time_zone_day_start_2am
|
206
|
+
assert_result_time :month, "2013-03-01 02:00:00 PST", "2013-04-01 08:59:59", true, :day_start => 2
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_month_start_of_month_with_time_zone_day_start_2am
|
210
|
+
assert_result_time :month, "2013-03-01 02:00:00 PST", "2013-03-01 10:00:00", true, :day_start => 2
|
211
|
+
end
|
212
|
+
|
159
213
|
# year
|
160
214
|
|
161
215
|
def test_year_end_of_year
|
@@ -174,6 +228,24 @@ module TestGroupdate
|
|
174
228
|
assert_result_time :year, "2014-01-01 00:00:00 PST", "2014-01-01 08:00:00", true
|
175
229
|
end
|
176
230
|
|
231
|
+
# year starts at 2am
|
232
|
+
|
233
|
+
def test_year_end_of_year_day_start_2am
|
234
|
+
assert_result_time :year, "2013-01-01 02:00:00 UTC", "2014-01-01 01:59:59", false, :day_start => 2
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_year_start_of_year_day_start_2am
|
238
|
+
assert_result_time :year, "2013-01-01 02:00:00 UTC", "2013-01-01 02:00:00", false, :day_start => 2
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_year_end_of_year_with_time_zone_day_start_2am
|
242
|
+
assert_result_time :year, "2013-01-01 02:00:00 PST", "2014-01-01 09:59:59", true, :day_start => 2
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_year_start_of_year_with_time_zone_day_start_2am
|
246
|
+
assert_result_time :year, "2013-01-01 02:00:00 PST", "2013-01-01 10:00:00", true, :day_start => 2
|
247
|
+
end
|
248
|
+
|
177
249
|
# hour of day
|
178
250
|
|
179
251
|
def test_hour_of_day_end_of_hour
|
@@ -192,6 +264,24 @@ module TestGroupdate
|
|
192
264
|
assert_result :hour_of_day, 1, "2013-01-01 09:00:00", true
|
193
265
|
end
|
194
266
|
|
267
|
+
# hour of day starts at 2am
|
268
|
+
|
269
|
+
def test_hour_of_day_end_of_day_day_start_2am
|
270
|
+
assert_result :hour_of_day, 23, "2013-01-01 01:59:59", false, :day_start => 2
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_hour_of_day_start_of_day_day_start_2am
|
274
|
+
assert_result :hour_of_day, 0, "2013-01-01 02:00:00", false, :day_start => 2
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_hour_of_day_end_of_day_with_time_zone_day_start_2am
|
278
|
+
assert_result :hour_of_day, 23, "2013-01-01 09:59:59", true, :day_start => 2
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_hour_of_day_start_of_day_with_time_zone_day_start_2am
|
282
|
+
assert_result :hour_of_day, 0, "2013-01-01 10:00:00", true, :day_start => 2
|
283
|
+
end
|
284
|
+
|
195
285
|
# day of week
|
196
286
|
|
197
287
|
def test_day_of_week_end_of_day
|
@@ -210,6 +300,24 @@ module TestGroupdate
|
|
210
300
|
assert_result :day_of_week, 3, "2013-01-02 08:00:00", true
|
211
301
|
end
|
212
302
|
|
303
|
+
# day of week starts at 2am
|
304
|
+
|
305
|
+
def test_day_of_week_end_of_day_day_start_2am
|
306
|
+
assert_result :day_of_week, 3, "2013-01-03 01:59:59", false, :day_start => 2
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_day_of_week_start_of_day_day_start_2am
|
310
|
+
assert_result :day_of_week, 3, "2013-01-02 02:00:00", false, :day_start => 2
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_day_of_week_end_of_day_with_time_zone_day_start_2am
|
314
|
+
assert_result :day_of_week, 3, "2013-01-03 09:59:59", true, :day_start => 2
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_day_of_week_start_of_day_with_time_zone_day_start_2am
|
318
|
+
assert_result :day_of_week, 3, "2013-01-02 10:00:00", true, :day_start => 2
|
319
|
+
end
|
320
|
+
|
213
321
|
# zeros
|
214
322
|
|
215
323
|
def test_zeros_second
|
@@ -241,19 +349,19 @@ module TestGroupdate
|
|
241
349
|
end
|
242
350
|
|
243
351
|
def test_zeros_week_mon
|
244
|
-
assert_zeros :week, "2013-05-01 20:00:00 UTC", ["2013-04-22 00:00:00 UTC", "2013-04-29 00:00:00 UTC", "2013-05-06 00:00:00 UTC"], "2013-04-27 23:59:59 UTC", "2013-05-11 23:59:59 UTC", false, :
|
352
|
+
assert_zeros :week, "2013-05-01 20:00:00 UTC", ["2013-04-22 00:00:00 UTC", "2013-04-29 00:00:00 UTC", "2013-05-06 00:00:00 UTC"], "2013-04-27 23:59:59 UTC", "2013-05-11 23:59:59 UTC", false, week_start: :mon
|
245
353
|
end
|
246
354
|
|
247
355
|
def test_zeros_week_time_zone_mon
|
248
|
-
assert_zeros :week, "2013-05-01 20:00:00 PDT", ["2013-04-22 00:00:00 PDT", "2013-04-29 00:00:00 PDT", "2013-05-06 00:00:00 PDT"], "2013-04-27 23:59:59 PDT", "2013-05-11 23:59:59 PDT", true, :
|
356
|
+
assert_zeros :week, "2013-05-01 20:00:00 PDT", ["2013-04-22 00:00:00 PDT", "2013-04-29 00:00:00 PDT", "2013-05-06 00:00:00 PDT"], "2013-04-27 23:59:59 PDT", "2013-05-11 23:59:59 PDT", true, week_start: :mon
|
249
357
|
end
|
250
358
|
|
251
359
|
def test_zeros_week_sat
|
252
|
-
assert_zeros :week, "2013-05-01 20:00:00 UTC", ["2013-04-20 00:00:00 UTC", "2013-04-27 00:00:00 UTC", "2013-05-04 00:00:00 UTC"], "2013-04-26 23:59:59 UTC", "2013-05-10 23:59:59 UTC", false, :
|
360
|
+
assert_zeros :week, "2013-05-01 20:00:00 UTC", ["2013-04-20 00:00:00 UTC", "2013-04-27 00:00:00 UTC", "2013-05-04 00:00:00 UTC"], "2013-04-26 23:59:59 UTC", "2013-05-10 23:59:59 UTC", false, week_start: :sat
|
253
361
|
end
|
254
362
|
|
255
363
|
def test_zeros_week_time_zone_sat
|
256
|
-
assert_zeros :week, "2013-05-01 20:00:00 PDT", ["2013-04-20 00:00:00 PDT", "2013-04-27 00:00:00 PDT", "2013-05-04 00:00:00 PDT"], "2013-04-26 23:59:59 PDT", "2013-05-10 23:59:59 PDT", true, :
|
364
|
+
assert_zeros :week, "2013-05-01 20:00:00 PDT", ["2013-04-20 00:00:00 PDT", "2013-04-27 00:00:00 PDT", "2013-05-04 00:00:00 PDT"], "2013-04-26 23:59:59 PDT", "2013-05-10 23:59:59 PDT", true, week_start: :sat
|
257
365
|
end
|
258
366
|
|
259
367
|
def test_zeros_month
|
@@ -278,7 +386,7 @@ module TestGroupdate
|
|
278
386
|
7.times do |n|
|
279
387
|
expected[n] = n == 3 ? 1 : 0
|
280
388
|
end
|
281
|
-
assert_equal expected, User.group_by_day_of_week(:created_at,
|
389
|
+
assert_equal expected, User.group_by_day_of_week(:created_at, range: true).count(:created_at)
|
282
390
|
end
|
283
391
|
|
284
392
|
def test_zeros_hour_of_day
|
@@ -287,7 +395,7 @@ module TestGroupdate
|
|
287
395
|
24.times do |n|
|
288
396
|
expected[n] = n == 20 ? 1 : 0
|
289
397
|
end
|
290
|
-
assert_equal expected, User.group_by_hour_of_day(:created_at,
|
398
|
+
assert_equal expected, User.group_by_hour_of_day(:created_at, range: true).count(:created_at)
|
291
399
|
end
|
292
400
|
|
293
401
|
def test_zeros_excludes_end
|
@@ -295,7 +403,7 @@ module TestGroupdate
|
|
295
403
|
expected = {
|
296
404
|
Time.parse("2013-05-01 00:00:00 UTC") => 0
|
297
405
|
}
|
298
|
-
assert_equal expected, User.group_by_day(:created_at,
|
406
|
+
assert_equal expected, User.group_by_day(:created_at, range: Time.parse("2013-05-01 00:00:00 UTC")...Time.parse("2013-05-02 00:00:00 UTC")).count
|
299
407
|
end
|
300
408
|
|
301
409
|
def test_zeros_previous_scope
|
@@ -303,7 +411,7 @@ module TestGroupdate
|
|
303
411
|
expected = {
|
304
412
|
Time.parse("2013-05-01 00:00:00 UTC") => 0
|
305
413
|
}
|
306
|
-
assert_equal expected, User.where("id = 0").group_by_day(:created_at,
|
414
|
+
assert_equal expected, User.where("id = 0").group_by_day(:created_at, range: Time.parse("2013-05-01 00:00:00 UTC")..Time.parse("2013-05-01 23:59:59 UTC")).count
|
307
415
|
end
|
308
416
|
|
309
417
|
def test_zeros_datetime
|
@@ -311,13 +419,13 @@ module TestGroupdate
|
|
311
419
|
expected = {
|
312
420
|
Time.parse("2013-05-01 00:00:00 UTC") => 1
|
313
421
|
}
|
314
|
-
assert_equal expected, User.group_by_day(:created_at,
|
422
|
+
assert_equal expected, User.group_by_day(:created_at, range: DateTime.parse("2013-05-01 00:00:00 UTC")..DateTime.parse("2013-05-01 00:00:00 UTC")).count
|
315
423
|
end
|
316
424
|
|
317
425
|
def test_zeros_null_value
|
318
426
|
user = User.create!(name: "Andrew")
|
319
427
|
user.update_column :created_at, nil
|
320
|
-
assert_equal 0, User.group_by_hour_of_day(:created_at,
|
428
|
+
assert_equal 0, User.group_by_hour_of_day(:created_at, range: true).count[0]
|
321
429
|
end
|
322
430
|
|
323
431
|
def test_zeroes_range_true
|
@@ -328,7 +436,7 @@ module TestGroupdate
|
|
328
436
|
Time.parse("2013-05-02 00:00:00 UTC") => 0,
|
329
437
|
Time.parse("2013-05-03 00:00:00 UTC") => 1
|
330
438
|
}
|
331
|
-
assert_equal expected, User.group_by_day(:created_at,
|
439
|
+
assert_equal expected, User.group_by_day(:created_at, range: true).count
|
332
440
|
end
|
333
441
|
|
334
442
|
# week_start
|
@@ -340,21 +448,21 @@ module TestGroupdate
|
|
340
448
|
|
341
449
|
def test_week_start_and_start_option
|
342
450
|
Groupdate.week_start = :mon
|
343
|
-
assert_result_time :week, "2013-03-16 00:00:00 UTC", "2013-03-22 23:59:59", false, :
|
451
|
+
assert_result_time :week, "2013-03-16 00:00:00 UTC", "2013-03-22 23:59:59", false, week_start: :sat
|
344
452
|
end
|
345
453
|
|
346
454
|
# misc
|
347
455
|
|
348
456
|
def test_order_day
|
349
|
-
assert_empty User.group_by_day(:created_at).order("day desc").limit(20).count
|
457
|
+
assert_empty User.group_by_day(:created_at, series: false).order("day desc").limit(20).count
|
350
458
|
end
|
351
459
|
|
352
460
|
def test_order_week
|
353
|
-
assert_empty User.group_by_week(:created_at).order("week asc").count
|
461
|
+
assert_empty User.group_by_week(:created_at, series: false).order("week asc").count
|
354
462
|
end
|
355
463
|
|
356
464
|
def test_order_hour_of_day
|
357
|
-
assert_empty User.group_by_hour_of_day(:created_at).order("hour_of_day desc").count
|
465
|
+
assert_empty User.group_by_hour_of_day(:created_at, series: false).order("hour_of_day desc").count
|
358
466
|
end
|
359
467
|
|
360
468
|
def test_table_name
|
@@ -375,8 +483,8 @@ module TestGroupdate
|
|
375
483
|
def assert_result(method, expected, time_str, time_zone = false, options = {})
|
376
484
|
create_user time_str
|
377
485
|
expected = expected.is_a?(Time) ? time_key(expected) : number_key(expected)
|
378
|
-
assert_equal ordered_hash({expected => 1}), User.send(:"group_by_#{method}", :created_at, time_zone ? "Pacific Time (US & Canada)" : nil
|
379
|
-
assert_equal 1, User.send(:"group_by_#{method}", :created_at, time_zone ? "Pacific Time (US & Canada)" : nil
|
486
|
+
assert_equal ordered_hash({expected => 1}), User.send(:"group_by_#{method}", :created_at, options.merge(series: false, time_zone: time_zone ? "Pacific Time (US & Canada)" : nil)).order(method.to_s).count
|
487
|
+
assert_equal 1, User.send(:"group_by_#{method}", :created_at, options.merge(time_zone: time_zone ? "Pacific Time (US & Canada)" : nil)).count[expected]
|
380
488
|
end
|
381
489
|
|
382
490
|
def assert_zeros(method, created_at, keys, range_start, range_end, time_zone = nil, options = {})
|
@@ -385,7 +493,7 @@ module TestGroupdate
|
|
385
493
|
keys.each_with_index do |key, i|
|
386
494
|
expected[Time.parse(key)] = i == 1 ? 1 : 0
|
387
495
|
end
|
388
|
-
assert_equal expected, User.send(:"group_by_#{method}", :created_at, time_zone ? "Pacific Time (US & Canada)" : nil, Time.parse(range_start)..Time.parse(range_end)
|
496
|
+
assert_equal expected, User.send(:"group_by_#{method}", :created_at, options.merge(time_zone: time_zone ? "Pacific Time (US & Canada)" : nil, range: Time.parse(range_start)..Time.parse(range_end))).count
|
389
497
|
end
|
390
498
|
|
391
499
|
def ordered_hash(hash)
|