groupdate 2.5.2 → 2.5.3

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
  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