activerecord-prunable 0.3.3 → 0.4.3

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
  SHA1:
3
- metadata.gz: 98eed29b171fce5713dbc74ab812c8d6ccd4531a
4
- data.tar.gz: 41bf6db4104667a2eff427332acdb4f6ee1423c1
3
+ metadata.gz: 8dd903bc39672f786b325d8907bfba3b4ba1d47e
4
+ data.tar.gz: 6377d77ab1c31b4d8ee4c38cd104c8e091df35a9
5
5
  SHA512:
6
- metadata.gz: 531bf56a1a4e857af793da15fb681f90d93f549671872cdfbbef07805aa30fff9a45be76d8773d9b8cf0d0a9c2a834dedaf297cc05fee59d6928c85209e04510
7
- data.tar.gz: 6aeceb2f4cc5cde6fe6634b6b1efeaec7bfa2c7eaed4da293a3f35190a431fce02ee5093f11d9fac02a0f2b3a2f8384c9d10714cd39cb23eb6f4d70d05cf3b65
6
+ metadata.gz: 502ae14d858b2b7f0997b70e1a752d165a1e553d511772a3412cbece5ce18b0b2becbc40e0a44238e6955241fa85ca5c19527da7ba12270d355ee5be245d194f
7
+ data.tar.gz: 5776ff5903da67cbf0b55c2b36f6c5b4c8605e9aa5ba6570e5160541bb2322ea7d2487fb79650a4d0d006e9a36a53d3645efc826f97a0c88e00402a859a1ba70
@@ -1,45 +1,47 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activerecord-prunable (0.3.2)
4
+ activerecord-prunable (0.4.2)
5
5
  activerecord (>= 3.0, < 6.0)
6
6
  activesupport (>= 3.0, < 6.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (4.2.10)
12
- activesupport (= 4.2.10)
11
+ activemodel (4.2.7.1)
12
+ activesupport (= 4.2.7.1)
13
13
  builder (~> 3.1)
14
- activerecord (4.2.10)
15
- activemodel (= 4.2.10)
16
- activesupport (= 4.2.10)
14
+ activerecord (4.2.7.1)
15
+ activemodel (= 4.2.7.1)
16
+ activesupport (= 4.2.7.1)
17
17
  arel (~> 6.0)
18
- activesupport (4.2.10)
18
+ activesupport (4.2.7.1)
19
19
  i18n (~> 0.7)
20
+ json (~> 1.7, >= 1.7.7)
20
21
  minitest (~> 5.1)
21
22
  thread_safe (~> 0.3, >= 0.3.4)
22
23
  tzinfo (~> 1.1)
23
- arel (6.0.4)
24
+ arel (6.0.3)
24
25
  builder (3.2.3)
25
- diff-lcs (1.3)
26
- i18n (0.8.6)
27
- minitest (5.10.3)
28
- rspec (3.6.0)
29
- rspec-core (~> 3.6.0)
30
- rspec-expectations (~> 3.6.0)
31
- rspec-mocks (~> 3.6.0)
32
- rspec-core (3.6.0)
33
- rspec-support (~> 3.6.0)
34
- rspec-expectations (3.6.0)
26
+ diff-lcs (1.2.5)
27
+ i18n (0.8.1)
28
+ json (1.8.6)
29
+ minitest (5.10.1)
30
+ rspec (3.5.0)
31
+ rspec-core (~> 3.5.0)
32
+ rspec-expectations (~> 3.5.0)
33
+ rspec-mocks (~> 3.5.0)
34
+ rspec-core (3.5.4)
35
+ rspec-support (~> 3.5.0)
36
+ rspec-expectations (3.5.0)
35
37
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.6.0)
37
- rspec-mocks (3.6.0)
38
+ rspec-support (~> 3.5.0)
39
+ rspec-mocks (3.5.0)
38
40
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.6.0)
40
- rspec-support (3.6.0)
41
+ rspec-support (~> 3.5.0)
42
+ rspec-support (3.5.0)
41
43
  thread_safe (0.3.6)
42
- tzinfo (1.2.3)
44
+ tzinfo (1.2.2)
43
45
  thread_safe (~> 0.1)
44
46
 
45
47
  PLATFORMS
@@ -50,4 +52,4 @@ DEPENDENCIES
50
52
  rspec (~> 3.0)
51
53
 
52
54
  BUNDLED WITH
53
- 1.15.4
55
+ 1.16.1
data/README.md CHANGED
@@ -34,6 +34,10 @@ __2. Define the `:prunable` scope which returns models to prune.__
34
34
  # You can also set type of removing records (:destroy or :delete).
35
35
  # By default it's :destroy
36
36
  prune_method :delete
37
+
38
+ # Additional method to set removing in batches.
39
+ # You're also able to specify batch size with number
40
+ batch_removal
37
41
  end
38
42
  ```
39
43
 
@@ -43,7 +47,7 @@ __2. Define the `:prunable` scope which returns models to prune.__
43
47
  class Notification < ApplicationRecord
44
48
  include ActiveRecord::Prunable
45
49
 
46
- prune_after 7.days
50
+ prune_after 7.days
47
51
  end
48
52
  ```
49
53
 
@@ -84,6 +88,12 @@ __Set default method of pruning (:destroy or :delete):__
84
88
  Prunable.prune!(prune_method: :delete)
85
89
  ```
86
90
 
91
+ __Batch removal:__
92
+ ```ruby
93
+ Prunable.prune!(in_batches: true)
94
+ ```
95
+ You're also able to specify the batch size: `Prunable.prune!(batch_size: 100)`
96
+
87
97
  __Call `:prunable` scope with params:__
88
98
 
89
99
  ```ruby
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "activerecord-prunable"
3
- spec.version = "0.3.3"
3
+ spec.version = "0.4.3"
4
4
  spec.authors = ["dr2m"]
5
5
  spec.email = ["maletin@maletin.work"]
6
6
 
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
 
22
22
  module ClassMethods
23
23
  def prune_method(method)
24
- unless check_prune_method(method)
24
+ unless valid_prune_method?(method)
25
25
  logger.info "Incorrect prune method #{method} has been ignored for #{self}"
26
26
  return false
27
27
  end
@@ -30,37 +30,41 @@ module ActiveRecord
30
30
  class_variable_set(:@@prune_method, method)
31
31
  end
32
32
 
33
- def prune_after(duration)
34
- prune_created_after(duration)
35
- end
36
-
37
33
  def prune_created_after(duration)
38
34
  class_variable_set(:@@prune_created_after, duration)
39
35
  end
40
36
 
37
+ alias prune_after prune_created_after
38
+
41
39
  def prune_updated_after(duration)
42
40
  class_variable_set(:@@prune_updated_after, duration)
43
41
  end
44
42
 
45
- def prune!(*params, prune_method: nil, current_time: nil)
43
+ def prune!(*params, prune_method: nil, current_time: nil, batch_size: nil, in_batches: false)
46
44
  logger.info "Pruning old records of #{self}"
47
- return false unless check_scope(*params)
45
+ return false unless prunable_model?
48
46
 
49
47
  scope = resolve_scope(*params, current_time)
50
- destroyed_records = prune_by_method(scope, prune_method)
48
+ batch_size ||= class_variable_get(:@@prunable_batch_size) if class_variable_defined?(:@@prunable_batch_size)
49
+ batch_size ||= 1000 if in_batches
50
+ destroyed_records = prune(scope, prune_method, batch_size)
51
51
 
52
- if destroyed_records > 0
53
- logger.info "#{destroyed_records} records have been removed."
54
- else
52
+ if destroyed_records.zero?
55
53
  logger.info 'Nothing to prune.'
54
+ else
55
+ logger.info "#{destroyed_records} records have been removed."
56
56
  end
57
57
 
58
58
  destroyed_records
59
59
  end
60
60
 
61
+ def batch_removal(batch_size = 1000)
62
+ class_variable_set(:@@prunable_batch_size, batch_size)
63
+ end
64
+
61
65
  private
62
66
 
63
- def check_scope(*params)
67
+ def prunable_model?
64
68
  pruning_means_count = [
65
69
  respond_to?(:prunable),
66
70
  class_variable_defined?(:@@prune_created_after),
@@ -83,33 +87,50 @@ module ActiveRecord
83
87
  def resolve_scope(*params, current_time)
84
88
  current_time ||= Time.current
85
89
 
86
- case
87
- when respond_to?(:prunable)
90
+ if respond_to?(:prunable)
88
91
  prunable(*params)
89
- when class_variable_defined?(:@@prune_created_after)
92
+ elsif class_variable_defined?(:@@prune_created_after)
90
93
  where('created_at < ?', current_time - class_variable_get(:@@prune_created_after))
91
- when class_variable_defined?(:@@prune_updated_after)
94
+ elsif class_variable_defined?(:@@prune_updated_after)
92
95
  where('updated_at < ?', current_time - class_variable_get(:@@prune_updated_after))
93
96
  end
94
97
  end
95
98
 
96
- def check_prune_method(method)
99
+ def valid_prune_method?(method)
97
100
  %i[destroy delete].include?(method)
98
101
  end
99
102
 
100
- def prune_by_method(scope, prune_method)
101
- prune_method = if class_variable_defined?(:@@prune_method)
102
- class_variable_get(:@@prune_method)
103
- else
104
- prune_method || :destroy
105
- end
106
-
107
- return false unless check_prune_method(prune_method)
103
+ def prune(scope, prune_method, batch_size)
104
+ prune_method = resolve_prune_method(prune_method)
105
+ return false unless valid_prune_method?(prune_method)
108
106
 
109
107
  logger.info "Prune method is #{prune_method}"
110
108
 
111
- return scope.delete_all if prune_method == :delete
112
- scope.destroy_all.size
109
+ pruner = pruner_for(prune_method)
110
+ return pruner.call(scope) unless batch_size
111
+
112
+ logger.info "Removing in batches, batch_size: #{batch_size}"
113
+
114
+ batch_results = scope.find_in_batches(batch_size: batch_size) do |batch|
115
+ batch_ids = batch.map(&:id)
116
+ relation = scope.model.where(id: batch_ids)
117
+ pruner.call(relation)
118
+ end
119
+
120
+ batch_results.present? ? batch_results.sum : 0
121
+ end
122
+
123
+ def resolve_prune_method(prune_method)
124
+ return class_variable_get(:@@prune_method) if class_variable_defined?(:@@prune_method)
125
+ prune_method || :destroy
126
+ end
127
+
128
+ def pruner_for(prune_method)
129
+ if prune_method == :delete
130
+ :delete_all.to_proc
131
+ else
132
+ ->(scope) { scope.destroy_all.size }
133
+ end
113
134
  end
114
135
  end
115
136
  end
@@ -11,29 +11,47 @@ module Prunable
11
11
  ActiveRecord::Prunable.includes
12
12
  end
13
13
 
14
- def prune!(*models, prune_method: nil, current_time: nil, params: [])
15
- models = self.models if models.empty?
14
+ def prune!(*args)
15
+ models, params = resolve_args(args)
16
16
 
17
17
  models.each_with_object({}) do |model, pruned|
18
- pruned[model.table_name] = model.prune!(*params, prune_method: prune_method, current_time: current_time)
18
+ pruned[model.table_name] = prune_model!(model, params)
19
19
  end
20
20
  end
21
21
 
22
- def prune(*models, prune_method: nil, current_time: nil, params: [])
23
- models = self.models if models.empty?
22
+ def prune(*args)
23
+ models, params = resolve_args(args)
24
24
 
25
25
  pruned = {}
26
26
  errors = []
27
27
 
28
28
  models.each do |model|
29
29
  begin
30
- pruned[model.table_name] = model.prune!(*params, prune_method: prune_method, current_time: current_time)
31
- rescue => e
30
+ pruned[model.table_name] = prune_model!(model, params)
31
+ rescue StandardError => e
32
32
  errors << e
33
33
  end
34
34
  end
35
35
 
36
36
  [pruned, errors]
37
37
  end
38
+
39
+ private
40
+
41
+ def resolve_args(args)
42
+ params = args.last.is_a?(Hash) ? args.pop : {}
43
+ models = args.any? ? args : self.models
44
+ [models, params]
45
+ end
46
+
47
+ def prune_model!(model, prune_method: nil, current_time: nil, params: [], batch_size: nil, in_batches: false)
48
+ model.prune!(
49
+ *params,
50
+ prune_method: prune_method,
51
+ current_time: current_time,
52
+ batch_size: batch_size,
53
+ in_batches: in_batches
54
+ )
55
+ end
38
56
  end
39
57
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-prunable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - dr2m
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-13 00:00:00.000000000 Z
11
+ date: 2018-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec