groupdate 2.5.2 → 2.5.3

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
  SHA1:
3
- metadata.gz: 034c6a221a1b829973a2144cc5cd08a8553b004e
4
- data.tar.gz: bf9e8fcc113763a0362b1d14e027033f5abca1dc
3
+ metadata.gz: 2e5361eb118741ab6aae412f5463db1813f85fe2
4
+ data.tar.gz: 0aa40c54eadeb578914db75567bff930fb0dbef8
5
5
  SHA512:
6
- metadata.gz: b394b615b8f63f0c5666ea48fa45a4a6260b9c86c928c60d948d1f4b845a92e58fa6015189927a94eae945c3f2c24de43cff49a889b53b0583ab1b313c95753e
7
- data.tar.gz: 77468a2939c378c27323a13115f5129d2ff38b35b6f5e34d9be8c67ff0e346981b835adc54ccb000a59b3d842b857bb6094dee2f34631608c83b2462f8f19024
6
+ metadata.gz: e642a4eb6084d4a1d339a193b549dd34e13298d082f42ecc58b02803c37296e62d8f5df7773a5cfbe4e8ba087ece17b7b52c362219d0cc307ab2210e25a88f4e
7
+ data.tar.gz: f55793c8987b1dd1d49ce7dbba35ddaf8033e5a4b627e983b208df5daf296b150afc4816fcd8c425bfaccc1c3842a83af631cb50e5d21b0fa700d36ef563b5e7
@@ -1,3 +1,8 @@
1
+ ## 2.5.3
2
+
3
+ - All tests green with `mysql` gem
4
+ - Added support for decimal day start
5
+
1
6
  ## 2.5.2
2
7
 
3
8
  - Added `dates` option to return dates for day, week, month, quarter, and year
data/README.md CHANGED
@@ -21,8 +21,6 @@ Supports PostgreSQL and MySQL, plus arrays and hashes
21
21
 
22
22
  ## Get Started
23
23
 
24
- Group by day
25
-
26
24
  ```ruby
27
25
  User.group_by_day(:created_at).count
28
26
  # {
@@ -34,11 +32,12 @@ User.group_by_day(:created_at).count
34
32
 
35
33
  Results are returned in ascending order by default, so no need to sort.
36
34
 
37
- You can also group by:
35
+ You can group by:
38
36
 
39
37
  - second
40
38
  - minute
41
39
  - hour
40
+ - day
42
41
  - week
43
42
  - month
44
43
  - quarter
@@ -72,7 +71,7 @@ User.group_by_week(:created_at, time_zone: "Pacific Time (US & Canada)").count
72
71
  # }
73
72
  ```
74
73
 
75
- Time zone objects also work.
74
+ Time zone objects also work. To see a list of available time zones in Rails, run `rake time:zones:all`.
76
75
 
77
76
  ### Week Start
78
77
 
@@ -138,7 +137,9 @@ User.group_by_day(:created_at).order("day desc").count
138
137
 
139
138
  ### Keys
140
139
 
141
- To get keys as date objects instead of time objects, use:
140
+ Keys are returned as time objects for the start of the period.
141
+
142
+ To get keys as date objects instead, use:
142
143
 
143
144
  ```ruby
144
145
  User.group_by_day(:created_at, dates: true).count
@@ -16,9 +16,7 @@ module Groupdate
16
16
  end
17
17
 
18
18
  require "groupdate/enumerable"
19
- begin
20
- require "active_record"
21
- rescue LoadError
22
- # do nothing
19
+
20
+ ActiveSupport.on_load(:active_record) do
21
+ require "groupdate/active_record"
23
22
  end
24
- require "groupdate/active_record" if defined?(ActiveRecord)
@@ -36,17 +36,17 @@ module Groupdate
36
36
  case field
37
37
  when :day_of_week # Sunday = 0, Monday = 1, etc
38
38
  # use CONCAT for consistent return type (String)
39
- ["DAYOFWEEK(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?)) - 1", time_zone]
39
+ ["DAYOFWEEK(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?)) - 1", time_zone]
40
40
  when :hour_of_day
41
- ["(EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?)) + 24 - #{day_start}) % 24", time_zone]
41
+ ["(EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?)) + 24 - #{day_start / 3600}) % 24", time_zone]
42
42
  when :day_of_month
43
- ["DAYOFMONTH(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?))", time_zone]
43
+ ["DAYOFMONTH(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?))", time_zone]
44
44
  when :month_of_year
45
- ["MONTH(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?))", time_zone]
45
+ ["MONTH(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?))", time_zone]
46
46
  when :week
47
- ["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]
47
+ ["CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL ((#{7 - week_start} + WEEKDAY(CONVERT_TZ(#{column}, '+00:00', ?) - INTERVAL #{day_start} second)) % 7) DAY) - INTERVAL #{day_start} second, '+00:00', ?), '%Y-%m-%d 00:00:00') + INTERVAL #{day_start} second, ?, '+00:00')", time_zone, time_zone, time_zone]
48
48
  when :quarter
49
- ["DATE_ADD(CONVERT_TZ(DATE_FORMAT(DATE(CONCAT(EXTRACT(YEAR FROM CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?)), '-', LPAD(1 + 3 * (QUARTER(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} HOUR), '+00:00', ?)) - 1), 2, '00'), '-01')), '%Y-%m-%d %H:%i:%S'), ?, '+00:00'), INTERVAL #{day_start} HOUR)", time_zone, time_zone, time_zone]
49
+ ["DATE_ADD(CONVERT_TZ(DATE_FORMAT(DATE(CONCAT(EXTRACT(YEAR FROM CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?)), '-', LPAD(1 + 3 * (QUARTER(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?)) - 1), 2, '00'), '-01')), '%Y-%m-%d %H:%i:%S'), ?, '+00:00'), INTERVAL #{day_start} second)", time_zone, time_zone, time_zone]
50
50
  else
51
51
  format =
52
52
  case field
@@ -64,27 +64,31 @@ module Groupdate
64
64
  "%Y-01-01 00:00:00"
65
65
  end
66
66
 
67
- ["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]
67
+ ["DATE_ADD(CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?), '#{format}'), ?, '+00:00'), INTERVAL #{day_start} second)", time_zone, time_zone]
68
68
  end
69
69
  when "PostgreSQL", "PostGIS"
70
70
  case field
71
71
  when :day_of_week
72
- ["EXTRACT(DOW from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour')::integer", time_zone]
72
+ ["EXTRACT(DOW from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
73
73
  when :hour_of_day
74
- ["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour')::integer", time_zone]
74
+ ["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
75
75
  when :day_of_month
76
- ["EXTRACT(DAY from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour')::integer", time_zone]
76
+ ["EXTRACT(DAY from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
77
77
  when :month_of_year
78
- ["EXTRACT(MONTH from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} hour')::integer", time_zone]
78
+ ["EXTRACT(MONTH from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
79
79
  when :week # start on Sunday, not PostgreSQL default Monday
80
- ["(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]
80
+ ["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{week_start} day' - INTERVAL '#{day_start} second') AT TIME ZONE ?) + INTERVAL '#{week_start} day' + INTERVAL '#{day_start} second') AT TIME ZONE ?", time_zone, time_zone]
81
81
  else
82
- ["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{day_start} hour') AT TIME ZONE ?) + INTERVAL '#{day_start} hour') AT TIME ZONE ?", time_zone, time_zone]
82
+ ["(DATE_TRUNC('#{field}', (#{column}::timestamptz - INTERVAL '#{day_start} second') AT TIME ZONE ?) + INTERVAL '#{day_start} second') AT TIME ZONE ?", time_zone, time_zone]
83
83
  end
84
84
  else
85
85
  raise "Connection adapter not supported: #{adapter_name}"
86
86
  end
87
87
 
88
+ if adapter_name == "MySQL" && field == :week
89
+ query[0] = "CAST(#{query[0]} AS DATETIME)"
90
+ end
91
+
88
92
  group = relation.group(Groupdate::OrderHack.new(relation.send(:sanitize_sql_array, query), field, time_zone))
89
93
  if options[:series] == false
90
94
  group
@@ -126,7 +130,7 @@ module Groupdate
126
130
  lambda { |k| k.to_i }
127
131
  else
128
132
  utc = ActiveSupport::TimeZone["UTC"]
129
- lambda { |k| (k.is_a?(String) ? utc.parse(k) : k.to_time).in_time_zone(time_zone) }
133
+ lambda { |k| (k.is_a?(String) || !k.respond_to?(:to_time) ? utc.parse(k.to_s) : k.to_time).in_time_zone(time_zone) }
130
134
  end
131
135
 
132
136
  count =
@@ -153,7 +157,7 @@ module Groupdate
153
157
  end
154
158
 
155
159
  def day_start
156
- @day_start ||= (options[:day_start] || Groupdate.day_start).to_i
160
+ @day_start ||= ((options[:day_start] || Groupdate.day_start).to_f * 3600).round
157
161
  end
158
162
 
159
163
  def time_range
@@ -222,7 +226,7 @@ module Groupdate
222
226
  series =
223
227
  if multiple_groups
224
228
  keys = count.keys.map { |k| k[0...@group_index] + k[(@group_index + 1)..-1] }.uniq
225
- series = series.reverse if reverse
229
+ series = series.to_a.reverse if reverse
226
230
  keys.flat_map do |k|
227
231
  series.map { |s| k[0...@group_index] + [s] + k[@group_index..-1] }
228
232
  end
@@ -243,7 +247,7 @@ module Groupdate
243
247
  lambda do |key|
244
248
  case field
245
249
  when :hour_of_day
246
- key = sunday + key.hours + day_start.hours
250
+ key = sunday + key.hours + day_start.seconds
247
251
  when :day_of_week
248
252
  key = sunday + key.days
249
253
  when :day_of_month
@@ -268,7 +272,7 @@ module Groupdate
268
272
  end
269
273
 
270
274
  def round_time(time)
271
- time = time.to_time.in_time_zone(time_zone) - day_start.hours
275
+ time = time.to_time.in_time_zone(time_zone) - day_start.seconds
272
276
 
273
277
  time =
274
278
  case field
@@ -302,7 +306,7 @@ module Groupdate
302
306
  raise "Invalid field"
303
307
  end
304
308
 
305
- time.is_a?(Time) ? time + day_start.hours : time
309
+ time.is_a?(Time) ? time + day_start.seconds : time
306
310
  end
307
311
 
308
312
  def activerecord42?
@@ -22,5 +22,9 @@ module Groupdate
22
22
  def respond_to?(method, include_all = false)
23
23
  ActiveRecord::Calculations.method_defined?(method) || relation.respond_to?(method) || super
24
24
  end
25
+
26
+ def reverse_order_value
27
+ nil
28
+ end
25
29
  end
26
30
  end
@@ -1,3 +1,3 @@
1
1
  module Groupdate
2
- VERSION = "2.5.2"
2
+ VERSION = "2.5.3"
3
3
  end
@@ -1,11 +1,12 @@
1
1
  require_relative "test_helper"
2
+ require "ostruct"
2
3
 
3
4
  class TestEnumerable < Minitest::Test
4
5
  include TestGroupdate
5
6
 
6
7
  def test_enumerable
7
- user_a = User.new(created_at: utc.parse("2014-01-21"))
8
- user_b = User.new(created_at: utc.parse("2014-03-14"))
8
+ user_a = create_user("2014-01-21")
9
+ user_b = create_user("2014-03-14")
9
10
  expected = {
10
11
  utc.parse("2014-01-01") => [user_a],
11
12
  utc.parse("2014-02-01") => [],
@@ -19,6 +20,31 @@ class TestEnumerable < Minitest::Test
19
20
  end
20
21
 
21
22
  def call_method(method, field, options)
22
- Hash[User.all.to_a.group_by_period(method, options) { |u| u.send(field) }.map { |k, v| [k, v.size] }]
23
+ Hash[@users.group_by_period(method, options) { |u| u.send(field) }.map { |k, v| [k, v.size] }]
24
+ end
25
+
26
+ def create_user(created_at, score = 1)
27
+ user =
28
+ OpenStruct.new(
29
+ name: "Andrew",
30
+ score: score,
31
+ created_at: created_at ? utc.parse(created_at) : nil,
32
+ created_on: created_at ? Date.parse(created_at) : nil
33
+ )
34
+ @users << user
35
+ user
36
+ end
37
+
38
+ def setup
39
+ super
40
+ @users = []
41
+ end
42
+
43
+ def teardown
44
+ # do nothing
45
+ end
46
+
47
+ def enumerable_test?
48
+ true
23
49
  end
24
50
  end
@@ -2,9 +2,14 @@ require_relative "test_helper"
2
2
 
3
3
  class TestMysql < Minitest::Test
4
4
  include TestGroupdate
5
+ include TestDatabase
5
6
 
6
7
  def setup
7
8
  super
8
- User.establish_connection adapter: "mysql2", database: "groupdate_test", username: "root"
9
+ @@setup ||= begin
10
+ ActiveRecord::Base.establish_connection adapter: "mysql2", database: "groupdate_test", username: "root"
11
+ create_tables
12
+ true
13
+ end
9
14
  end
10
15
  end
@@ -2,13 +2,14 @@ require_relative "test_helper"
2
2
 
3
3
  class TestPostgresql < Minitest::Test
4
4
  include TestGroupdate
5
+ include TestDatabase
5
6
 
6
7
  def setup
7
8
  super
8
- User.establish_connection adapter: "postgresql", database: "groupdate_test"
9
- end
10
-
11
- def test_no_column
12
- assert_raises(ArgumentError) { User.group_by_day.first }
9
+ @@setup ||= begin
10
+ ActiveRecord::Base.establish_connection adapter: "postgresql", database: "groupdate_test"
11
+ create_tables
12
+ true
13
+ end
13
14
  end
14
15
  end
@@ -3,6 +3,7 @@ Bundler.require(:default)
3
3
  require "minitest/autorun"
4
4
  require "minitest/pride"
5
5
  require "logger"
6
+ require "active_record"
6
7
 
7
8
  Minitest::Test = Minitest::Unit::TestCase unless defined?(Minitest::Test)
8
9
 
@@ -32,13 +33,14 @@ time: {
32
33
  }
33
34
 
34
35
  # migrations
35
- %w(postgresql mysql2).each do |adapter|
36
- ActiveRecord::Base.establish_connection adapter: adapter, database: "groupdate_test", username: adapter == "mysql2" ? "root" : nil
36
+ def create_tables
37
+ ActiveRecord::Migration.verbose = false
37
38
 
38
39
  ActiveRecord::Migration.create_table :users, force: true do |t|
39
40
  t.string :name
40
41
  t.integer :score
41
42
  t.timestamp :created_at
43
+ t.date :created_on
42
44
  end
43
45
 
44
46
  ActiveRecord::Migration.create_table :posts, force: true do |t|
@@ -47,6 +49,304 @@ time: {
47
49
  end
48
50
  end
49
51
 
52
+ module TestDatabase
53
+ def test_zeros_previous_scope
54
+ create_user "2013-05-01 00:00:00 UTC"
55
+ expected = {
56
+ utc.parse("2013-05-01 00:00:00 UTC") => 0
57
+ }
58
+ 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
59
+ end
60
+
61
+ def test_order_hour_of_day
62
+ assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").count.keys.first
63
+ end
64
+
65
+ def test_order_hour_of_day_case
66
+ assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day DESC").count.keys.first
67
+ end
68
+
69
+ def test_order_hour_of_day_reverse
70
+ skip if ActiveRecord::VERSION::MAJOR == 5
71
+ assert_equal 23, User.group_by_hour_of_day(:created_at).reverse_order.count.keys.first
72
+ end
73
+
74
+ def test_order_hour_of_day_order_reverse
75
+ skip if ActiveRecord::VERSION::MAJOR == 5
76
+ assert_equal 0, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").reverse_order.count.keys.first
77
+ end
78
+
79
+ def test_table_name
80
+ assert_empty User.group_by_day("users.created_at").count
81
+ end
82
+
83
+ def test_previous_scopes
84
+ create_user "2013-05-01 00:00:00 UTC"
85
+ assert_empty User.where("id = 0").group_by_day(:created_at).count
86
+ end
87
+
88
+ def test_where_after
89
+ create_user "2013-05-01 00:00:00 UTC"
90
+ create_user "2013-05-02 00:00:00 UTC"
91
+ expected = {utc.parse("2013-05-02 00:00:00 UTC") => 1}
92
+ assert_equal expected, User.group_by_day(:created_at).where("created_at > ?", "2013-05-01 00:00:00 UTC").count
93
+ end
94
+
95
+ def test_group_before
96
+ create_user "2013-05-01 00:00:00 UTC", 1
97
+ create_user "2013-05-02 00:00:00 UTC", 2
98
+ create_user "2013-05-03 00:00:00 UTC", 2
99
+ expected = {
100
+ [1, utc.parse("2013-05-01 00:00:00 UTC")] => 1,
101
+ [1, utc.parse("2013-05-02 00:00:00 UTC")] => 0,
102
+ [1, utc.parse("2013-05-03 00:00:00 UTC")] => 0,
103
+ [2, utc.parse("2013-05-01 00:00:00 UTC")] => 0,
104
+ [2, utc.parse("2013-05-02 00:00:00 UTC")] => 1,
105
+ [2, utc.parse("2013-05-03 00:00:00 UTC")] => 1
106
+ }
107
+ assert_equal expected, User.group(:score).group_by_day(:created_at).order(:score).count
108
+ end
109
+
110
+ def test_group_after
111
+ create_user "2013-05-01 00:00:00 UTC", 1
112
+ create_user "2013-05-02 00:00:00 UTC", 2
113
+ create_user "2013-05-03 00:00:00 UTC", 2
114
+ expected = {
115
+ [utc.parse("2013-05-01 00:00:00 UTC"), 1] => 1,
116
+ [utc.parse("2013-05-02 00:00:00 UTC"), 1] => 0,
117
+ [utc.parse("2013-05-03 00:00:00 UTC"), 1] => 0,
118
+ [utc.parse("2013-05-01 00:00:00 UTC"), 2] => 0,
119
+ [utc.parse("2013-05-02 00:00:00 UTC"), 2] => 1,
120
+ [utc.parse("2013-05-03 00:00:00 UTC"), 2] => 1
121
+ }
122
+ assert_equal expected, User.group_by_day(:created_at).group(:score).order(:score).count
123
+ end
124
+
125
+ def test_group_day_of_week
126
+ create_user "2013-05-01 00:00:00 UTC", 1
127
+ create_user "2013-05-02 00:00:00 UTC", 2
128
+ create_user "2013-05-03 00:00:00 UTC", 2
129
+ expected = {
130
+ [1, 0] => 0,
131
+ [1, 1] => 0,
132
+ [1, 2] => 0,
133
+ [1, 3] => 1,
134
+ [1, 4] => 0,
135
+ [1, 5] => 0,
136
+ [1, 6] => 0,
137
+ [2, 0] => 0,
138
+ [2, 1] => 0,
139
+ [2, 2] => 0,
140
+ [2, 3] => 0,
141
+ [2, 4] => 1,
142
+ [2, 5] => 1,
143
+ [2, 6] => 0
144
+ }
145
+ assert_equal expected, User.group(:score).group_by_day_of_week(:created_at).count
146
+ end
147
+
148
+ def test_groupdate_multiple
149
+ create_user "2013-05-01 00:00:00 UTC", 1
150
+ expected = {
151
+ [utc.parse("2013-05-01 00:00:00 UTC"), utc.parse("2013-01-01 00:00:00 UTC")] => 1
152
+ }
153
+ assert_equal expected, User.group_by_day(:created_at).group_by_year(:created_at).count
154
+ end
155
+
156
+ def test_groupdate_multiple_hour_of_day_day_of_week
157
+ create_user "2013-05-01 00:00:00 UTC", 1
158
+ expected = {}
159
+ 24.times do |i|
160
+ 7.times do |j|
161
+ expected[[i, j]] = i == 0 && j == 3 ? 1 : 0
162
+ end
163
+ end
164
+ assert_equal expected, User.group_by_hour_of_day(:created_at).group_by_day_of_week(:created_at).count
165
+ end
166
+
167
+ def test_not_modified
168
+ create_user "2013-05-01 00:00:00 UTC"
169
+ expected = {utc.parse("2013-05-01 00:00:00 UTC") => 1}
170
+ relation = User.group_by_day(:created_at)
171
+ relation.where("created_at > ?", "2013-05-01 00:00:00 UTC")
172
+ assert_equal expected, relation.count
173
+ end
174
+
175
+ def test_bad_method
176
+ assert_raises(NoMethodError) { User.group_by_day(:created_at).no_such_method }
177
+ end
178
+
179
+ def test_respond_to_where
180
+ assert User.group_by_day(:created_at).respond_to?(:order)
181
+ end
182
+
183
+ def test_respond_to_bad_method
184
+ assert !User.group_by_day(:created_at).respond_to?(:no_such_method)
185
+ end
186
+
187
+ def test_last
188
+ create_user "#{this_year - 3}-01-01 00:00:00 UTC"
189
+ create_user "#{this_year - 1}-01-01 00:00:00 UTC"
190
+ expected = {
191
+ utc.parse("#{this_year - 2}-01-01 00:00:00 UTC") => 0,
192
+ utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => 1,
193
+ utc.parse("#{this_year}-01-01 00:00:00 UTC") => 0
194
+ }
195
+ assert_equal expected, User.group_by_year(:created_at, last: 3).count
196
+ end
197
+
198
+ def test_current
199
+ create_user "#{this_year - 3}-01-01 00:00:00 UTC"
200
+ create_user "#{this_year - 1}-01-01 00:00:00 UTC"
201
+ expected = {
202
+ utc.parse("#{this_year - 2}-01-01 00:00:00 UTC") => 0,
203
+ utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => 1
204
+ }
205
+ assert_equal expected, User.group_by_year(:created_at, last: 2, current: false).count
206
+ end
207
+
208
+ def test_format_locale
209
+ create_user "2014-10-01 00:00:00 UTC"
210
+ assert_equal ({"Okt" => 1}), User.group_by_day(:created_at, format: "%b", locale: :de).count
211
+ end
212
+
213
+ def test_format_locale_by_symbol
214
+ create_user "2014-10-01 00:00:00 UTC"
215
+ assert_equal ({"Okt 1, 2014" => 1}), User.group_by_day(:created_at, format: :special, locale: :de).count
216
+ end
217
+
218
+ def test_format_locale_global
219
+ create_user "2014-10-01 00:00:00 UTC"
220
+ I18n.locale = :de
221
+ assert_equal ({"Okt" => 1}), User.group_by_day(:created_at, format: "%b").count
222
+ ensure
223
+ I18n.locale = :en
224
+ end
225
+
226
+ def test_format_multiple_groups
227
+ create_user "2014-03-01 00:00:00 UTC"
228
+ assert_equal ({["Sun", 1] => 1}), User.group_by_week(:created_at, format: "%a").group(:score).count
229
+ assert_equal ({[1, "Sun"] => 1}), User.group(:score).group_by_week(:created_at, format: "%a").count
230
+ end
231
+
232
+ # permit
233
+
234
+ def test_permit
235
+ assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:day, :created_at, permit: %w(week)).count }
236
+ end
237
+
238
+ def test_permit_bad_period
239
+ assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:bad_period, :created_at).count }
240
+ end
241
+
242
+ def test_permit_symbol_symbols
243
+ assert_equal ({}), User.group_by_period(:day, :created_at, permit: [:day]).count
244
+ end
245
+
246
+ def test_permit_string_symbols
247
+ assert_equal ({}), User.group_by_period("day", :created_at, permit: [:day]).count
248
+ end
249
+
250
+ def test_permit_symbol_strings
251
+ assert_equal ({}), User.group_by_period(:day, :created_at, permit: %w(day)).count
252
+ end
253
+
254
+ def test_permit_string_strings
255
+ assert_equal ({}), User.group_by_period("day", :created_at, permit: %w(day)).count
256
+ end
257
+
258
+ # default value
259
+
260
+ def test_default_value
261
+ create_user "#{this_year}-01-01 00:00:00 UTC"
262
+ expected = {
263
+ utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => nil,
264
+ utc.parse("#{this_year}-01-01 00:00:00 UTC") => 1
265
+ }
266
+ assert_equal expected, User.group_by_year(:created_at, last: 2, default_value: nil).count
267
+ end
268
+
269
+ # associations
270
+
271
+ def test_associations
272
+ user = create_user("2014-03-01 00:00:00 UTC")
273
+ user.posts.create!(created_at: "2014-04-01 00:00:00 UTC")
274
+ expected = {
275
+ utc.parse("2014-04-01 00:00:00 UTC") => 1
276
+ }
277
+ assert_equal expected, user.posts.group_by_day(:created_at).count
278
+ end
279
+
280
+ # activerecord default_timezone option
281
+
282
+ def test_default_timezone_local
283
+ User.default_timezone = :local
284
+ assert_raises(RuntimeError) { User.group_by_day(:created_at).count }
285
+ ensure
286
+ User.default_timezone = :utc
287
+ end
288
+
289
+ # Brasilia Summer Time
290
+
291
+ def test_brasilia_summer_time
292
+ # must parse and convert to UTC for ActiveRecord 3.1
293
+ create_user(brasilia.parse("2014-10-19 02:00:00").utc.to_s)
294
+ create_user(brasilia.parse("2014-10-20 02:00:00").utc.to_s)
295
+ expected = {
296
+ brasilia.parse("2014-10-19 01:00:00") => 1,
297
+ brasilia.parse("2014-10-20 00:00:00") => 1
298
+ }
299
+ assert_equal expected, User.group_by_day(:created_at, time_zone: "Brasilia").count
300
+ end
301
+
302
+ # carry_forward option
303
+
304
+ def test_carry_forward
305
+ create_user "2014-05-01 00:00:00 UTC"
306
+ create_user "2014-05-01 00:00:00 UTC"
307
+ create_user "2014-05-03 00:00:00 UTC"
308
+ assert_equal 2, User.group_by_day(:created_at, carry_forward: true).count[utc.parse("2014-05-02 00:00:00 UTC")]
309
+ end
310
+
311
+ # dates
312
+
313
+ def test_dates
314
+ create_user "2014-03-01 12:00:00 UTC"
315
+ assert_equal ({Date.parse("2014-03-01") => 1}), User.group_by_day(:created_at, dates: true).count
316
+ end
317
+
318
+ def test_no_column
319
+ assert_raises(ArgumentError) { User.group_by_day.first }
320
+ end
321
+
322
+ def call_method(method, field, options)
323
+ User.group_by_period(method, field, options).count
324
+ end
325
+
326
+ def create_user(created_at, score = 1)
327
+ user =
328
+ User.create!(
329
+ name: "Andrew",
330
+ score: score,
331
+ created_at: created_at ? utc.parse(created_at) : nil,
332
+ created_on: created_at ? Date.parse(created_at) : nil
333
+ )
334
+
335
+ # hack for MySQL adapter
336
+ user.update_attributes(created_at: nil, created_on: nil) if created_at.nil?
337
+
338
+ user
339
+ end
340
+
341
+ def teardown
342
+ User.delete_all
343
+ end
344
+
345
+ def enumerable_test?
346
+ false
347
+ end
348
+ end
349
+
50
350
  module TestGroupdate
51
351
  def setup
52
352
  Groupdate.week_start = :sun
@@ -55,7 +355,7 @@ module TestGroupdate
55
355
  # second
56
356
 
57
357
  def test_second_end_of_second
58
- if ActiveRecord::Base.connection.adapter_name == "Mysql2" && ActiveRecord::VERSION::STRING.starts_with?("4.2.")
358
+ if enumerable_test? || (ActiveRecord::Base.connection.adapter_name == "Mysql2" && ActiveRecord::VERSION::STRING.starts_with?("4.2."))
59
359
  skip # no millisecond precision
60
360
  else
61
361
  assert_result_time :second, "2013-05-03 00:00:00 UTC", "2013-05-03 00:00:00.999"
@@ -564,14 +864,6 @@ module TestGroupdate
564
864
  assert_equal expected, call_method(:day, :created_at, range: Time.parse("2013-05-01 00:00:00 UTC")...Time.parse("2013-05-02 00:00:00 UTC"))
565
865
  end
566
866
 
567
- def test_zeros_previous_scope
568
- create_user "2013-05-01 00:00:00 UTC"
569
- expected = {
570
- utc.parse("2013-05-01 00:00:00 UTC") => 0
571
- }
572
- 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
573
- end
574
-
575
867
  def test_zeros_datetime
576
868
  create_user "2013-05-01 00:00:00 UTC"
577
869
  expected = {
@@ -581,8 +873,7 @@ module TestGroupdate
581
873
  end
582
874
 
583
875
  def test_zeros_null_value
584
- user = User.create!(name: "Andrew")
585
- user.update_column :created_at, nil
876
+ create_user nil
586
877
  assert_equal 0, call_method(:hour_of_day, :created_at, range: true)[0]
587
878
  end
588
879
 
@@ -611,152 +902,16 @@ module TestGroupdate
611
902
 
612
903
  # misc
613
904
 
614
- def test_order_hour_of_day
615
- assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").count.keys.first
616
- end
617
-
618
- def test_order_hour_of_day_case
619
- assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day DESC").count.keys.first
620
- end
621
-
622
- def test_order_hour_of_day_reverse
623
- skip if ActiveRecord::VERSION::MAJOR == 5
624
- assert_equal 23, User.group_by_hour_of_day(:created_at).reverse_order.count.keys.first
625
- end
626
-
627
- def test_order_hour_of_day_order_reverse
628
- skip if ActiveRecord::VERSION::MAJOR == 5
629
- assert_equal 0, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").reverse_order.count.keys.first
630
- end
631
-
632
905
  def test_order_hour_of_day_reverse_option
633
906
  assert_equal 23, call_method(:hour_of_day, :created_at, reverse: true).keys.first
634
907
  end
635
908
 
636
- def test_table_name
637
- assert_empty User.group_by_day("users.created_at").count
638
- end
639
-
640
- def test_previous_scopes
641
- create_user "2013-05-01 00:00:00 UTC"
642
- assert_empty User.where("id = 0").group_by_day(:created_at).count
643
- end
644
-
645
909
  def test_time_zone
646
910
  create_user "2013-05-01 00:00:00 UTC"
647
911
  time_zone = "Pacific Time (US & Canada)"
648
912
  assert_equal time_zone, call_method(:day, :created_at, time_zone: time_zone).keys.first.time_zone.name
649
913
  end
650
914
 
651
- def test_where_after
652
- create_user "2013-05-01 00:00:00 UTC"
653
- create_user "2013-05-02 00:00:00 UTC"
654
- expected = {utc.parse("2013-05-02 00:00:00 UTC") => 1}
655
- assert_equal expected, User.group_by_day(:created_at).where("created_at > ?", "2013-05-01 00:00:00 UTC").count
656
- end
657
-
658
- def test_group_before
659
- create_user "2013-05-01 00:00:00 UTC", 1
660
- create_user "2013-05-02 00:00:00 UTC", 2
661
- create_user "2013-05-03 00:00:00 UTC", 2
662
- expected = {
663
- [1, utc.parse("2013-05-01 00:00:00 UTC")] => 1,
664
- [1, utc.parse("2013-05-02 00:00:00 UTC")] => 0,
665
- [1, utc.parse("2013-05-03 00:00:00 UTC")] => 0,
666
- [2, utc.parse("2013-05-01 00:00:00 UTC")] => 0,
667
- [2, utc.parse("2013-05-02 00:00:00 UTC")] => 1,
668
- [2, utc.parse("2013-05-03 00:00:00 UTC")] => 1
669
- }
670
- assert_equal expected, User.group(:score).group_by_day(:created_at).order(:score).count
671
- end
672
-
673
- def test_group_after
674
- create_user "2013-05-01 00:00:00 UTC", 1
675
- create_user "2013-05-02 00:00:00 UTC", 2
676
- create_user "2013-05-03 00:00:00 UTC", 2
677
- expected = {
678
- [utc.parse("2013-05-01 00:00:00 UTC"), 1] => 1,
679
- [utc.parse("2013-05-02 00:00:00 UTC"), 1] => 0,
680
- [utc.parse("2013-05-03 00:00:00 UTC"), 1] => 0,
681
- [utc.parse("2013-05-01 00:00:00 UTC"), 2] => 0,
682
- [utc.parse("2013-05-02 00:00:00 UTC"), 2] => 1,
683
- [utc.parse("2013-05-03 00:00:00 UTC"), 2] => 1
684
- }
685
- assert_equal expected, User.group_by_day(:created_at).group(:score).order(:score).count
686
- end
687
-
688
- def test_group_day_of_week
689
- create_user "2013-05-01 00:00:00 UTC", 1
690
- create_user "2013-05-02 00:00:00 UTC", 2
691
- create_user "2013-05-03 00:00:00 UTC", 2
692
- expected = {
693
- [1, 0] => 0,
694
- [1, 1] => 0,
695
- [1, 2] => 0,
696
- [1, 3] => 1,
697
- [1, 4] => 0,
698
- [1, 5] => 0,
699
- [1, 6] => 0,
700
- [2, 0] => 0,
701
- [2, 1] => 0,
702
- [2, 2] => 0,
703
- [2, 3] => 0,
704
- [2, 4] => 1,
705
- [2, 5] => 1,
706
- [2, 6] => 0
707
- }
708
- assert_equal expected, User.group(:score).group_by_day_of_week(:created_at).count
709
- end
710
-
711
- def test_groupdate_multiple
712
- create_user "2013-05-01 00:00:00 UTC", 1
713
- expected = {
714
- [utc.parse("2013-05-01 00:00:00 UTC"), utc.parse("2013-01-01 00:00:00 UTC")] => 1
715
- }
716
- assert_equal expected, User.group_by_day(:created_at).group_by_year(:created_at).count
717
- end
718
-
719
- def test_not_modified
720
- create_user "2013-05-01 00:00:00 UTC"
721
- expected = {utc.parse("2013-05-01 00:00:00 UTC") => 1}
722
- relation = User.group_by_day(:created_at)
723
- relation.where("created_at > ?", "2013-05-01 00:00:00 UTC")
724
- assert_equal expected, relation.count
725
- end
726
-
727
- def test_bad_method
728
- assert_raises(NoMethodError) { User.group_by_day(:created_at).no_such_method }
729
- end
730
-
731
- def test_respond_to_where
732
- assert User.group_by_day(:created_at).respond_to?(:order)
733
- end
734
-
735
- def test_respond_to_bad_method
736
- assert !User.group_by_day(:created_at).respond_to?(:no_such_method)
737
- end
738
-
739
- def test_last
740
- create_user "#{this_year - 3}-01-01 00:00:00 UTC"
741
- create_user "#{this_year - 1}-01-01 00:00:00 UTC"
742
- expected = {
743
- utc.parse("#{this_year - 2}-01-01 00:00:00 UTC") => 0,
744
- utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => 1,
745
- utc.parse("#{this_year}-01-01 00:00:00 UTC") => 0
746
- }
747
- assert_equal expected, User.group_by_year(:created_at, last: 3).count
748
- end
749
-
750
- def test_current
751
- create_user "#{this_year - 3}-01-01 00:00:00 UTC"
752
- create_user "#{this_year - 1}-01-01 00:00:00 UTC"
753
- expected = {
754
- utc.parse("#{this_year - 2}-01-01 00:00:00 UTC") => 0,
755
- utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => 1
756
- }
757
- assert_equal expected, User.group_by_year(:created_at, last: 2, current: false).count
758
- end
759
-
760
915
  def test_format_day
761
916
  create_user "2014-03-01 00:00:00 UTC"
762
917
  assert_format :day, "March 1, 2014", "%B %-e, %Y"
@@ -807,110 +962,32 @@ module TestGroupdate
807
962
  assert_format :month_of_year, "Jan", "%b"
808
963
  end
809
964
 
810
- def test_format_locale
811
- create_user "2014-10-01 00:00:00 UTC"
812
- assert_equal ({"Okt" => 1}), User.group_by_day(:created_at, format: "%b", locale: :de).count
813
- end
814
-
815
- def test_format_locale_by_symbol
816
- create_user "2014-10-01 00:00:00 UTC"
817
- assert_equal ({"Okt 1, 2014" => 1}), User.group_by_day(:created_at, format: :special, locale: :de).count
818
- end
819
-
820
- def test_format_locale_global
821
- create_user "2014-10-01 00:00:00 UTC"
822
- I18n.locale = :de
823
- assert_equal ({"Okt" => 1}), User.group_by_day(:created_at, format: "%b").count
824
- ensure
825
- I18n.locale = :en
826
- end
827
-
828
- def test_format_multiple_groups
829
- create_user "2014-03-01 00:00:00 UTC"
830
- assert_equal ({["Sun", 1] => 1}), User.group_by_week(:created_at, format: "%a").group(:score).count
831
- assert_equal ({[1, "Sun"] => 1}), User.group(:score).group_by_week(:created_at, format: "%a").count
832
- end
833
-
834
- # permit
835
-
836
- def test_permit
837
- assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:day, :created_at, permit: %w(week)).count }
838
- end
839
-
840
- def test_permit_bad_period
841
- assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:bad_period, :created_at).count }
842
- end
843
-
844
- def test_permit_symbol_symbols
845
- assert_equal ({}), User.group_by_period(:day, :created_at, permit: [:day]).count
846
- end
847
-
848
- def test_permit_string_symbols
849
- assert_equal ({}), User.group_by_period("day", :created_at, permit: [:day]).count
850
- end
851
-
852
- def test_permit_symbol_strings
853
- assert_equal ({}), User.group_by_period(:day, :created_at, permit: %w(day)).count
854
- end
855
-
856
- def test_permit_string_strings
857
- assert_equal ({}), User.group_by_period("day", :created_at, permit: %w(day)).count
858
- end
859
-
860
- # default value
965
+ # date column
861
966
 
862
- def test_default_value
863
- create_user "#{this_year}-01-01 00:00:00 UTC"
967
+ def test_date_column
864
968
  expected = {
865
- utc.parse("#{this_year - 1}-01-01 00:00:00 UTC") => nil,
866
- utc.parse("#{this_year}-01-01 00:00:00 UTC") => 1
969
+ Date.parse("2013-05-03") => 1
867
970
  }
868
- assert_equal expected, User.group_by_year(:created_at, last: 2, default_value: nil).count
869
- end
870
-
871
- # associations
872
-
873
- def test_associations
874
- user = create_user("2014-03-01 00:00:00 UTC")
875
- assert_empty user.posts.group_by_day(:created_at).count
876
- end
877
-
878
- # activerecord default_timezone option
879
-
880
- def test_default_timezone_local
881
- User.default_timezone = :local
882
- assert_raises(RuntimeError) { User.group_by_day(:created_at).count }
883
- ensure
884
- User.default_timezone = :utc
971
+ assert_equal expected, result(:day, "2013-05-03", false, dates: true)
885
972
  end
886
973
 
887
- # Brasilia Summer Time
888
-
889
- def test_brasilia_summer_time
890
- # must parse and convert to UTC for ActiveRecord 3.1
891
- create_user(brasilia.parse("2014-10-19 02:00:00").utc.to_s)
892
- create_user(brasilia.parse("2014-10-20 02:00:00").utc.to_s)
974
+ def test_date_column_with_time_zone
975
+ # TODO change for Groupdate 3.0
976
+ skip
893
977
  expected = {
894
- brasilia.parse("2014-10-19 01:00:00") => 1,
895
- brasilia.parse("2014-10-20 00:00:00") => 1
978
+ Date.parse("2013-05-03") => 1
896
979
  }
897
- assert_equal expected, User.group_by_day(:created_at, time_zone: "Brasilia").count
980
+ assert_equal expected, result(:day, "2013-05-03", true, dates: true)
898
981
  end
899
982
 
900
- # carry_forward option
983
+ # day start
901
984
 
902
- def test_carry_forward
903
- create_user "2014-05-01 00:00:00 UTC"
904
- create_user "2014-05-01 00:00:00 UTC"
905
- create_user "2014-05-03 00:00:00 UTC"
906
- assert_equal 2, User.group_by_day(:created_at, carry_forward: true).count[utc.parse("2014-05-02 00:00:00 UTC")]
985
+ def test_day_start_decimal_end_of_day
986
+ assert_result_time :day, "2013-05-03 02:30:00 UTC", "2013-05-04 02:29:59", false, day_start: 2.5
907
987
  end
908
988
 
909
- # dates
910
-
911
- def test_dates
912
- create_user "2014-03-01 12:00:00 UTC"
913
- assert_equal ({Date.parse("2014-03-01") => 1}), User.group_by_day(:created_at, dates: true).count
989
+ def test_day_start_decimal_start_of_day
990
+ assert_result_time :day, "2013-05-03 02:30:00 UTC", "2013-05-03 02:30:00", false, day_start: 2.5
914
991
  end
915
992
 
916
993
  # helpers
@@ -942,14 +1019,6 @@ module TestGroupdate
942
1019
  assert_equal expected, call_method(method, :created_at, options.merge(time_zone: time_zone ? "Pacific Time (US & Canada)" : nil, range: Time.parse(range_start)..Time.parse(range_end)))
943
1020
  end
944
1021
 
945
- def call_method(method, field, options)
946
- User.group_by_period(method, field, options).count
947
- end
948
-
949
- def create_user(created_at, score = 1)
950
- User.create! name: "Andrew", score: score, created_at: utc.parse(created_at)
951
- end
952
-
953
1022
  def this_year
954
1023
  Time.now.utc.year
955
1024
  end
@@ -961,8 +1030,4 @@ module TestGroupdate
961
1030
  def brasilia
962
1031
  ActiveSupport::TimeZone["Brasilia"]
963
1032
  end
964
-
965
- def teardown
966
- User.delete_all
967
- end
968
1033
  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: 2.5.2
4
+ version: 2.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-17 00:00:00.000000000 Z
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  version: '0'
161
161
  requirements: []
162
162
  rubyforge_project:
163
- rubygems_version: 2.4.5.1
163
+ rubygems_version: 2.6.1
164
164
  signing_key:
165
165
  specification_version: 4
166
166
  summary: The simplest way to group temporal data