groupdate 0.0.3 → 0.1.0

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: 389dc65b32212f41266af6d39d4f422c5ed00143
4
- data.tar.gz: b0345ab008fc00b1ae2ac0dffecb1b6677e29daf
3
+ metadata.gz: 51407cdc14a5d08e4a7f50111c5d5bd91f7d2a8a
4
+ data.tar.gz: 00650eedbd754abced4b15701c631eee2baa9e61
5
5
  SHA512:
6
- metadata.gz: fe786c3908de9a1288f147b4bddac9f62d4e7f67c33734da2b94a98d1b2601ae8c35731a7cacdc0d439ba4a68d0a00dffe9554cee67ed95c907e111c44262e41
7
- data.tar.gz: 6534a271d8e8a7730b58cdd0aa73f818a92194b3ee58d2259097634544b2667ef10be5ac75cd5368841e65e7601597f44227bbec4f9414c0e1264a70c1218c0a
6
+ metadata.gz: 9528a76cc3e2a523216c18b0692c5edb4b6739c34e720e2ae35797305266125bc059b60dbe5cca9ea36e981a85b538600f9aa1ebb8613c87538066453b0c0175
7
+ data.tar.gz: 2be5da38025c0865eaaf8e8086dd146378172187972ec80efa72171331134088388d96dd2296b1567e10ab0f2ff74bd2e3b63168129abf2ddf552986d4910e3b
data/README.md CHANGED
@@ -5,12 +5,13 @@ The simplest way to group by:
5
5
  - day
6
6
  - week
7
7
  - month
8
- - hour
8
+ - day of the week
9
+ - hour of the day
9
10
  - *and more* (complete list at bottom)
10
11
 
11
12
  :tada: Time zones supported!!
12
13
 
13
- PostgreSQL only at the moment - support for other datastores coming soon
14
+ PostgreSQL and MySQL only at the moment - support for other datastores coming soon
14
15
 
15
16
  ## Usage
16
17
 
@@ -42,9 +43,9 @@ The default time zone is `Time.zone`. Pass a time zone as the second argument.
42
43
  ```ruby
43
44
  User.group_by_week(:created_at, "Pacific Time (US & Canada)").count
44
45
  # {
45
- # "2013-02-25 08:00:00+00" => 80,
46
- # "2013-03-04 08:00:00+00" => 70,
47
- # "2013-03-11 07:00:00+00" => 54
46
+ # "2013-03-03 08:00:00+00" => 80,
47
+ # "2013-03-10 08:00:00+00" => 70,
48
+ # "2013-03-17 07:00:00+00" => 54
48
49
  # }
49
50
 
50
51
  # equivalently
@@ -52,6 +53,30 @@ time_zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
52
53
  User.group_by_week(:created_at, time_zone).count
53
54
  ```
54
55
 
56
+ **Note:** Weeks start on Sunday.
57
+
58
+ You can also group by the day of the week or hour of the day.
59
+
60
+ ```ruby
61
+ # day of the week
62
+ User.group_by_day_of_week(:created_at).count
63
+ # {
64
+ # "0" => 54, # Sunday
65
+ # "1" => 2, # Monday
66
+ # ...
67
+ # "6" => 3 # Saturday
68
+ # }
69
+
70
+ # hour of the day
71
+ User.group_by_hour_of_day(:created_at, "Pacific Time (US & Canada)").count
72
+ # {
73
+ # "0" => 34,
74
+ # "1" => 61,
75
+ # ...
76
+ # "23" => 12
77
+ # }
78
+ ```
79
+
55
80
  Use it with anything you can use `group` with:
56
81
 
57
82
  ```ruby
@@ -76,19 +101,17 @@ gem 'groupdate'
76
101
 
77
102
  ## Complete list
78
103
 
79
- - microseconds
80
- - milliseconds
104
+ group_by_?
105
+
81
106
  - second
82
107
  - minute
83
108
  - hour
84
109
  - day
85
110
  - week
86
111
  - month
87
- - quarter
88
112
  - year
89
- - decade
90
- - century
91
- - millennium
113
+ - hour_of_day
114
+ - day_of_week
92
115
 
93
116
  ## Contributing
94
117
 
data/groupdate.gemspec CHANGED
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "minitest"
26
26
  spec.add_development_dependency "pg"
27
+ spec.add_development_dependency "mysql"
28
+ spec.add_development_dependency "mysql2"
27
29
  end
data/lib/groupdate.rb CHANGED
@@ -27,16 +27,61 @@ module Groupdate
27
27
  included do
28
28
  # Field list from
29
29
  # http://www.postgresql.org/docs/9.1/static/functions-datetime.html
30
- %w(microseconds milliseconds second minute hour day week month quarter year decade century millennium).each do |field|
31
- self.scope :"group_by_#{field}", lambda {|column, time_zone = Time.zone|
30
+ fields = %w(second minute hour day week month year day_of_week hour_of_day)
31
+ fields.each do |field|
32
+ self.scope :"group_by_#{field}", lambda {|unsafe_column, time_zone = Time.zone|
33
+ column = connection.quote_column_name(unsafe_column)
32
34
  time_zone ||= "Etc/UTC"
33
35
  if time_zone.is_a?(ActiveSupport::TimeZone) or time_zone = ActiveSupport::TimeZone[time_zone]
34
36
  time_zone = time_zone.tzinfo.name
35
37
  else
36
38
  raise "Unrecognized time zone"
37
39
  end
38
- sql = "DATE_TRUNC('#{field}', #{column}::timestamptz AT TIME ZONE ?) AT TIME ZONE ?"
39
- group(sanitize_sql_array([sql, time_zone, time_zone]))
40
+ query =
41
+ case connection.adapter_name
42
+ when "MySQL", "Mysql2"
43
+ case field
44
+ when "day_of_week" # Sunday = 0, Monday = 1, etc
45
+ # use CONCAT for consistent return type (String)
46
+ ["CONCAT('', DAYOFWEEK(CONVERT_TZ(#{column}, '+00:00', ?)) - 1)", time_zone]
47
+ when "hour_of_day"
48
+ ["CONCAT('', EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?)))", time_zone]
49
+ when "week"
50
+ ["CONCAT(CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL (DAYOFWEEK(CONVERT_TZ(#{column}, '+00:00', ?)) - 1) DAY), '+00:00', ?), '%Y-%m-%d 00:00:00'), ?, '+00:00'), '+00')", time_zone, time_zone, time_zone]
51
+ else
52
+ format =
53
+ case field
54
+ when "second"
55
+ "%Y-%m-%d %H:%i:%S"
56
+ when "minute"
57
+ "%Y-%m-%d %H:%i:00"
58
+ when "hour"
59
+ "%Y-%m-%d %H:00:00"
60
+ when "day"
61
+ "%Y-%m-%d 00:00:00"
62
+ when "month"
63
+ "%Y-%m-01 00:00:00"
64
+ else # year
65
+ "%Y-01-01 00:00:00"
66
+ end
67
+
68
+ ["CONCAT(CONVERT_TZ(DATE_FORMAT(CONVERT_TZ(#{column}, '+00:00', ?), '#{format}'), ?, '+00:00'), '+00')", time_zone, time_zone]
69
+ end
70
+ when "PostgreSQL"
71
+ case field
72
+ when "day_of_week"
73
+ ["EXTRACT(DOW from #{column}::timestamptz AT TIME ZONE ?)", time_zone]
74
+ when "hour_of_day"
75
+ ["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ?)", time_zone]
76
+ when "week" # start on Sunday, not PostgreSQL default Monday
77
+ ["(DATE_TRUNC('#{field}', (#{column}::timestamptz + INTERVAL '1 day') AT TIME ZONE ?) - INTERVAL '1 day') AT TIME ZONE ?", time_zone, time_zone]
78
+ else
79
+ ["DATE_TRUNC('#{field}', #{column}::timestamptz AT TIME ZONE ?) AT TIME ZONE ?", time_zone, time_zone]
80
+ end
81
+ else
82
+ raise "Connection adapter not supported"
83
+ end
84
+ group(sanitize_sql_array(query))
40
85
  }
41
86
  end
42
87
  end
@@ -1,3 +1,3 @@
1
1
  module Groupdate
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,3 +1,4 @@
1
+ require "minitest/spec"
1
2
  require "minitest/autorun"
2
3
  require "active_record"
3
4
  require "groupdate"
@@ -10,45 +11,118 @@ require "logger"
10
11
  ActiveRecord::Base.default_timezone = :utc
11
12
  ActiveRecord::Base.time_zone_aware_attributes = true
12
13
 
13
- # start connection
14
- ActiveRecord::Base.establish_connection adapter: "postgresql", database: "groupdate"
15
-
16
- # ActiveRecord::Migration.create_table :users do |t|
17
- # t.string :name
18
- # t.integer :score
19
- # t.timestamps
20
- # end
21
-
22
14
  class User < ActiveRecord::Base
23
15
  end
24
16
 
25
- class TestGroupdate < MiniTest::Unit::TestCase
26
- def setup
27
- User.delete_all
28
- [
29
- {name: "Andrew", score: 1, created_at: Time.parse("2013-04-01 00:00:00 UTC")},
30
- {name: "Jordan", score: 2, created_at: Time.parse("2013-04-01 00:00:00 UTC")},
31
- {name: "Nick", score: 3, created_at: Time.parse("2013-04-02 00:00:00 UTC")}
32
- ].each{|u| User.create!(u) }
33
- end
17
+ describe Groupdate do
18
+ %w(postgresql mysql mysql2).each do |adapter|
19
+ describe adapter do
20
+ before do
21
+ ActiveRecord::Base.establish_connection adapter: adapter, database: "groupdate"
34
22
 
35
- def test_count
36
- expected = {
37
- "2013-04-01 00:00:00+00" => 2,
38
- "2013-04-02 00:00:00+00" => 1
39
- }
40
- assert_equal expected, User.group_by_day(:created_at).count
41
- end
23
+ # ActiveRecord::Migration.create_table :users do |t|
24
+ # t.string :name
25
+ # t.integer :score
26
+ # t.timestamps
27
+ # end
42
28
 
43
- def test_time_zone
44
- expected = {
45
- "2013-03-31 07:00:00+00" => 2,
46
- "2013-04-01 07:00:00+00" => 1
47
- }
48
- assert_equal expected, User.group_by_day(:created_at, "Pacific Time (US & Canada)").count
49
- end
29
+ User.delete_all
30
+ end
31
+
32
+ it "works!" do
33
+ [
34
+ {name: "Andrew", score: 1, created_at: Time.parse("2013-04-01 00:00:10.200 UTC")},
35
+ {name: "Jordan", score: 2, created_at: Time.parse("2013-04-01 00:00:10.200 UTC")},
36
+ {name: "Nick", score: 3, created_at: Time.parse("2013-04-02 00:00:20.800 UTC")}
37
+ ].each{|u| User.create!(u) }
38
+
39
+ assert_equal(
40
+ {"2013-04-01 00:00:00+00" => 1, "2013-04-02 00:00:00+00" => 1},
41
+ User.where("score > 1").group_by_day(:created_at).count
42
+ )
43
+ end
44
+
45
+ it "group_by_second" do
46
+ create_user "2013-04-01 00:00:01 UTC"
47
+ assert_equal({"2013-04-01 00:00:01+00" => 1}, User.group_by_second(:created_at).count)
48
+ end
49
+
50
+ it "group_by_minute" do
51
+ create_user "2013-04-01 00:01:01 UTC"
52
+ assert_equal({"2013-04-01 00:01:00+00" => 1}, User.group_by_minute(:created_at).count)
53
+ end
54
+
55
+ it "group_by_hour" do
56
+ create_user "2013-04-01 01:01:01 UTC"
57
+ assert_equal({"2013-04-01 01:00:00+00" => 1}, User.group_by_hour(:created_at).count)
58
+ end
59
+
60
+ it "group_by_day" do
61
+ create_user "2013-04-01 01:01:01 UTC"
62
+ assert_equal({"2013-04-01 00:00:00+00" => 1}, User.group_by_day(:created_at).count)
63
+ end
64
+
65
+ it "group_by_day with time zone" do
66
+ create_user "2013-04-01 01:01:01 UTC"
67
+ assert_equal({"2013-03-31 07:00:00+00" => 1}, User.group_by_day(:created_at, "Pacific Time (US & Canada)").count)
68
+ end
69
+
70
+ it "group_by_week" do
71
+ create_user "2013-03-17 01:01:01 UTC"
72
+ assert_equal({"2013-03-17 00:00:00+00" => 1}, User.group_by_week(:created_at).count)
73
+ end
74
+
75
+ it "group_by_week with time zone" do # day of DST
76
+ create_user "2013-03-17 01:01:01 UTC"
77
+ assert_equal({"2013-03-10 08:00:00+00" => 1}, User.group_by_week(:created_at, "Pacific Time (US & Canada)").count)
78
+ end
79
+
80
+ it "group_by_month" do
81
+ create_user "2013-04-01 01:01:01 UTC"
82
+ assert_equal({"2013-04-01 00:00:00+00" => 1}, User.group_by_month(:created_at).count)
83
+ end
84
+
85
+ it "group_by_month with time zone" do
86
+ create_user "2013-04-01 01:01:01 UTC"
87
+ assert_equal({"2013-03-01 08:00:00+00" => 1}, User.group_by_month(:created_at, "Pacific Time (US & Canada)").count)
88
+ end
89
+
90
+ it "group_by_year" do
91
+ create_user "2013-01-01 01:01:01 UTC"
92
+ assert_equal({"2013-01-01 00:00:00+00" => 1}, User.group_by_year(:created_at).count)
93
+ end
94
+
95
+ it "group_by_year with time zone" do
96
+ create_user "2013-01-01 01:01:01 UTC"
97
+ assert_equal({"2012-01-01 08:00:00+00" => 1}, User.group_by_year(:created_at, "Pacific Time (US & Canada)").count)
98
+ end
99
+
100
+ it "group_by_hour_of_day" do
101
+ create_user "2013-01-01 11:00:00 UTC"
102
+ assert_equal({"11" => 1}, User.group_by_hour_of_day(:created_at).count)
103
+ end
104
+
105
+ it "group_by_hour_of_day with time zone" do
106
+ create_user "2013-01-01 11:00:00 UTC"
107
+ assert_equal({"3" => 1}, User.group_by_hour_of_day(:created_at, "Pacific Time (US & Canada)").count)
108
+ end
109
+
110
+ it "group_by_day_of_week" do
111
+ create_user "2013-03-03 00:00:00 UTC"
112
+ assert_equal({"0" => 1}, User.group_by_day_of_week(:created_at).count)
113
+ end
114
+
115
+ it "group_by_day_of_week with time zone" do
116
+ create_user "2013-03-03 00:00:00 UTC"
117
+ assert_equal({"6" => 1}, User.group_by_day_of_week(:created_at, "Pacific Time (US & Canada)").count)
118
+ end
119
+
120
+ # helper methods
121
+
122
+ def create_user(created_at)
123
+ User.create!(name: "Andrew", score: 1, created_at: Time.parse(created_at))
124
+ end
50
125
 
51
- def test_where
52
- assert_equal({"2013-04-02 00:00:00+00" => 1}, User.where("score > 2").group_by_day(:created_at).count)
126
+ end
53
127
  end
54
128
  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: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-18 00:00:00.000000000 Z
11
+ date: 2013-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mysql
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: mysql2
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: The simplest way to group temporal data
84
112
  email:
85
113
  - acekane1@gmail.com