activerecord-prunable 0.3.3 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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