rollups 0.1.2 → 0.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 +13 -0
- data/LICENSE.txt +1 -1
- data/README.md +8 -2
- data/lib/rollup/aggregator.rb +25 -13
- data/lib/rollup/version.rb +1 -1
- data/lib/rollup.rb +1 -1
- data/lib/rollups.rb +1 -0
- metadata +8 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bc765589c1bb3ac755335e36a1a283ef4aeac8ac54a6bc102d3358c57768628
|
4
|
+
data.tar.gz: 0eab24b5cd948823ab190674618fec7ce0935b91d740384854e0474b931d9318
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a64dd7d050f06d49a5d8261b09b0437faf7a579e086b154903daf86de86ad799a1b97c98d44149b0e0fb20e4531a9d435b787adccefff7b89afb91f4cc44af3
|
7
|
+
data.tar.gz: 60ac29b15fb518bfaad4026ca02d55a926a829f1229f758993a07cace6117030247211750fb1bc33deb9547e55e406ab81e1a06f2ecc3f9208d626d62744aa3c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## 0.2.0 (2022-04-05)
|
2
|
+
|
3
|
+
- Added `range` option
|
4
|
+
- Dropped support for Active Record < 5.2
|
5
|
+
|
6
|
+
## 0.1.4 (2021-12-15)
|
7
|
+
|
8
|
+
- Fixed warning with Active Record 7
|
9
|
+
|
10
|
+
## 0.1.3 (2021-10-20)
|
11
|
+
|
12
|
+
- Fixed issue rolling up rollups
|
13
|
+
|
1
14
|
## 0.1.2 (2021-06-07)
|
2
15
|
|
3
16
|
- Fixed deprecation warning with Active Record 6.1
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -11,13 +11,13 @@ Works great with [Ahoy](https://github.com/ankane/ahoy) and [Searchjoy](https://
|
|
11
11
|
Add this line to your application’s Gemfile:
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
gem
|
14
|
+
gem "rollups"
|
15
15
|
```
|
16
16
|
|
17
17
|
For Rails < 6, also add:
|
18
18
|
|
19
19
|
```ruby
|
20
|
-
gem
|
20
|
+
gem "activerecord-import"
|
21
21
|
```
|
22
22
|
|
23
23
|
And run:
|
@@ -173,6 +173,12 @@ To recalculate the last few intervals, use:
|
|
173
173
|
User.rollup("New users", last: 3)
|
174
174
|
```
|
175
175
|
|
176
|
+
To recalculate a time range, use:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
User.rollup("New users", range: 1.week.ago.all_week)
|
180
|
+
```
|
181
|
+
|
176
182
|
To only store data for completed intervals, use:
|
177
183
|
|
178
184
|
```ruby
|
data/lib/rollup/aggregator.rb
CHANGED
@@ -4,13 +4,15 @@ class Rollup
|
|
4
4
|
@klass = klass # or relation
|
5
5
|
end
|
6
6
|
|
7
|
-
def rollup(name, column: nil, interval: "day", dimension_names: nil, time_zone: nil, current:
|
7
|
+
def rollup(name, column: nil, interval: "day", dimension_names: nil, time_zone: nil, current: nil, last: nil, clear: false, range: nil, &block)
|
8
8
|
raise "Name can't be blank" if name.blank?
|
9
9
|
|
10
10
|
column ||= @klass.rollup_column || :created_at
|
11
|
-
|
11
|
+
# Groupdate 6+ validates, but keep this for now for additional safety
|
12
|
+
# no need to quote/resolve column here, as Groupdate handles it
|
13
|
+
column = validate_column(column)
|
12
14
|
|
13
|
-
relation = perform_group(name, column: column, interval: interval, time_zone: time_zone, current: current, last: last, clear: clear)
|
15
|
+
relation = perform_group(name, column: column, interval: interval, time_zone: time_zone, current: current, last: last, clear: clear, range: range)
|
14
16
|
result = perform_calculation(relation, &block)
|
15
17
|
|
16
18
|
dimension_names = set_dimension_names(dimension_names, relation)
|
@@ -23,18 +25,24 @@ class Rollup
|
|
23
25
|
|
24
26
|
# basic version of Active Record disallow_raw_sql!
|
25
27
|
# symbol = column (safe), Arel node = SQL (safe), other = untrusted
|
26
|
-
#
|
27
|
-
# TODO remove this method when gem depends on Groupdate 6+
|
28
|
+
# matches table.column and column
|
28
29
|
def validate_column(column)
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
unless column.is_a?(Symbol) || column.is_a?(Arel::Nodes::SqlLiteral)
|
31
|
+
column = column.to_s
|
32
|
+
unless /\A\w+(\.\w+)?\z/i.match(column)
|
33
|
+
raise ActiveRecord::UnknownAttributeReference, "Query method called with non-attribute argument(s): #{column.inspect}. Use Arel.sql() for known-safe values."
|
34
|
+
end
|
32
35
|
end
|
36
|
+
column
|
33
37
|
end
|
34
38
|
|
35
|
-
def perform_group(name, column:, interval:, time_zone:, current:, last:, clear:)
|
39
|
+
def perform_group(name, column:, interval:, time_zone:, current:, last:, clear:, range:)
|
40
|
+
raise ArgumentError, "Cannot use last and range together" if last && range
|
36
41
|
raise ArgumentError, "Cannot use last and clear together" if last && clear
|
42
|
+
raise ArgumentError, "Cannot use range and clear together" if range && clear
|
43
|
+
raise ArgumentError, "Cannot use range and current together" if range && !current.nil?
|
37
44
|
|
45
|
+
current = true if current.nil?
|
38
46
|
time_zone ||= Rollup.time_zone
|
39
47
|
|
40
48
|
gd_options = {
|
@@ -48,10 +56,14 @@ class Rollup
|
|
48
56
|
|
49
57
|
if last
|
50
58
|
gd_options[:last] = last
|
59
|
+
elsif range
|
60
|
+
gd_options[:range] = range
|
61
|
+
gd_options[:expand_range] = true
|
62
|
+
gd_options.delete(:current)
|
51
63
|
elsif !clear
|
52
64
|
# if no rollups, compute all intervals
|
53
65
|
# if rollups, recompute last interval
|
54
|
-
max_time = Rollup.where(name: name, interval: interval).maximum(Utils.time_sql(interval))
|
66
|
+
max_time = Rollup.unscoped.where(name: name, interval: interval).maximum(Utils.time_sql(interval))
|
55
67
|
if max_time
|
56
68
|
# for MySQL on Ubuntu 18.04 (and likely other platforms)
|
57
69
|
if max_time.is_a?(String)
|
@@ -157,7 +169,7 @@ class Rollup
|
|
157
169
|
def maybe_clear(clear, name, interval)
|
158
170
|
if clear
|
159
171
|
Rollup.transaction do
|
160
|
-
Rollup.where(name: name, interval: interval).delete_all
|
172
|
+
Rollup.unscoped.where(name: name, interval: interval).delete_all
|
161
173
|
yield
|
162
174
|
end
|
163
175
|
else
|
@@ -173,10 +185,10 @@ class Rollup
|
|
173
185
|
|
174
186
|
if ActiveRecord::VERSION::MAJOR >= 6
|
175
187
|
options = Utils.mysql? ? {} : {unique_by: conflict_target}
|
176
|
-
Rollup.upsert_all(records, **options)
|
188
|
+
Rollup.unscoped.upsert_all(records, **options)
|
177
189
|
else
|
178
190
|
update = Utils.mysql? ? [:value] : {columns: [:value], conflict_target: conflict_target}
|
179
|
-
Rollup.import(records,
|
191
|
+
Rollup.unscoped.import(records,
|
180
192
|
on_duplicate_key_update: update,
|
181
193
|
validate: false
|
182
194
|
)
|
data/lib/rollup/version.rb
CHANGED
data/lib/rollup.rb
CHANGED
@@ -75,7 +75,7 @@ class Rollup < ActiveRecord::Base
|
|
75
75
|
# feels cleaner than overriding _read_attribute
|
76
76
|
def inspect
|
77
77
|
if Utils.date_interval?(interval)
|
78
|
-
super.sub(/time: "[^"]+"/, "time: \"#{time.
|
78
|
+
super.sub(/time: "[^"]+"/, "time: \"#{time.to_formatted_s(:db)}\"")
|
79
79
|
else
|
80
80
|
super
|
81
81
|
end
|
data/lib/rollups.rb
CHANGED
metadata
CHANGED
@@ -1,31 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rollups
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.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:
|
11
|
+
date: 2022-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '5.1'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '5.1'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: groupdate
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - ">="
|
@@ -39,105 +25,21 @@ dependencies:
|
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '5.2'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '5'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '5'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: activerecord
|
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: pg
|
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'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: mysql2
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: sqlite3
|
28
|
+
name: groupdate
|
127
29
|
requirement: !ruby/object:Gem::Requirement
|
128
30
|
requirements:
|
129
31
|
- - ">="
|
130
32
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
132
|
-
type: :
|
33
|
+
version: '6.1'
|
34
|
+
type: :runtime
|
133
35
|
prerelease: false
|
134
36
|
version_requirements: !ruby/object:Gem::Requirement
|
135
37
|
requirements:
|
136
38
|
- - ">="
|
137
39
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
40
|
+
version: '6.1'
|
139
41
|
description:
|
140
|
-
email: andrew@
|
42
|
+
email: andrew@ankane.org
|
141
43
|
executables: []
|
142
44
|
extensions: []
|
143
45
|
extra_rdoc_files: []
|
@@ -173,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
75
|
- !ruby/object:Gem::Version
|
174
76
|
version: '0'
|
175
77
|
requirements: []
|
176
|
-
rubygems_version: 3.
|
78
|
+
rubygems_version: 3.3.7
|
177
79
|
signing_key:
|
178
80
|
specification_version: 4
|
179
81
|
summary: Rollup time-series data in Rails
|