ar_aggregate_by_interval 1.1.7 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Circle CI](https://circleci.com/gh/jotto/ar_aggregate_by_interval.svg?style=svg)](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
|