calculate_in_group 0.0.1 → 0.0.2

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
  SHA256:
3
- metadata.gz: c5a7b900a5d475fc22804562ef0bac072706dcb251219b5be5c06c302f5dd75a
4
- data.tar.gz: 73fa7ceb228a9704acc409ba00b99af5d307b9cfe8739a09496097481ee5b7d0
3
+ metadata.gz: a355bb8d2b965bf9e26129775305e20c02b7d8fed65331e63aa058c4ea4d26d7
4
+ data.tar.gz: 2179b1820693525eea6ce4ba9a28d25f0c2351133c0dccad55ac90a0130178d9
5
5
  SHA512:
6
- metadata.gz: 80974131cdfb53dfc1279c516a61c72565ae29a3cc2bd181823298158a7fae24360e7fae377ab4e174984c2d4657650b93ac4d3b5b647f4bca084998d81667ab
7
- data.tar.gz: 0d6c1989fa40e2dd60e77f1897467a05dd36caf2ee581d60884e176688c0bf501c7ecb0cc940c3eb04ef25bef5f04c2689e51a70db07ead31925ebd2ae55e027
6
+ metadata.gz: 4c4988070914bff246095f5fdce43e3fa77aa1f020760fd6857ce88750f2c675e301c61c4aa9ae9cb9d81a144f498fcf6a840284f62bf8bf45d2654710cf91f7
7
+ data.tar.gz: 302d7f0906ddee7951cd7a23cb2b4248de37bb3a6686e10b7d7f261b5615a39edd92747a7e4232c50709d22ed9fc4c5fbd8f73539ca01fa706b0cec065a36edf
data/README.md CHANGED
@@ -1,11 +1,46 @@
1
- # CalculateInGroup
2
- Short description and motivation.
1
+ # calculate_in_group
2
+
3
+ [![RailsJazz](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/my_other.svg?raw=true)](https://www.railsjazz.com)
4
+ [![https://www.patreon.com/igorkasyanchuk](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/patron.svg?raw=true)](https://www.patreon.com/igorkasyanchuk)
5
+
6
+ Group ActiveRecord models with ranges. No more need to SQL with complex statements. Make your life easier :)
7
+
8
+ Can solve problems like "I need to group users by age in different categories." or "I need to do some calculations for the reports/charts".
9
+
10
+ Easy to use, just add to Gemfile `gem "calculate_in_group"` and call `calculate_in_group` on your model.
3
11
 
4
12
  ## Usage
5
- How to use my plugin.
13
+
14
+ See below how to group your model by ranges or arrays and run aggregations for them in one SQL query.
15
+
16
+ ```ruby
17
+ # Grouping can be used with :count, :average, :sum, :maximum, :minimum.
18
+
19
+ # Group with Ranges
20
+ User.calculate_in_group(:count, :age, [...10, 10...50, 50..] # => {"...10"=>1, "10...50"=>3, "50.."=>3}
21
+ User.calculate_in_group(:count, :created_at, { "old" => 12.hours.ago..1.minutes.ago, "new" => Time.now..10.hours.from_now }) # => {"old" => 2, "new" => 1}
22
+
23
+ # Group with arrays or just values
24
+ User.calculate_in_group(:count, :role, "with_permissions" => ["admin", "moderator"], "no_permissions" => "user") # => {"with_permissions" => 3, "no_permissions" => 3}
25
+
26
+ # Other agg functions
27
+ User.calculate_in_group(:average, :age, "young" => 0..25, "old" => 60..100) # => {"young" => 11.0, "old" => 80.0}
28
+ User.calculate_in_group(:average, :age, "young" => 0..25, "old" => 60...100) # => {"young" => 11.0, "old" => 60.0}
29
+ User.calculate_in_group(:maximum, :age, "young" => 0..25, "old" => 60..100) # => {"young" => 20, "old" => 100}
30
+ User.calculate_in_group(:minimum, :age, "young" => 0..25, "old" => 60..100) # => {"young" => 3, "old" => 60}
31
+ User.calculate_in_group(:sum, :age, "young" => 0..25, "old" => 60..100) # => {"young" => 33, "old" => 160}
32
+ User.calculate_in_group(:sum, :age, {"young" => 0..25, "old" => 60..100}) # => {"young" => 33, "old" => 160}
33
+
34
+ # You can specify "other values" (with custom label) which are out of ranges
35
+ User.calculate_in_group(:count, :age, {"young" => 10, "average" => 25, "old" => 60}, {include_nil: "OTHER"}) # => {"young" => 1, "old" => 1, "OTHER" => 7}
36
+
37
+ # You can specify default value for keys which are missing in query
38
+ User.calculate_in_group(:count, :age, {"young" => 10, "average" => 25, "old" => 60}, { default_for_missing: 0 }) # => {"young" => 1, "old" => 1, "average" => 0}
39
+
40
+ # SEE MORE EXAMLES in test/calculate_in_group_test.rb
41
+ ```
6
42
 
7
43
  ## Installation
8
- Add this line to your application's Gemfile:
9
44
 
10
45
  ```ruby
11
46
  gem "calculate_in_group"
@@ -16,19 +51,16 @@ And then execute:
16
51
  $ bundle
17
52
  ```
18
53
 
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install calculate_in_group
22
- ```
23
-
24
54
  ## Testing
25
55
 
26
- ruby test/calculate_in_group_test.rb
56
+ `ruby test/calculate_in_group_test.rb`.
27
57
 
28
58
  Not sure, why rake test doesn't works for me :)
29
59
 
30
60
  ## Contributing
31
- Contribution directions go here.
61
+
62
+ You are welcome to contribute or share your ideas.
32
63
 
33
64
  ## License
65
+
34
66
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,3 +1,3 @@
1
1
  module CalculateInGroup
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -3,10 +3,12 @@ require "calculate_in_group/railtie"
3
3
 
4
4
  module CalculateInGroup
5
5
  module QueryMethods
6
- def calculate_in_group(operation_type, field, groups = {}, options = {})
6
+ def calculate_in_group(operation_type, field, groups, options = {})
7
7
  # check if arguments are good
8
+ raise ArgumentError.new("Please specify options for groups. Check the documentation") if groups.empty?
8
9
  raise ArgumentError.new("Operation #{operation_type} not supported. Try to use: :count, :average, :sum, :maximum, :minimum") if ![:count, :average, :sum, :maximum, :minimum].include?(operation_type.to_s.to_sym)
9
10
  raise ArgumentError.new("Column #{field} not found in `#{table_name}`") if !column_names.include?(field.to_s)
11
+ raise ArgumentError.new("Groups `#{groups}` can be array or hash. Check the documentation") unless groups.is_a?(Array) || groups.is_a?(Hash)
10
12
 
11
13
  # init variables
12
14
  table = self.arel_table
@@ -14,14 +16,29 @@ module CalculateInGroup
14
16
  operation_attribute = "__#{operation_type}_all"
15
17
  query = Arel::Nodes::Case.new
16
18
  conditions = []
19
+ groupings = groups.is_a?(Array) ? groups.inject({}) {|res, e| res[e.to_s] = e; res} : groups
17
20
 
18
21
  # build conditions
19
- groups.each do |(k, v)|
22
+ groupings.each do |(k, v)|
20
23
  c = case v
21
24
  when Range
22
25
  # range could be endless, so we need to compact and build correct SQL for "between"
23
26
  a = table[field].gteq(v.begin) if v.begin
24
- b = table[field].lteq(v.end) if v.end
27
+ if v.end
28
+ b = if v.exclude_end? # e.g. 5...10 => [5,6,7,8,9]
29
+ # [3] pry(#<CalculateInGroupTest>)> a = 0...10
30
+ # a.to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
31
+ # [4] pry(#<CalculateInGroupTest>)> a.exclude_end?
32
+ # => true
33
+ table[field].lt(v.end)
34
+ else
35
+ # [1] pry(#<CalculateInGroupTest>)> a = 0..10
36
+ # a.to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
37
+ # [2] pry(#<CalculateInGroupTest>)> a.exclude_end?
38
+ # => false
39
+ table[field].lteq(v.end) # e.g. 5..10 => [5,6,7,8,9,10]
40
+ end
41
+ end
25
42
  [a, b].compact.inject(&:and)
26
43
  when Array
27
44
  # SQL "IN"
@@ -60,7 +77,7 @@ module CalculateInGroup
60
77
 
61
78
  # check if we need to build full hash with all grouped fields
62
79
  if options.has_key?(:default_for_missing)
63
- (groups.keys.map(&:to_s) - result.keys).each do |k|
80
+ (groupings.keys.map(&:to_s) - result.keys).each do |k|
64
81
  result[k] = options[:default_for_missing]
65
82
  end
66
83
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calculate_in_group
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk