delete_recursively 1.0.2 → 1.1.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/lib/delete_recursively/version.rb +1 -1
- data/lib/delete_recursively.rb +102 -34
- 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: ffee1566019b0d29f6ae829b45b0ff3ecef4fcbe05dca62d4dc592f6d3c4b13b
|
4
|
+
data.tar.gz: 3ee5fbef69a228c8195d4312d24df37ec742c91821598b89041bd002f5b79182
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffaf462ba56e68682f10540b6e972017e5ded7da75d95644a74a1bd8b2dc962cf84c85aac2561bc3663e121c61731e9bfab497e8329417a4db7254e32fdaa4fa
|
7
|
+
data.tar.gz: 640d3df7bf66b5a7c1ba5a5a42d20f297de30f82e77644c85f6325746bb28a0e35c1c475dab375ac5013be838d14229d496475cd30ffa828f96d2ef20ed0d5a9
|
data/lib/delete_recursively.rb
CHANGED
@@ -21,34 +21,78 @@ module DeleteRecursively
|
|
21
21
|
# override Association#handle_dependency to apply the new option if it is set
|
22
22
|
module DependencyHandling
|
23
23
|
def handle_dependency
|
24
|
-
|
24
|
+
if DeleteRecursively.enabled_for?(self)
|
25
|
+
delete_dependencies_recursively
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete_dependencies_recursively(force: false)
|
25
32
|
if reflection.belongs_to?
|
26
|
-
#
|
27
|
-
|
33
|
+
# Special case. The owner is already destroyed at this point,
|
34
|
+
# so we cannot use the efficient ::dependent_ids lookup. Note that this
|
35
|
+
# only happens for a single entry-record on #destroy, though.
|
36
|
+
return unless target = load_target
|
37
|
+
|
38
|
+
DeleteRecursively.delete_records_recursively(target.class, target.id, force: force)
|
28
39
|
else
|
29
|
-
|
40
|
+
DeleteRecursively.delete_recursively(reflection, owner.class, owner.id, force: force)
|
30
41
|
end
|
31
|
-
DeleteRecursively.delete_recursively(reflection, ids)
|
32
42
|
end
|
33
43
|
end
|
34
44
|
|
35
45
|
class << self
|
36
|
-
def delete_recursively(reflection,
|
37
|
-
|
38
|
-
if
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
def delete_recursively(reflection, owner_class, owner_ids, seen: [], force: false)
|
47
|
+
# Dependent deletion can be bi-directional, so we need to avoid a loop.
|
48
|
+
return if seen.include?(reflection)
|
49
|
+
|
50
|
+
seen << reflection
|
51
|
+
|
52
|
+
associated_classes(reflection).each do |record_class|
|
53
|
+
record_ids = nil # fetched only when needed for recursion, deletion, or both
|
54
|
+
|
55
|
+
if recurse_on?(reflection)
|
56
|
+
record_ids = dependent_ids(owner_class, owner_ids, reflection, record_class)
|
57
|
+
record_class.reflect_on_all_associations.each do |subref|
|
58
|
+
delete_recursively(subref, record_class, record_ids, seen: seen, force: force)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if dest_method = destructive_method(reflection, record_class, record_ids, force: force)
|
63
|
+
record_ids ||= dependent_ids(owner_class, owner_ids, reflection, record_class)
|
64
|
+
record_class.send(dest_method, record_ids)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def associated_classes(reflection)
|
70
|
+
if reflection.polymorphic?
|
71
|
+
# This ignores relatives where the inverse relation is not defined.
|
72
|
+
# The alternative to this approach would be to expensively select
|
73
|
+
# all distinct values from the *_type column:
|
74
|
+
# reflection.active_record.distinct.pluck(reflection.foreign_type)
|
75
|
+
ActiveRecord::Base.descendants.select do |klass|
|
76
|
+
klass.reflect_on_all_associations
|
77
|
+
.any? { |ref| ref.inverse_of == reflection }
|
42
78
|
end
|
79
|
+
else
|
80
|
+
[reflection.klass]
|
43
81
|
end
|
44
|
-
destroy_or_delete(reflection, record_class, record_ids)
|
45
82
|
end
|
46
83
|
|
47
|
-
def
|
48
|
-
|
49
|
-
record_class
|
50
|
-
|
51
|
-
|
84
|
+
def delete_records_recursively(record_class, record_ids, force: false)
|
85
|
+
record_class.reflect_on_all_associations.each do |ref|
|
86
|
+
delete_recursively(ref, record_class, record_ids, force: force)
|
87
|
+
end
|
88
|
+
record_class.delete(record_ids)
|
89
|
+
end
|
90
|
+
|
91
|
+
def destructive_method(reflection, record_class, record_ids, force: false)
|
92
|
+
if deleting?(reflection) || force && destructive?(reflection)
|
93
|
+
:delete
|
94
|
+
elsif destructive?(reflection)
|
95
|
+
:destroy
|
52
96
|
end
|
53
97
|
end
|
54
98
|
|
@@ -65,16 +109,19 @@ module DeleteRecursively
|
|
65
109
|
end
|
66
110
|
|
67
111
|
def deleting?(reflection)
|
68
|
-
|
112
|
+
[:delete, :delete_all, NEW_DEPENDENT_OPTION].include?(reflection.options[:dependent])
|
69
113
|
end
|
70
114
|
|
71
|
-
def dependent_ids(owner_class, owner_ids, reflection)
|
115
|
+
def dependent_ids(owner_class, owner_ids, reflection, assoc_class = nil)
|
72
116
|
if reflection.belongs_to?
|
73
|
-
|
74
|
-
|
117
|
+
owners = owner_class.where(owner_class.primary_key => owner_ids)
|
118
|
+
if reflection.polymorphic?
|
119
|
+
owners = owners.where(reflection.foreign_type => assoc_class.to_s)
|
120
|
+
end
|
121
|
+
owners.pluck(reflection.foreign_key).compact
|
75
122
|
elsif reflection.through_reflection
|
76
123
|
dependent_ids_with_through_option(owner_class, owner_ids, reflection)
|
77
|
-
else
|
124
|
+
else # plain `has_many` or `has_one`
|
78
125
|
owner_foreign_key = foreign_key(owner_class, reflection)
|
79
126
|
reflection.klass.where(owner_foreign_key => owner_ids).ids
|
80
127
|
end
|
@@ -102,16 +149,21 @@ module DeleteRecursively
|
|
102
149
|
end
|
103
150
|
|
104
151
|
def foreign_key(owner_class, reflection)
|
105
|
-
|
106
|
-
custom_foreign_key || owner_class.to_s.foreign_key
|
152
|
+
reflection && reflection.foreign_key || owner_class.to_s.foreign_key
|
107
153
|
end
|
108
154
|
|
109
|
-
def all(record_class, criteria = {})
|
155
|
+
def all(record_class, criteria = {}, seen = [])
|
156
|
+
return if seen.include?(record_class)
|
157
|
+
|
158
|
+
seen << record_class
|
159
|
+
|
110
160
|
record_class.reflect_on_all_associations.each do |reflection|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
161
|
+
associated_classes(reflection).each do |assoc_class|
|
162
|
+
if recurse_on?(reflection)
|
163
|
+
all(assoc_class, criteria, seen)
|
164
|
+
elsif deleting?(reflection)
|
165
|
+
delete_with_applicable_criteria(assoc_class, criteria)
|
166
|
+
end
|
115
167
|
end
|
116
168
|
end
|
117
169
|
delete_with_applicable_criteria(record_class, criteria)
|
@@ -128,10 +180,26 @@ end
|
|
128
180
|
|
129
181
|
require 'active_record'
|
130
182
|
|
131
|
-
|
132
|
-
|
133
|
-
|
183
|
+
module ActiveRecord
|
184
|
+
module Associations
|
185
|
+
%w[BelongsTo HasMany HasOne].each do |assoc_name|
|
186
|
+
assoc_builder = Builder.const_get(assoc_name)
|
187
|
+
assoc_builder.singleton_class.prepend(DeleteRecursively::OptionPermission)
|
134
188
|
|
135
|
-
|
136
|
-
|
189
|
+
assoc_class = const_get("#{assoc_name}Association")
|
190
|
+
assoc_class.prepend(DeleteRecursively::DependencyHandling)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class Base
|
195
|
+
def delete_recursively(force: false)
|
196
|
+
DeleteRecursively.delete_records_recursively(self.class, id, force: force)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class Relation
|
201
|
+
def delete_all_recursively(force: false)
|
202
|
+
DeleteRecursively.delete_records_recursively(klass, ids, force: force)
|
203
|
+
end
|
204
|
+
end
|
137
205
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delete_recursively
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janosch Müller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -162,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
162
|
- !ruby/object:Gem::Version
|
163
163
|
version: '0'
|
164
164
|
requirements: []
|
165
|
-
rubygems_version: 3.
|
165
|
+
rubygems_version: 3.4.0.dev
|
166
166
|
signing_key:
|
167
167
|
specification_version: 4
|
168
168
|
summary: Delete ActiveRecords efficiently
|