groupdate 2.0.3 → 2.0.4

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: 0f508159d00896699f39ded75030c0a5222f995b
4
- data.tar.gz: 3463e516136dec2e0f06cd321f4a8a8f7b913cab
3
+ metadata.gz: 30c3377f6edb6fe33f5d0ac0aab691a6a7a6c198
4
+ data.tar.gz: d725a9a605553a390055a4bbf55a132233aade70
5
5
  SHA512:
6
- metadata.gz: 2fc8f83f7a9d755b4b4fd4ab6066b1d90d0160e1e0e4bb21f9d4a8d28ff0fe93840747c2618d3124bccf23b7415ad0bb553f7bd53d516ed8e17f9b49ffb5d452
7
- data.tar.gz: b9f8b64e5a7a175f116a2079457d16c5d75515f791e3308a98bfc89ff4976b913e4f3e90f7cdeb762dc0aec8f95ad84168525fd594fa353b87939019421af1ee
6
+ metadata.gz: d121c447a7c6c4c6b9be3e28942c640ea4f7bb5da420314eb863d7ff9a1a648c77129afe726ae3311a61cef6a32d386fbf76e97948adc0313f0a87935f4fe181
7
+ data.tar.gz: 13e3ba1f7530160f450cb48aa1e5e67f65af979602e2c3ff0d392cc436079db1c12cd457c122e30d63e1c5cac75001af3dafb4b3839520402d1b115015200613
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ *.gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 2.0.4
2
+
3
+ - added multiple groups
4
+ - added order
5
+ - subsequent methods no longer modify relation
6
+
1
7
  # 2.0.3
2
8
 
3
9
  - implemented respond_to?
data/Gemfile CHANGED
@@ -2,12 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in groupdate.gemspec
4
4
  gemspec
5
-
6
- # gem "activerecord", github: "rails/rails"
7
- # gem "activerecord", "3.0.20"
8
- # gem "mysql2", "< 0.3.0"
9
-
10
- platform :jruby do
11
- gem "activerecord-jdbcpostgresql-adapter", :github => "jruby/activerecord-jdbc-adapter"
12
- gem "activerecord-jdbcmysql-adapter", :github => "jruby/activerecord-jdbc-adapter"
13
- end
data/README.md CHANGED
@@ -32,7 +32,7 @@ User.group_by_day(:created_at).count
32
32
  # }
33
33
  ```
34
34
 
35
- Results are returned in ascending order, so no need to sort.
35
+ Results are returned in ascending order by default, so no need to sort.
36
36
 
37
37
  You can also group by:
38
38
 
@@ -48,6 +48,8 @@ and
48
48
  - hour_of_day
49
49
  - day_of_week (Sunday = 0, Monday = 1, etc)
50
50
 
51
+ Use it anywhere you can use `group`.
52
+
51
53
  ### Time Zones
52
54
 
53
55
  The default time zone is `Time.zone`. Change this with:
@@ -105,6 +107,20 @@ To get a specific time range, use:
105
107
  User.group_by_day(:created_at, range: 2.weeks.ago.midnight..Time.now).count
106
108
  ```
107
109
 
110
+ ### Order
111
+
112
+ You can order in descending order with:
113
+
114
+ ```ruby
115
+ User.group_by_day(:created_at).reverse_order.count
116
+ ```
117
+
118
+ or
119
+
120
+ ```ruby
121
+ User.group_by_day(:created_at).order("day desc").count
122
+ ```
123
+
108
124
  ## Installation
109
125
 
110
126
  Add this line to your application’s Gemfile:
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in searchkick.gemspec
4
+ gemspec path: "../"
5
+
6
+ gem "activerecord", "3.1.12"
data/groupdate.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["acekane1@gmail.com"]
11
11
  spec.description = %q{The simplest way to group temporal data}
12
12
  spec.summary = %q{The simplest way to group temporal data}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/ankane/groupdate"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -76,7 +76,7 @@ module Groupdate
76
76
  group = group(Groupdate::OrderHack.new(sanitize_sql_array(query), field, time_zone))
77
77
  range = args[2] || options[:range] || true
78
78
  unless options[:series] == false
79
- Series.new(group, field, column, time_zone_object, range, week_start, day_start)
79
+ Series.new(group, field, column, time_zone_object, range, week_start, day_start, group.group_values.size - 1)
80
80
  else
81
81
  group
82
82
  end
@@ -1,23 +1,30 @@
1
1
  module Groupdate
2
2
  class Series
3
3
 
4
- def initialize(relation, field, column, time_zone, time_range, week_start, day_start)
5
- if time_range.is_a?(Range)
6
- # doesn't matter whether we include the end of a ... range - it will be excluded later
7
- @relation = relation.where("#{column} >= ? AND #{column} <= ?", time_range.first, time_range.last)
8
- else
9
- @relation = relation.where("#{column} IS NOT NULL")
10
- end
4
+ def initialize(relation, field, column, time_zone, time_range, week_start, day_start, group_index)
5
+ @relation = relation
11
6
  @field = field
7
+ @column = column
12
8
  @time_zone = time_zone
13
9
  @time_range = time_range
14
10
  @week_start = week_start
15
11
  @day_start = day_start
12
+ @group_index = group_index
16
13
  end
17
14
 
18
15
  def build_series(count)
19
16
  utc = ActiveSupport::TimeZone["UTC"]
20
17
 
18
+ reverse = @reverse
19
+ order = @relation.order_values.first
20
+ if order.is_a?(String)
21
+ parts = order.split(" ")
22
+ reverse_order = (parts.size == 2 && parts[0] == @field && parts[1].to_s.downcase == "desc")
23
+ reverse = !reverse if reverse_order
24
+ end
25
+
26
+ multiple_groups = @relation.group_values.size > 1
27
+
21
28
  cast_method =
22
29
  case @field
23
30
  when "day_of_week", "hour_of_day"
@@ -26,7 +33,7 @@ module Groupdate
26
33
  lambda{|k| (k.is_a?(String) ? utc.parse(k) : k.to_time).in_time_zone(@time_zone) }
27
34
  end
28
35
 
29
- count = Hash[ count.map{|k, v| [cast_method.call(k), v] } ]
36
+ count = Hash[ count.map{|k, v| [multiple_groups ? k[0...@group_index] + [cast_method.call(k[@group_index])] + k[(@group_index + 1)..-1] : cast_method.call(k), v] } ]
30
37
 
31
38
  series =
32
39
  case @field
@@ -40,7 +47,12 @@ module Groupdate
40
47
  @time_range
41
48
  else
42
49
  # use first and last values
43
- sorted_keys = count.keys.sort
50
+ sorted_keys =
51
+ if multiple_groups
52
+ count.keys.map{|k| k[@group_index] }.sort
53
+ else
54
+ count.keys.sort
55
+ end
44
56
  sorted_keys.first..sorted_keys.last
45
57
  end
46
58
 
@@ -76,12 +88,25 @@ module Groupdate
76
88
  series << series.last + step
77
89
  end
78
90
 
79
- series
91
+ if multiple_groups
92
+ keys = count.keys.map{|k| k[0...@group_index] + k[(@group_index + 1)..-1] }.uniq
93
+ series = series.reverse if reverse
94
+ keys.flat_map do |k|
95
+ series.map{|s| k[0...@group_index] + [s] + k[@group_index..-1] }
96
+ end
97
+ else
98
+ series
99
+ end
80
100
  else
81
101
  []
82
102
  end
83
103
  end
84
104
 
105
+ # reversed above if multiple groups
106
+ if !multiple_groups and reverse
107
+ series = series.to_a.reverse
108
+ end
109
+
85
110
  Hash[series.map do |k|
86
111
  [k, count[k] || 0]
87
112
  end]
@@ -90,10 +115,23 @@ module Groupdate
90
115
  def method_missing(method, *args, &block)
91
116
  # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/calculations.rb
92
117
  if ActiveRecord::Calculations.method_defined?(method)
93
- build_series(@relation.send(method, *args, &block))
118
+ relation =
119
+ if @time_range.is_a?(Range)
120
+ # doesn't matter whether we include the end of a ... range - it will be excluded later
121
+ @relation.where("#{@column} >= ? AND #{@column} <= ?", @time_range.first, @time_range.last)
122
+ else
123
+ @relation.where("#{@column} IS NOT NULL")
124
+ end
125
+
126
+ # undo reverse since we do not want this to appear in the query
127
+ if relation.reverse_order_value
128
+ @reverse = true
129
+ relation = relation.reverse_order
130
+ end
131
+
132
+ build_series(relation.send(method, *args, &block))
94
133
  elsif @relation.respond_to?(method)
95
- @relation = @relation.send(method, *args, &block)
96
- self
134
+ Groupdate::Series.new(@relation.send(method, *args, &block), @field, @column, @time_zone, @time_range, @week_start, @day_start, @group_index)
97
135
  else
98
136
  super
99
137
  end
@@ -1,3 +1,3 @@
1
1
  module Groupdate
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4"
3
3
  end
data/test/mysql_test.rb CHANGED
@@ -8,12 +8,4 @@ class TestMysql < Minitest::Unit::TestCase
8
8
  User.establish_connection :adapter => "mysql2", :database => "groupdate_test", :username => "root"
9
9
  end
10
10
 
11
- def time_key(key)
12
- key
13
- end
14
-
15
- def number_key(key)
16
- key
17
- end
18
-
19
11
  end
@@ -8,20 +8,4 @@ class TestPostgresql < Minitest::Unit::TestCase
8
8
  User.establish_connection :adapter => "postgresql", :database => "groupdate_test"
9
9
  end
10
10
 
11
- def time_key(key)
12
- if ActiveRecord::VERSION::MAJOR == 3
13
- key.utc.strftime("%Y-%m-%d %H:%M:%S+00")
14
- else
15
- key
16
- end
17
- end
18
-
19
- def number_key(key)
20
- if RUBY_PLATFORM != "java" and ActiveRecord::VERSION::MAJOR == 3
21
- key.to_s
22
- else
23
- key
24
- end
25
- end
26
-
27
11
  end
data/test/test_helper.rb CHANGED
@@ -386,7 +386,7 @@ module TestGroupdate
386
386
  7.times do |n|
387
387
  expected[n] = n == 3 ? 1 : 0
388
388
  end
389
- assert_equal expected, User.group_by_day_of_week(:created_at, range: true).count(:created_at)
389
+ assert_equal expected, User.group_by_day_of_week(:created_at, range: true).count
390
390
  end
391
391
 
392
392
  def test_zeros_hour_of_day
@@ -395,13 +395,13 @@ module TestGroupdate
395
395
  24.times do |n|
396
396
  expected[n] = n == 20 ? 1 : 0
397
397
  end
398
- assert_equal expected, User.group_by_hour_of_day(:created_at, range: true).count(:created_at)
398
+ assert_equal expected, User.group_by_hour_of_day(:created_at, range: true).count
399
399
  end
400
400
 
401
401
  def test_zeros_excludes_end
402
402
  create_user "2013-05-02 00:00:00 UTC"
403
403
  expected = {
404
- Time.parse("2013-05-01 00:00:00 UTC") => 0
404
+ utc.parse("2013-05-01 00:00:00 UTC") => 0
405
405
  }
406
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
407
407
  end
@@ -409,7 +409,7 @@ module TestGroupdate
409
409
  def test_zeros_previous_scope
410
410
  create_user "2013-05-01 00:00:00 UTC"
411
411
  expected = {
412
- Time.parse("2013-05-01 00:00:00 UTC") => 0
412
+ utc.parse("2013-05-01 00:00:00 UTC") => 0
413
413
  }
414
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
415
415
  end
@@ -417,7 +417,7 @@ module TestGroupdate
417
417
  def test_zeros_datetime
418
418
  create_user "2013-05-01 00:00:00 UTC"
419
419
  expected = {
420
- Time.parse("2013-05-01 00:00:00 UTC") => 1
420
+ utc.parse("2013-05-01 00:00:00 UTC") => 1
421
421
  }
422
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
423
423
  end
@@ -432,9 +432,9 @@ module TestGroupdate
432
432
  create_user "2013-05-01 00:00:00 UTC"
433
433
  create_user "2013-05-03 00:00:00 UTC"
434
434
  expected = {
435
- Time.parse("2013-05-01 00:00:00 UTC") => 1,
436
- Time.parse("2013-05-02 00:00:00 UTC") => 0,
437
- Time.parse("2013-05-03 00:00:00 UTC") => 1
435
+ utc.parse("2013-05-01 00:00:00 UTC") => 1,
436
+ utc.parse("2013-05-02 00:00:00 UTC") => 0,
437
+ utc.parse("2013-05-03 00:00:00 UTC") => 1
438
438
  }
439
439
  assert_equal expected, User.group_by_day(:created_at, range: true).count
440
440
  end
@@ -453,16 +453,20 @@ module TestGroupdate
453
453
 
454
454
  # misc
455
455
 
456
- def test_order_day
457
- assert_empty User.group_by_day(:created_at, series: false).order("day desc").limit(20).count
456
+ def test_order_hour_of_day
457
+ assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").count.keys.first
458
458
  end
459
459
 
460
- def test_order_week
461
- assert_empty User.group_by_week(:created_at, series: false).order("week asc").count
460
+ def test_order_hour_of_day_case
461
+ assert_equal 23, User.group_by_hour_of_day(:created_at).order("hour_of_day DESC").count.keys.first
462
462
  end
463
463
 
464
- def test_order_hour_of_day
465
- assert_empty User.group_by_hour_of_day(:created_at, series: false).order("hour_of_day desc").count
464
+ def test_order_hour_of_day_reverse
465
+ assert_equal 23, User.group_by_hour_of_day(:created_at).reverse_order.count.keys.first
466
+ end
467
+
468
+ def test_order_hour_of_day_order_reverse
469
+ assert_equal 0, User.group_by_hour_of_day(:created_at).order("hour_of_day desc").reverse_order.count.keys.first
466
470
  end
467
471
 
468
472
  def test_table_name
@@ -487,6 +491,52 @@ module TestGroupdate
487
491
  assert_equal expected, User.group_by_day(:created_at).where("created_at > ?", "2013-05-01 00:00:00 UTC").count
488
492
  end
489
493
 
494
+ def test_group_before
495
+ create_user "2013-05-01 00:00:00 UTC", 1
496
+ create_user "2013-05-02 00:00:00 UTC", 2
497
+ create_user "2013-05-03 00:00:00 UTC", 2
498
+ expected = {
499
+ [1, utc.parse("2013-05-01 00:00:00 UTC")] => 1,
500
+ [1, utc.parse("2013-05-02 00:00:00 UTC")] => 0,
501
+ [1, utc.parse("2013-05-03 00:00:00 UTC")] => 0,
502
+ [2, utc.parse("2013-05-01 00:00:00 UTC")] => 0,
503
+ [2, utc.parse("2013-05-02 00:00:00 UTC")] => 1,
504
+ [2, utc.parse("2013-05-03 00:00:00 UTC")] => 1
505
+ }
506
+ assert_equal expected, User.group(:score).group_by_day(:created_at).order(:score).count
507
+ end
508
+
509
+ def test_group_after
510
+ create_user "2013-05-01 00:00:00 UTC", 1
511
+ create_user "2013-05-02 00:00:00 UTC", 2
512
+ create_user "2013-05-03 00:00:00 UTC", 2
513
+ expected = {
514
+ [utc.parse("2013-05-01 00:00:00 UTC"), 1] => 1,
515
+ [utc.parse("2013-05-02 00:00:00 UTC"), 1] => 0,
516
+ [utc.parse("2013-05-03 00:00:00 UTC"), 1] => 0,
517
+ [utc.parse("2013-05-01 00:00:00 UTC"), 2] => 0,
518
+ [utc.parse("2013-05-02 00:00:00 UTC"), 2] => 1,
519
+ [utc.parse("2013-05-03 00:00:00 UTC"), 2] => 1
520
+ }
521
+ assert_equal expected, User.group_by_day(:created_at).group(:score).order(:score).count
522
+ end
523
+
524
+ def test_groupdate_multiple
525
+ create_user "2013-05-01 00:00:00 UTC", 1
526
+ expected = {
527
+ [utc.parse("2013-05-01 00:00:00 UTC"), utc.parse("2013-01-01 00:00:00 UTC")] => 1
528
+ }
529
+ assert_equal expected, User.group_by_day(:created_at).group_by_year(:created_at).count
530
+ end
531
+
532
+ def test_not_modified
533
+ create_user "2013-05-01 00:00:00 UTC"
534
+ expected = {utc.parse("2013-05-01 00:00:00 UTC") => 1}
535
+ relation = User.group_by_day(:created_at)
536
+ relation.where("created_at > ?", "2013-05-01 00:00:00 UTC")
537
+ assert_equal expected, relation.count
538
+ end
539
+
490
540
  def test_bad_method
491
541
  assert_raises(NoMethodError) { User.group_by_day(:created_at).no_such_method }
492
542
  end
@@ -502,31 +552,30 @@ module TestGroupdate
502
552
  # helpers
503
553
 
504
554
  def assert_result_time(method, expected, time_str, time_zone = false, options = {})
505
- assert_result method, Time.parse(expected), time_str, time_zone, options
555
+ expected = {utc.parse(expected).in_time_zone(time_zone ? "Pacific Time (US & Canada)" : utc) => 1}
556
+ assert_equal expected, result(method, time_str, time_zone, options)
506
557
  end
507
558
 
508
559
  def assert_result(method, expected, time_str, time_zone = false, options = {})
560
+ assert_equal 1, result(method, time_str, time_zone, options)[expected]
561
+ end
562
+
563
+ def result(method, time_str, time_zone = false, options = {})
509
564
  create_user time_str
510
- expected = expected.is_a?(Time) ? time_key(expected) : number_key(expected)
511
- 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
512
- assert_equal 1, User.send(:"group_by_#{method}", :created_at, options.merge(time_zone: time_zone ? "Pacific Time (US & Canada)" : nil)).count[expected]
565
+ User.send(:"group_by_#{method}", :created_at, options.merge(time_zone: time_zone ? "Pacific Time (US & Canada)" : nil)).count
513
566
  end
514
567
 
515
568
  def assert_zeros(method, created_at, keys, range_start, range_end, time_zone = nil, options = {})
516
569
  create_user created_at
517
570
  expected = {}
518
571
  keys.each_with_index do |key, i|
519
- expected[Time.parse(key)] = i == 1 ? 1 : 0
572
+ expected[utc.parse(key).in_time_zone(time_zone ? "Pacific Time (US & Canada)" : utc)] = i == 1 ? 1 : 0
520
573
  end
521
574
  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
522
575
  end
523
576
 
524
- def ordered_hash(hash)
525
- RUBY_VERSION =~ /1\.8/ ? hash.inject(ActiveSupport::OrderedHash.new){|h, (k, v)| h[k] = v; h } : hash
526
- end
527
-
528
- def create_user(created_at)
529
- User.create! :name => "Andrew", :score => 1, :created_at => utc.parse(created_at)
577
+ def create_user(created_at, score = 1)
578
+ User.create! :name => "Andrew", :score => score, :created_at => utc.parse(created_at)
530
579
  end
531
580
 
532
581
  def utc
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.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-12 00:00:00.000000000 Z
11
+ date: 2014-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -108,6 +108,7 @@ files:
108
108
  - LICENSE.txt
109
109
  - README.md
110
110
  - Rakefile
111
+ - gemfiles/activerecord31.gemfile
111
112
  - groupdate.gemspec
112
113
  - lib/groupdate.rb
113
114
  - lib/groupdate/order_hack.rb
@@ -117,7 +118,7 @@ files:
117
118
  - test/mysql_test.rb
118
119
  - test/postgresql_test.rb
119
120
  - test/test_helper.rb
120
- homepage: ''
121
+ homepage: https://github.com/ankane/groupdate
121
122
  licenses:
122
123
  - MIT
123
124
  metadata: {}