groupdate 2.0.3 → 2.0.4

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: 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: {}