kakurenbo 0.1.3 → 0.2.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/.travis.yml +2 -3
- data/Gemfile +4 -0
- data/README.md +24 -12
- data/kakurenbo.gemspec +2 -2
- data/lib/kakurenbo.rb +8 -1
- data/lib/kakurenbo/{soft_delete_core.rb → core.rb} +76 -53
- data/lib/kakurenbo/mixin_ar_base.rb +38 -15
- data/lib/kakurenbo/mixin_ar_relation.rb +82 -0
- data/lib/kakurenbo/version.rb +1 -1
- data/spec/kakurenbo/cores/associations_spec.rb +178 -0
- data/spec/kakurenbo/cores/callbacks_spec.rb +102 -0
- data/spec/kakurenbo/cores/core_spec.rb +186 -0
- data/spec/kakurenbo/cores/scopes_spec.rb +96 -0
- data/spec/kakurenbo/mixin_ar_base_spec.rb +65 -46
- data/spec/kakurenbo/mixin_ar_relation_spec.rb +117 -0
- data/spec/spec_helper.rb +15 -2
- metadata +19 -16
- data/spec/kakurenbo/soft_delete_cores/associations_spec.rb +0 -270
- data/spec/kakurenbo/soft_delete_cores/callbacks_spec.rb +0 -38
- data/spec/kakurenbo/soft_delete_cores/core_spec.rb +0 -229
- data/spec/kakurenbo/soft_delete_cores/scopes_spec.rb +0 -60
data/lib/kakurenbo/version.rb
CHANGED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
#
|
4
|
+
# NormalChildModel [has_many]
|
5
|
+
# ParentModel < ParanoidChildModel [has_many]
|
6
|
+
# ParanoidSingleChildModel [has_many][belongs_to]
|
7
|
+
#
|
8
|
+
describe Kakurenbo::Core do
|
9
|
+
create_temp_table(:parent_models) { |t| t.integer :child_belongs_to_id; t.datetime :deleted_at }
|
10
|
+
create_temp_table(:normal_child_models) { |t| t.integer :parent_model_id }
|
11
|
+
create_temp_table(:paranoid_child_models) { |t| t.integer :parent_model_id; t.datetime :deleted_at }
|
12
|
+
create_temp_table(:paranoid_single_child_models) { |t| t.integer :parent_model_id; t.datetime :deleted_at }
|
13
|
+
|
14
|
+
subject :subject_soft_delete do
|
15
|
+
create_unrelated_children
|
16
|
+
expect { parent.destroy! }.to change(child_class, :count).by(children.length * -1)
|
17
|
+
end
|
18
|
+
|
19
|
+
subject :subject_restore do
|
20
|
+
create_unrelated_children
|
21
|
+
expect { parent.destroy! }.to change(child_class, :count).by(children.length * -1)
|
22
|
+
expect { parent.restore! }.to change(child_class, :count).by(children.length)
|
23
|
+
end
|
24
|
+
|
25
|
+
subject :subject_not_restore do
|
26
|
+
parent.destroy!
|
27
|
+
expect { parent.restore! }.not_to change(child_class, :count)
|
28
|
+
end
|
29
|
+
|
30
|
+
let :create_unrelated_children do
|
31
|
+
[
|
32
|
+
child_class.create!,
|
33
|
+
child_class.create!,
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
let :destroy_children do
|
38
|
+
children.each {|child| child.destroy!}
|
39
|
+
end
|
40
|
+
|
41
|
+
let :parent do
|
42
|
+
parent_class.create!
|
43
|
+
end
|
44
|
+
|
45
|
+
let :parent_class do
|
46
|
+
ParentModel.tap do |parent_class|
|
47
|
+
parent_class.has_many :normal_child_models, :dependent => :destroy
|
48
|
+
parent_class.has_many :paranoid_child_models, :dependent => :destroy
|
49
|
+
|
50
|
+
parent_class.has_one :child_has_one, :class_name => :ParanoidSingleChildModel, :dependent => :destroy
|
51
|
+
parent_class.belongs_to :child_belongs_to, :class_name => :ParanoidSingleChildModel, :dependent => :destroy
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'NormalChildModel' do
|
56
|
+
let :child_class do
|
57
|
+
NormalChildModel
|
58
|
+
end
|
59
|
+
|
60
|
+
let :children do
|
61
|
+
[
|
62
|
+
parent.normal_child_models.create!,
|
63
|
+
parent.normal_child_models.create!,
|
64
|
+
parent.normal_child_models.create!,
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when parent is destroyed' do
|
69
|
+
it 'related children will be destroyed.' do
|
70
|
+
subject_soft_delete
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'ParanoidChildModel(has_many)' do
|
76
|
+
let :child_class do
|
77
|
+
ParanoidChildModel
|
78
|
+
end
|
79
|
+
|
80
|
+
let :children do
|
81
|
+
[
|
82
|
+
parent.paranoid_child_models.create!,
|
83
|
+
parent.paranoid_child_models.create!,
|
84
|
+
parent.paranoid_child_models.create!,
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when parent is destroyed' do
|
89
|
+
it 'related children will be destroyed.' do
|
90
|
+
subject_soft_delete
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when parent is restored' do
|
95
|
+
it 'related children will be restored.' do
|
96
|
+
subject_restore
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when children are deleted, before restore parent' do
|
100
|
+
before :each do
|
101
|
+
destroy_children
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'related children will be not restored.' do
|
105
|
+
subject_not_restore
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'ParanoidSingleChildModel(has_one)' do
|
112
|
+
let :child_class do
|
113
|
+
ParanoidSingleChildModel
|
114
|
+
end
|
115
|
+
|
116
|
+
let :children do
|
117
|
+
[
|
118
|
+
parent.create_child_has_one!
|
119
|
+
]
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when parent is destroyed' do
|
123
|
+
it 'related children will be destroyed.' do
|
124
|
+
subject_soft_delete
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when parent is restored' do
|
129
|
+
it 'related children will be restored.' do
|
130
|
+
subject_restore
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when children are deleted, before restore parent' do
|
134
|
+
before :each do
|
135
|
+
destroy_children
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'related children will be not restored.' do
|
139
|
+
subject_not_restore
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'ParanoidSingleChildModel(has_one)' do
|
146
|
+
let :child_class do
|
147
|
+
ParanoidSingleChildModel
|
148
|
+
end
|
149
|
+
|
150
|
+
let :children do
|
151
|
+
[
|
152
|
+
parent.create_child_belongs_to!
|
153
|
+
]
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'when parent is destroyed' do
|
157
|
+
it 'related children will be destroyed.' do
|
158
|
+
subject_soft_delete
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when parent is restored' do
|
163
|
+
it 'related children will be restored.' do
|
164
|
+
subject_restore
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when children are deleted, before restore parent' do
|
168
|
+
before :each do
|
169
|
+
destroy_children
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'related children will be not restored.' do
|
173
|
+
subject_not_restore
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kakurenbo::Core::Callbacks do
|
4
|
+
create_temp_table(:paranoid_models){ |t| t.datetime :deleted_at }
|
5
|
+
before :all do
|
6
|
+
ParanoidModel.tap do |klass|
|
7
|
+
klass.before_destroy :callback_before_destroy
|
8
|
+
klass.after_destroy :callback_after_destroy
|
9
|
+
klass.after_commit :callback_after_commit
|
10
|
+
|
11
|
+
klass.before_restore :callback_before_restore
|
12
|
+
klass.after_restore :callback_after_restore
|
13
|
+
|
14
|
+
klass.before_update :callback_before_update
|
15
|
+
klass.before_save :callback_before_save
|
16
|
+
klass.before_validation :callback_before_validation
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let! :model do
|
21
|
+
model_class.create!
|
22
|
+
end
|
23
|
+
|
24
|
+
let :model_class do
|
25
|
+
ParanoidModel.tap do |klass|
|
26
|
+
allow_any_instance_of(klass).to receive(:callback_before_destroy) { true }
|
27
|
+
allow_any_instance_of(klass).to receive(:callback_after_destroy) { true }
|
28
|
+
allow_any_instance_of(klass).to receive(:callback_after_commit) { true }
|
29
|
+
|
30
|
+
allow_any_instance_of(klass).to receive(:callback_before_restore) { true }
|
31
|
+
allow_any_instance_of(klass).to receive(:callback_after_restore) { true }
|
32
|
+
|
33
|
+
allow_any_instance_of(klass).to receive(:callback_before_update) { true }
|
34
|
+
allow_any_instance_of(klass).to receive(:callback_before_save) { true }
|
35
|
+
allow_any_instance_of(klass).to receive(:callback_before_validation) { true }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when call #delete' do
|
40
|
+
subject { model.delete }
|
41
|
+
|
42
|
+
it 'destroy-callbacks will not be called.' do
|
43
|
+
expect(model).not_to receive(:callback_before_destroy)
|
44
|
+
expect(model).not_to receive(:callback_after_destroy)
|
45
|
+
expect(model).not_to receive(:callback_after_commit)
|
46
|
+
|
47
|
+
subject
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'save-callbacks will not be called.' do
|
51
|
+
expect(model).not_to receive(:callback_before_update)
|
52
|
+
expect(model).not_to receive(:callback_before_save)
|
53
|
+
expect(model).not_to receive(:callback_before_validation)
|
54
|
+
|
55
|
+
subject
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when call #destroy' do
|
60
|
+
subject { model.destroy }
|
61
|
+
|
62
|
+
it 'destroy-callbacks will be called.' do
|
63
|
+
expect(model).to receive(:callback_before_destroy).once
|
64
|
+
expect(model).to receive(:callback_after_destroy).once
|
65
|
+
expect(model).to receive(:callback_after_commit).once
|
66
|
+
|
67
|
+
subject
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'save-callbacks will not be called.' do
|
71
|
+
expect(model).not_to receive(:callback_before_update)
|
72
|
+
expect(model).not_to receive(:callback_before_save)
|
73
|
+
expect(model).not_to receive(:callback_before_validation)
|
74
|
+
|
75
|
+
subject
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when call #restore' do
|
80
|
+
before :each do
|
81
|
+
model.destroy!
|
82
|
+
end
|
83
|
+
|
84
|
+
subject { model.restore }
|
85
|
+
|
86
|
+
it 'restore-callbacks will be called.' do
|
87
|
+
expect(model).to receive(:callback_before_restore).once
|
88
|
+
expect(model).to receive(:callback_after_restore).once
|
89
|
+
expect(model).to receive(:callback_after_commit).once
|
90
|
+
|
91
|
+
subject
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'save-callbacks will not be called.' do
|
95
|
+
expect(model).not_to receive(:callback_before_update)
|
96
|
+
expect(model).not_to receive(:callback_before_save)
|
97
|
+
expect(model).not_to receive(:callback_before_validation)
|
98
|
+
|
99
|
+
subject
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kakurenbo::Core do
|
4
|
+
create_temp_table(:paranoid_models){ |t| t.datetime :deleted_at }
|
5
|
+
before :all do
|
6
|
+
ParanoidModel.tap do |klass|
|
7
|
+
klass.before_destroy :callback_before_destroy
|
8
|
+
klass.before_restore :callback_before_restore
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject :subject_hard_delete do
|
13
|
+
expect {
|
14
|
+
subject
|
15
|
+
}.to change {
|
16
|
+
model_class.with_deleted.find_by(:id => model.id)
|
17
|
+
}.to(nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject :subject_not_hard_delete do
|
21
|
+
expect {
|
22
|
+
subject
|
23
|
+
}.not_to change {
|
24
|
+
model_class.with_deleted.find_by(:id => model.id)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
subject :subject_soft_delete do
|
29
|
+
expect { subject }.to change { model.reload.destroyed? }.from(false).to(true)
|
30
|
+
end
|
31
|
+
|
32
|
+
subject :subject_restore do
|
33
|
+
expect { subject }.to change { model.reload.destroyed? }.from(true).to(false)
|
34
|
+
end
|
35
|
+
|
36
|
+
let! :model do
|
37
|
+
model_class.create!
|
38
|
+
end
|
39
|
+
|
40
|
+
let :model_class do
|
41
|
+
ParanoidModel.tap do |klass|
|
42
|
+
allow_any_instance_of(klass).to receive(:callback_before_destroy) { true }
|
43
|
+
allow_any_instance_of(klass).to receive(:callback_before_restore) { true }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
let :now do
|
48
|
+
Time.now.tap do |now|
|
49
|
+
allow(Time).to receive(:now) { now.dup }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#delete' do
|
54
|
+
subject { model.delete }
|
55
|
+
|
56
|
+
it 'record will be soft-deleted.' do
|
57
|
+
subject_soft_delete
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'record will not be hard-deleted.' do
|
61
|
+
subject_not_hard_delete
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when with hard-delete option' do
|
65
|
+
subject { model.delete(:hard => true) }
|
66
|
+
|
67
|
+
it 'record will be hard-deleted.' do
|
68
|
+
subject_hard_delete
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#destroy' do
|
74
|
+
subject { model.destroy }
|
75
|
+
|
76
|
+
it 'record will be soft-deleted.' do
|
77
|
+
subject_soft_delete
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'record will not be hard-deleted.' do
|
81
|
+
subject_not_hard_delete
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'return self' do
|
85
|
+
expect(subject).to eq(model)
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when action is cancelled' do
|
89
|
+
before :each do
|
90
|
+
allow(model).to receive(:callback_before_destroy) { false }
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'record will not be soft-deleted.' do
|
94
|
+
expect { subject }.not_to change { model.reload.destroyed? }
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'return falsey' do
|
98
|
+
expect(subject).to be_falsey
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when with hard-delete option' do
|
103
|
+
subject { model.destroy(:hard => true) }
|
104
|
+
|
105
|
+
it 'record will be hard-deleted.' do
|
106
|
+
subject_hard_delete
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#destroy!' do
|
112
|
+
subject { model.destroy! }
|
113
|
+
context 'when action is cancelled' do
|
114
|
+
before :each do
|
115
|
+
allow(model).to receive(:callback_before_destroy) { false }
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'raise ActiveRecord::RecordNotDestroyed' do
|
119
|
+
expect{subject}.to raise_error(ActiveRecord::RecordNotDestroyed)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#destroyed?' do
|
125
|
+
subject { model.destroyed? }
|
126
|
+
|
127
|
+
context 'when model not deleted' do
|
128
|
+
it 'return falsey' do
|
129
|
+
expect(subject).to be_falsey
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when model deleted' do
|
134
|
+
before :each do
|
135
|
+
model.destroy
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'return truthy' do
|
139
|
+
expect(subject).to be_truthy
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#restore' do
|
145
|
+
before :each do
|
146
|
+
model.destroy
|
147
|
+
end
|
148
|
+
|
149
|
+
subject { model.restore }
|
150
|
+
|
151
|
+
it 'record will be restored.' do
|
152
|
+
subject_restore
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'return self' do
|
156
|
+
expect(subject).to eq(model)
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'when action is cancelled' do
|
160
|
+
before :each do
|
161
|
+
allow(model).to receive(:callback_before_restore) { false }
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'record will not be restored.' do
|
165
|
+
expect { subject }.not_to change { model.reload.destroyed? }
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'return falsey' do
|
169
|
+
expect(subject).to be_falsey
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#restore!' do
|
175
|
+
subject { model.restore! }
|
176
|
+
context 'when action is cancelled' do
|
177
|
+
before :each do
|
178
|
+
allow(model).to receive(:callback_before_restore) { false }
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'raise ActiveRecord::RecordNotRestored' do
|
182
|
+
expect{subject}.to raise_error(ActiveRecord::RecordNotRestored)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|