calculate-all 0.3.1 → 0.4.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/.github/workflows/build.yml +3 -3
- data/CHANGELOG.md +5 -0
- data/README.md +14 -1
- data/calculate-all.gemspec +1 -1
- data/gemfiles/activerecord42.gemfile +1 -1
- data/gemfiles/{activerecord51.gemfile → activerecord71.gemfile} +3 -3
- data/lib/calculate-all/version.rb +1 -1
- data/lib/calculate-all.rb +52 -43
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3928cde50fac04c8f8602ab9e83c685d190e8466febbb2c0314cf962182f99c
|
4
|
+
data.tar.gz: 83f9636ffda1f25e0faabc5454a4c731648371ba20572e5df53357f72e9b5708
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a13ddf4a236a27bebbdf1bf7f316c1137eff5eb6cfb3a0589a0f91dfa0548b6167cc4441173ca0ce4b174a156092aa50185ec5f111e54f6c0e75ee3c738d430
|
7
|
+
data.tar.gz: 95f229487220d5bb23ef2a6a50b9aef7a782e25b627c3d87716690a0673fc6890e28c3ab023481f475837a0d595baac84078ef31841c0e3b135081c61eda47b9
|
data/.github/workflows/build.yml
CHANGED
@@ -8,6 +8,8 @@ jobs:
|
|
8
8
|
include:
|
9
9
|
- ruby: "3.4"
|
10
10
|
gemfile: Gemfile
|
11
|
+
- ruby: "3.2"
|
12
|
+
gemfile: gemfiles/activerecord71.gemfile
|
11
13
|
- ruby: "3.1"
|
12
14
|
gemfile: gemfiles/activerecord70.gemfile
|
13
15
|
- ruby: "3.0"
|
@@ -16,11 +18,9 @@ jobs:
|
|
16
18
|
gemfile: gemfiles/activerecord60.gemfile
|
17
19
|
- ruby: "2.6"
|
18
20
|
gemfile: gemfiles/activerecord52.gemfile
|
19
|
-
- ruby: "2.6"
|
20
|
-
gemfile: gemfiles/activerecord51.gemfile
|
21
21
|
- ruby: "2.6"
|
22
22
|
gemfile: gemfiles/activerecord50.gemfile
|
23
|
-
- ruby: "2.
|
23
|
+
- ruby: "2.6"
|
24
24
|
gemfile: gemfiles/activerecord42.gemfile
|
25
25
|
runs-on: ubuntu-latest
|
26
26
|
env:
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,10 @@ in a single request, with support for grouping.
|
|
8
8
|
|
9
9
|
Should be useful for dashboards, timeseries stats, and charts.
|
10
10
|
|
11
|
-
Currently tested with PostgreSQL, MySQL and SQLite3, ruby >= 2.
|
11
|
+
Currently tested with PostgreSQL, MySQL and SQLite3, ruby >= 2.6, rails >= 4, groupdate >= 4.
|
12
|
+
|
13
|
+
With rails >= 7.1, `#async_calculate_all` is also available, which does the same but in a separate
|
14
|
+
db connection and ruby thread, and returns `ActiveRecord::Promise`
|
12
15
|
|
13
16
|
## Usage
|
14
17
|
|
@@ -48,6 +51,16 @@ stats = Order.group(:department_id).group(:payment_method).order(:payment_method
|
|
48
51
|
# }
|
49
52
|
```
|
50
53
|
|
54
|
+
```ruby
|
55
|
+
stats_by_department = Order.group(:department_id).async_calculate_all(:count, :price_sum)
|
56
|
+
# continue with some other expensive stuff
|
57
|
+
|
58
|
+
# later, in some view
|
59
|
+
stats_by_department.value.each do |department_id, stats|
|
60
|
+
# ...
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
51
64
|
## Rationale
|
52
65
|
|
53
66
|
Active Record makes it really easy to use most common database aggregate functions like COUNT(), MAX(), MIN(), AVG(), SUM().
|
data/calculate-all.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.required_ruby_version =
|
21
|
+
spec.required_ruby_version = ">= 2.6.0"
|
22
22
|
|
23
23
|
spec.add_dependency "activesupport", ">= 4.0.0"
|
24
24
|
end
|
@@ -5,8 +5,8 @@ gemspec path: ".."
|
|
5
5
|
gem "rake"
|
6
6
|
gem "minitest"
|
7
7
|
gem "minitest-reporters"
|
8
|
-
gem "activerecord", "~>
|
9
|
-
gem "groupdate", "~>
|
8
|
+
gem "activerecord", "~> 7.1.0"
|
9
|
+
gem "groupdate", "~> 6.0.0"
|
10
10
|
gem "pg"
|
11
11
|
gem "mysql2"
|
12
|
-
gem "sqlite3"
|
12
|
+
gem "sqlite3", "~> 1.4"
|
data/lib/calculate-all.rb
CHANGED
@@ -11,7 +11,7 @@ module CalculateAll
|
|
11
11
|
return_plain_values = true
|
12
12
|
end
|
13
13
|
|
14
|
-
named_expressions = expression_shortcuts.
|
14
|
+
named_expressions = expression_shortcuts.index_by(&:itself).merge(named_expressions)
|
15
15
|
|
16
16
|
named_expressions.transform_values! do |shortcut|
|
17
17
|
Helpers.decode_expression_shortcut(shortcut, group_values)
|
@@ -25,48 +25,55 @@ module CalculateAll
|
|
25
25
|
value_mapping = named_expressions.transform_values { |column| columns.index(column) }
|
26
26
|
columns.map! { |column| column.is_a?(String) ? Arel.sql(column) : column }
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
key = if group_values.size == 0
|
35
|
-
:ALL
|
36
|
-
elsif group_values.size == 1
|
37
|
-
# If only one group is provided, the resulting key is just a scalar value
|
38
|
-
row.first
|
39
|
-
else
|
40
|
-
# if multiple groups, the key will be an array.
|
41
|
-
row.first(group_values.size)
|
42
|
-
end
|
28
|
+
pluck(*columns).then do |rows|
|
29
|
+
results = rows.to_h do |row|
|
30
|
+
# If pluck called with a single argument
|
31
|
+
# it will return an array of scalars instead of array of arrays
|
32
|
+
row = [row] if columns.size == 1
|
43
33
|
|
44
|
-
|
34
|
+
key = if group_values.size == 0
|
35
|
+
:ALL
|
36
|
+
elsif group_values.size == 1
|
37
|
+
# If only one group is provided, the resulting key is just a scalar value
|
38
|
+
row.first
|
39
|
+
else
|
40
|
+
# if multiple groups, the key will be an array.
|
41
|
+
row.first(group_values.size)
|
42
|
+
end
|
45
43
|
|
46
|
-
|
44
|
+
value = value_mapping.transform_values { |index| row[index] }
|
47
45
|
|
48
|
-
|
49
|
-
end
|
46
|
+
value = value.values.last if return_plain_values
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
48
|
+
[key, value]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Additional groupdate magic of filling empty periods with defaults
|
52
|
+
if defined?(Groupdate.process_result)
|
53
|
+
# Since that hash is the same instance for every backfilled row, at least
|
54
|
+
# freeze it to prevent surprise modifications across multiple rows in the calling code.
|
55
|
+
default_value = return_plain_values ? nil : {}.freeze
|
56
|
+
results = Groupdate.process_result(self, results, default_value: default_value)
|
57
|
+
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
if block
|
60
|
+
results.transform_values! do |value|
|
61
|
+
return_plain_values ? block.call(value) : block.call(**value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return unwrapped hash directly for scope without any .group()
|
66
|
+
if group_values.empty?
|
67
|
+
results[:ALL]
|
68
|
+
else
|
69
|
+
results
|
62
70
|
end
|
63
71
|
end
|
72
|
+
end
|
64
73
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
results
|
74
|
+
if Gem::Version.new(ActiveRecord.version) >= Gem::Version.new('7.1.0')
|
75
|
+
def async_calculate_all(*expression_shortcuts, **named_expressions, &block)
|
76
|
+
async.calculate_all(*expression_shortcuts, **named_expressions, &block)
|
70
77
|
end
|
71
78
|
end
|
72
79
|
|
@@ -103,9 +110,16 @@ module CalculateAll
|
|
103
110
|
end
|
104
111
|
|
105
112
|
module Querying
|
106
|
-
#
|
107
|
-
def calculate_all(*
|
108
|
-
all.calculate_all(*
|
113
|
+
# see CalculateAll#calculate_all
|
114
|
+
def calculate_all(*expression_shortcuts, **named_expressions, &block)
|
115
|
+
all.calculate_all(*expression_shortcuts, **named_expressions, &block)
|
116
|
+
end
|
117
|
+
|
118
|
+
if Gem::Version.new(ActiveRecord.version) >= Gem::Version.new('7.1.0')
|
119
|
+
# see CalculateAll#async_calculate_all
|
120
|
+
def async_calculate_all(*expression_shortcuts, **named_expressions, &block)
|
121
|
+
all.async_calculate_all(*expression_shortcuts, **named_expressions, &block)
|
122
|
+
end
|
109
123
|
end
|
110
124
|
end
|
111
125
|
end
|
@@ -117,9 +131,4 @@ ActiveSupport.on_load(:active_record) do
|
|
117
131
|
# Make the calculate_all method available for all ActiveRecord::Base classes
|
118
132
|
# You can for example call Orders.calculate_all(:count, :sum_cents)
|
119
133
|
ActiveRecord::Base.extend CalculateAll::Querying
|
120
|
-
|
121
|
-
# A hack for groupdate 3.0 since it checks if the calculate_all method is defined
|
122
|
-
# on the ActiveRecord::Calculations module. It is never called but it is just
|
123
|
-
# needed for the check.
|
124
|
-
ActiveRecord::Calculations.include CalculateAll::Querying
|
125
134
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calculate-all
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Trofimenko
|
@@ -42,11 +42,11 @@ files:
|
|
42
42
|
- calculate-all.gemspec
|
43
43
|
- gemfiles/activerecord42.gemfile
|
44
44
|
- gemfiles/activerecord50.gemfile
|
45
|
-
- gemfiles/activerecord51.gemfile
|
46
45
|
- gemfiles/activerecord52.gemfile
|
47
46
|
- gemfiles/activerecord60.gemfile
|
48
47
|
- gemfiles/activerecord61.gemfile
|
49
48
|
- gemfiles/activerecord70.gemfile
|
49
|
+
- gemfiles/activerecord71.gemfile
|
50
50
|
- lib/calculate-all.rb
|
51
51
|
- lib/calculate-all/version.rb
|
52
52
|
homepage: http://github.com/codesnik/calculate-all
|
@@ -60,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 2.
|
63
|
+
version: 2.6.0
|
64
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|