ar_aggregate_by_interval 1.1.7 → 1.2.0
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +19 -8
- data/lib/ar_aggregate_by_interval.rb +1 -1
- data/lib/ar_aggregate_by_interval/query_result.rb +0 -13
- data/lib/ar_aggregate_by_interval/query_runner.rb +12 -3
- data/lib/ar_aggregate_by_interval/utils.rb +11 -15
- data/lib/ar_aggregate_by_interval/version.rb +1 -1
- data/spec/lib/ar_aggregate_by_interval_spec.rb +28 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c7e6ecadea46b5a620c4b4a6f2e86a4bd8cbb7d
|
4
|
+
data.tar.gz: 853b144cabd27a0fdbfbc3567c560a44fdc74bc1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccc8387f47774bcd549fd82be2c73f378ef4613e87769e0f3d402e75124dd1ca6d6094bf355a835f13149128a5e5cd2bd285d0d91bad4d2d7855bfe036c87c8f
|
7
|
+
data.tar.gz: 1f9eea1a86f3da795c343efeacfea8a944f53cd6f146634e7b702557534a621daf28b727e661f48cc4c28dff6309c1bb37c309e4787d29fb126cf94412a8cc12
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
This file adheres to [Keep a changelog](http://keepachangelog.com/).
|
5
5
|
|
6
|
+
## [1.2.0] - 2015-04-05
|
7
|
+
### Added
|
8
|
+
- normalize_dates option
|
9
|
+
|
6
10
|
## [1.1.7] - 2015-03-15 (maintenance)
|
7
11
|
### Added
|
8
12
|
- Tests for from and to parameters
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# ArAggregateByInterval
|
1
|
+
# ArAggregateByInterval
|
2
|
+
## ActiveRecord time series
|
2
3
|
---
|
3
4
|
|
4
5
|
[](https://circleci.com/gh/jotto/ar_aggregate_by_interval)
|
@@ -26,15 +27,22 @@ Blog.avg_weekly(:created_at, :pageviews, 1.month.ago).values
|
|
26
27
|
|
27
28
|
## Usage
|
28
29
|
```ruby
|
29
|
-
|
30
|
-
# [:group_by_column, :from, :to, :aggregate_column]
|
31
|
-
|
32
|
-
# or just pass arguments
|
33
|
-
# count: arg_hash can be arguments: (group_by_col, from, to)
|
34
|
-
# sum and avg: arg_hash can be arguments: (group_by_col, aggregate_col, from, to)
|
35
|
-
Blog.{count,sum,avg}_{daily,weekly,monthly}(arg_hash).{values,values_and_dates}
|
30
|
+
Blog.{count,sum,avg}_{daily,weekly,monthly}(hash_or_arg_list).{values,values_and_dates}`
|
36
31
|
```
|
37
32
|
|
33
|
+
### 1. "method_missing" methods on ActiveRecord
|
34
|
+
* `{count,sum,avg}_{daily,weekly,monthly}`
|
35
|
+
|
36
|
+
### 2. pass hash or argument list
|
37
|
+
|
38
|
+
* pass a Hash
|
39
|
+
* `{:group_by_column, :from, :to, :aggregate_column, :normalize_dates}`
|
40
|
+
* or pass arguments
|
41
|
+
* when using count: `[group_by_col, from, to, options_hash]`
|
42
|
+
* when using sum or avg: `[group_by_col, aggregate_col, from, to, options_hash]`
|
43
|
+
|
44
|
+
### 3. methods you can call: `#values` or `#values_and_dates`
|
45
|
+
|
38
46
|
```ruby
|
39
47
|
#values //(returns an array of numerics)
|
40
48
|
=> [4, 2, 15, 0, 10]
|
@@ -72,3 +80,6 @@ Billing.sum_weekly({
|
|
72
80
|
to: Time.zone.now
|
73
81
|
}).values_and_dates
|
74
82
|
```
|
83
|
+
|
84
|
+
## Options
|
85
|
+
* `normalize_dates` defaults to `True` which means the `from` argument is converted to beginning_of_{day,week,month} and the `to` argument is converted to end_of_{day,week,month}
|
@@ -17,7 +17,7 @@ module ArAggregateByInterval
|
|
17
17
|
|
18
18
|
hash_args = if args.size == 1 && args.first.is_a?(Hash)
|
19
19
|
args.first
|
20
|
-
elsif args.size > 1 && !args.any?{ |a| a.is_a?(Hash) }
|
20
|
+
elsif args.size > 1 && !args[0..-2].any?{ |a| a.is_a?(Hash) }
|
21
21
|
Utils.args_to_hash(aggregate_function, interval, *args)
|
22
22
|
else
|
23
23
|
nil
|
@@ -11,9 +11,6 @@ module ArAggregateByInterval
|
|
11
11
|
VALID_HASH_ARGS = {
|
12
12
|
date_values_hash: [Hash],
|
13
13
|
|
14
|
-
# # hash with 1 key where the key is a date column and value is the column being aggegated
|
15
|
-
# ar_result_select_col_mapping: -> (v) { v.is_a?(Hash) && v.size == 1 },
|
16
|
-
|
17
14
|
from: [Date, DateTime, Time, ActiveSupport::TimeWithZone],
|
18
15
|
to: [Date, DateTime, Time, ActiveSupport::TimeWithZone],
|
19
16
|
|
@@ -23,7 +20,6 @@ module ArAggregateByInterval
|
|
23
20
|
def initialize(hash_args)
|
24
21
|
ClassyHash.validate(hash_args, VALID_HASH_ARGS)
|
25
22
|
|
26
|
-
# @dates_values_hash = Utils.ar_to_hash(args[:ar_result], args[:ar_result_select_col_mapping])
|
27
23
|
@dates_values_hash = hash_args[:date_values_hash]
|
28
24
|
@date_iterator_method = Utils::DATE_ITERATOR_METHOD_MAP[hash_args[:interval]]
|
29
25
|
|
@@ -49,15 +45,6 @@ module ArAggregateByInterval
|
|
49
45
|
|
50
46
|
private
|
51
47
|
|
52
|
-
# def validate_args!(hash_args)
|
53
|
-
# ClassyHash.validate(hash_args, VALID_HASH_ARGS)
|
54
|
-
# first_res = hash_args[:ar_result].first
|
55
|
-
# keys = hash_args[:ar_result_select_col_mapping].to_a.flatten
|
56
|
-
# if first_res && keys.any? { |key| !first_res.respond_to?(key) }
|
57
|
-
# raise RuntimeError.new("the collection passed does not respond to all attribs: #{keys}")
|
58
|
-
# end
|
59
|
-
# end
|
60
|
-
|
61
48
|
def array_of_dates
|
62
49
|
@array_of_dates ||= @from.to_date.send(@date_iterator_method, @to.to_date).map do |date|
|
63
50
|
[date, date.strftime(@strftime_format)]
|
@@ -16,7 +16,9 @@ module ArAggregateByInterval
|
|
16
16
|
from: [Date, DateTime, Time, ActiveSupport::TimeWithZone],
|
17
17
|
to: [:optional, Date, DateTime, Time, ActiveSupport::TimeWithZone],
|
18
18
|
|
19
|
-
aggregate_column: [:optional, Symbol, NilClass] # required when using sum (as opposed to count)
|
19
|
+
aggregate_column: [:optional, Symbol, NilClass], # required when using sum (as opposed to count)
|
20
|
+
|
21
|
+
normalize_dates: [:optional, TrueClass, FalseClass]
|
20
22
|
}
|
21
23
|
|
22
24
|
attr_reader :values, :values_and_dates, :from, :to, :interval
|
@@ -27,8 +29,15 @@ module ArAggregateByInterval
|
|
27
29
|
|
28
30
|
@ar_model = ar_model
|
29
31
|
|
30
|
-
@from =
|
31
|
-
@to =
|
32
|
+
@from = hash_args[:from]
|
33
|
+
@to = hash_args[:to] || Time.zone.try(:now) || Time.now
|
34
|
+
|
35
|
+
# by default, change dates to beginning and end of interval
|
36
|
+
# e.g. beginning and end of {day,week,month}
|
37
|
+
if hash_args[:normalize_dates] != false
|
38
|
+
@from = normalize_from(@from, hash_args[:interval])
|
39
|
+
@to = normalize_to(@to, hash_args[:interval])
|
40
|
+
end
|
32
41
|
|
33
42
|
@db_vendor_select =
|
34
43
|
Utils.select_for_grouping_column(hash_args[:group_by_column])[hash_args[:interval]]
|
@@ -11,19 +11,18 @@ module ArAggregateByInterval
|
|
11
11
|
|
12
12
|
# support legacy arguments (as opposed to direct hash)
|
13
13
|
# can do:
|
14
|
-
# ArModel.count_weekly(:group_by_col, :from, :to, :
|
15
|
-
# ArModel.count_weekly(:from, :to, :
|
14
|
+
# ArModel.count_weekly(:group_by_col, :from, :to, :options_hash)
|
15
|
+
# ArModel.count_weekly(:from, :to, :options_hash) # defaults to :created_at
|
16
16
|
# or
|
17
|
-
# ArModel.sum_weekly(:group_by_col, :aggregate_col, :from, :to, :
|
17
|
+
# ArModel.sum_weekly(:group_by_col, :aggregate_col, :from, :to, :options_hash)
|
18
18
|
def args_to_hash(sum_or_count, daily_weekly_monthly, *args)
|
19
|
-
group_by_column, aggregate_column, from, to,
|
19
|
+
group_by_column, aggregate_column, from, to, options_hash = args
|
20
20
|
|
21
21
|
group_by_column ||= 'created_at'
|
22
|
-
return_dates ||= false
|
23
22
|
|
24
23
|
if sum_or_count == 'count'
|
25
24
|
if aggregate_column.present? && (aggregate_column.is_a?(Date) || aggregate_column.is_a?(Time))
|
26
|
-
|
25
|
+
options_hash = to
|
27
26
|
to = from
|
28
27
|
from = aggregate_column
|
29
28
|
aggregate_column = nil
|
@@ -32,19 +31,16 @@ module ArAggregateByInterval
|
|
32
31
|
raise ArgumentError, "aggregate_column cant be nil with #{sum_or_count}"
|
33
32
|
end
|
34
33
|
|
35
|
-
|
34
|
+
if !options_hash.nil? && !options_hash.is_a?(Hash)
|
35
|
+
raise ArgumentError, 'last argument must be options hash'
|
36
|
+
end
|
37
|
+
|
38
|
+
return (options_hash || {}).merge({
|
36
39
|
group_by_column: group_by_column.try(:intern),
|
37
40
|
from: from,
|
38
41
|
to: to,
|
39
42
|
aggregate_column: aggregate_column.try(:intern)
|
40
|
-
}.delete_if { |k, v| v.nil? }
|
41
|
-
end
|
42
|
-
|
43
|
-
def ar_to_hash(ar_result, mapping)
|
44
|
-
ar_result.to_a.inject({}) do |memo, ar_obj|
|
45
|
-
mapping.each { |key, val| memo.merge!(ar_obj.send(key).to_s => ar_obj.send(val)) }
|
46
|
-
memo
|
47
|
-
end
|
43
|
+
}).delete_if { |k, v| v.nil? }
|
48
44
|
end
|
49
45
|
|
50
46
|
def ruby_strftime_map
|
@@ -15,7 +15,7 @@ describe ArAggregateByInterval do
|
|
15
15
|
@from = DateTime.parse '2013-08-05'
|
16
16
|
@to = @from
|
17
17
|
blog1 = Blog.create! arbitrary_number: 10, created_at: @from
|
18
|
-
blog2 = Blog.create! arbitrary_number: 20, created_at: @from
|
18
|
+
blog2 = Blog.create! arbitrary_number: 20, created_at: @from + 1.day
|
19
19
|
|
20
20
|
# extra row that should not be included in any of the calculations
|
21
21
|
# verifying that the from and to parameters are working
|
@@ -61,6 +61,21 @@ describe ArAggregateByInterval do
|
|
61
61
|
|
62
62
|
context 'hash args' do
|
63
63
|
|
64
|
+
context 'with normalize dates disabled' do
|
65
|
+
subject do
|
66
|
+
Blog.count_weekly({
|
67
|
+
group_by_column: :created_at,
|
68
|
+
from: @from,
|
69
|
+
to: @to,
|
70
|
+
normalize_dates: false
|
71
|
+
})
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not change dates on #{db_config}" do
|
75
|
+
expect(subject.values_and_dates).to eq([date: @from.to_date, value: 1])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
64
79
|
context 'for count' do
|
65
80
|
subject do
|
66
81
|
Blog.count_weekly({
|
@@ -112,6 +127,18 @@ describe ArAggregateByInterval do
|
|
112
127
|
|
113
128
|
context 'normal args' do
|
114
129
|
|
130
|
+
context 'with normalize dates disabled' do
|
131
|
+
subject do
|
132
|
+
Blog.count_weekly(:created_at, @from, @from, {
|
133
|
+
normalize_dates: false
|
134
|
+
})
|
135
|
+
end
|
136
|
+
|
137
|
+
it "does not change dates on #{db_config}" do
|
138
|
+
expect(subject.values_and_dates).to eq([date: @from.to_date, value: 1])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
115
142
|
context 'with to' do
|
116
143
|
subject do
|
117
144
|
Blog.count_weekly(:created_at, @from, @from)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_aggregate_by_interval
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Otto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|