immortal 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE DELETED
@@ -1,9 +0,0 @@
1
- (The MIT License)
2
-
3
- Copyright (c) Teambox
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
9
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,383 +0,0 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
-
3
- describe Immortal do
4
- before do
5
- @m = ImmortalModel.create! title: 'testing immortal'
6
- end
7
-
8
- it "should not be deleted from the database using #destroy" do
9
- expect {
10
- @m.destroy
11
- }.to_not change(ImmortalModel, :count_with_deleted)
12
- end
13
-
14
- it "should be frozen using #destroy" do
15
- @m.destroy
16
- @m.should be_frozen
17
- end
18
-
19
- it "should not be dirty using #destroy" do
20
- @m.destroy
21
- @m.should_not be_changed
22
- end
23
-
24
- it "should not be dirty using #destroy" do
25
- expect {
26
- @m.destroy
27
- }.to change(@m, :updated_at)
28
- end
29
-
30
- it "should be deleted from the database using #destroy!" do
31
- expect {
32
- @m.destroy!
33
- }.to change(ImmortalModel, :count_with_deleted)
34
- end
35
-
36
- it "should find non deleted records" do
37
- ImmortalModel.first.should == @m
38
- ImmortalModel.all.should include(@m)
39
- end
40
-
41
- it "should not find deleted records" do
42
- @m.destroy
43
- ImmortalModel.first.should be_nil
44
- ImmortalModel.all.should be_empty
45
- end
46
-
47
- it "should find deleted records using the old method" do
48
- ImmortalModel.find_with_deleted(@m.id).should == @m
49
- @m.destroy
50
- ImmortalModel.find_with_deleted(@m.id).should == @m
51
- end
52
-
53
- it "should count undeleted records by default" do
54
- @m2 = ImmortalModel.create! title: 'testing immortal again'
55
- ImmortalModel.count_only_deleted.should == 0
56
-
57
- @m.destroy
58
-
59
- ImmortalModel.count_only_deleted.should == 1
60
- end
61
-
62
- it "should find only deleted records" do
63
- @m2 = ImmortalModel.create! title: 'testing immortal again'
64
- expect {
65
- ImmortalModel.find_only_deleted(@m.id)
66
- }.to raise_error(ActiveRecord::RecordNotFound)
67
-
68
- @m.destroy
69
-
70
- ImmortalModel.find_only_deleted(@m.id).should == @m
71
- expect {
72
- ImmortalModel.find_only_deleted(@m2.id)
73
- }.to raise_error(ActiveRecord::RecordNotFound)
74
- end
75
-
76
- it "should be able to count undeleted records" do
77
- @m2 = ImmortalModel.create! title: 'testing immortal again'
78
- ImmortalModel.count.should == 2
79
-
80
- @m.destroy
81
-
82
- ImmortalModel.count.should == 1
83
- end
84
-
85
- it "should be able to count all the records including deleted" do
86
- @m2 = ImmortalModel.create! title: 'testing immortal again'
87
- @m.destroy
88
- ImmortalModel.count_with_deleted.should == 2
89
- end
90
-
91
- it "should not exist if deleted" do
92
- ImmortalModel.exists?(@m.id).should be_true
93
- @m.destroy
94
- ImmortalModel.exists?(@m.id).should be_false
95
- end
96
-
97
- it "should calculate without deleted" do
98
- @m2 = ImmortalModel.create! value: 10
99
- @m3 = ImmortalModel.create! value: 20
100
- ImmortalModel.calculate(:sum, :value).should == 30
101
- @m2.destroy
102
- ImmortalModel.calculate(:sum, :value).should == 20
103
- end
104
-
105
- it "should execute the before_destroy callback when immortally destroyed" do
106
- @m.destroy
107
- @m.before_d.should be_true
108
- end
109
-
110
- it "should execute the after_destroy callback when immortally destroyed" do
111
- @m.destroy
112
- @m.after_d.should be_true
113
- end
114
-
115
- it "should execute the after_commit callback when immortally destroyed" do
116
- @m.after_commit = false
117
- @m.destroy
118
- @m.after_commit.should be_true
119
- end
120
-
121
- it "should not return true when a before hook halts" do
122
- @m.before_return = false
123
- @m.after_commit = false
124
- @m.destroy.should be_false
125
- @m.after_commit.should_not be_true
126
- end
127
-
128
- it "should not execute the before_update callback when immortally destroyed" do
129
- @m.destroy
130
- @m.before_u.should be_nil
131
- end
132
-
133
- it "should not execute the after_update callback when immortally destroyed" do
134
- @m.destroy
135
- @m.after_u.should be_nil
136
- end
137
-
138
- it "should not execute the before_destroy callback when immortally destroyed without callbacks" do
139
- @m.destroy_without_callbacks
140
- @m.before_d.should be_nil
141
- end
142
-
143
- it "should not execute the after_destroy callback when immortally destroyed without callbacks" do
144
- @m.destroy_without_callbacks
145
- @m.after_d.should be_nil
146
- end
147
-
148
- it "should immortally delete all records with delete_all" do
149
- expect {
150
- ImmortalModel.delete_all
151
- }.to change(ImmortalModel, :count).by(-1)
152
- ImmortalModel.count_with_deleted.should == 1
153
- end
154
-
155
- it "should immortally delete all records with delete_all!" do
156
- expect {
157
- ImmortalModel.delete_all!
158
- }.to change(ImmortalModel, :count_with_deleted).by(-1)
159
- end
160
-
161
- it "should know if it's deleted" do
162
- @m.should_not be_deleted
163
- @m.destroy
164
- @m.should be_deleted
165
- end
166
-
167
- it "should be recoverable" do
168
- @m.destroy
169
- @m = ImmortalModel.find_with_deleted(@m.id)
170
- expect {
171
- @m.recover!
172
- }.to change(@m, :updated_at)
173
- @m.should_not be_frozen
174
- @m.should_not be_changed
175
- ImmortalModel.first.should == @m
176
- end
177
-
178
- it "should consider an Many-to-many association with through as deleted when the join is deleted." do
179
- @n = ImmortalNode.create! title: 'testing association'
180
- @join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
181
-
182
- @m.nodes.count.should == 1
183
- @n.models.count.should == 1
184
-
185
- @join.destroy
186
-
187
- @m.nodes.count.should == 0
188
- @n.models.count.should == 0
189
- end
190
-
191
- it "should only immortally delete scoped associations, NOT ALL RECORDS" do
192
- n1 = ImmortalNode.create! title: 'testing association 1'
193
- j1 = ImmortalJoin.create! immortal_model: @m, immortal_node: n1
194
-
195
- n2 = ImmortalNode.create! title: 'testing association 2'
196
- j2 = ImmortalJoin.create! immortal_model: @m, immortal_node: n2
197
-
198
- n3 = ImmortalNode.create! title: 'testing association 3'
199
- j3 = ImmortalJoin.create! immortal_node: n3
200
-
201
- @m.destroy
202
-
203
- [n1,n2,j1,j2].all? {|r| r.reload.deleted?}.should be_true
204
- [n3,j3].all? {|r| !r.reload.deleted?}.should be_true
205
- end
206
-
207
- it "should properly generate joins" do
208
- join_sql1 = 'INNER JOIN "immortal_joins" ON "immortal_joins"."immortal_node_id" = "immortal_nodes"."id"'
209
- join_sql2 = 'INNER JOIN "immortal_models" ON "immortal_models"."id" = "immortal_joins"."immortal_model_id"'
210
- generated_sql = ImmortalNode.joins(:immortal_models).to_sql
211
- generated_sql.should include(join_sql1)
212
- generated_sql.should include(join_sql2)
213
- end
214
-
215
- it "should reload immortal polymorphic associations using default reader" do
216
- node = ImmortalNode.create! title: 'testing association 1'
217
- target_1 = ImmortalSomeTarget.create! title: 'target 1'
218
- target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
219
-
220
- node.target.should be_nil
221
- node.target = target_1
222
- node.target.should == target_1
223
-
224
- node.target_id = target_2.id
225
- node.target_type = target_2.class.name
226
-
227
- target_2.destroy
228
- node.target.should be_nil
229
- end
230
-
231
- it "should reload immortal polymorphic associations using deleted reader" do
232
- #setup
233
- node = ImmortalNode.create! title: 'testing association 1'
234
- target_1 = ImmortalSomeTarget.create! title: 'target 1'
235
- target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
236
-
237
- #confirm initial state
238
- node.target.should be_nil
239
-
240
- #load target & confirm
241
- node.target = target_1
242
- node.target.should == target_1
243
-
244
- #switch target indirectly
245
- node.target_id = target_2.id
246
- node.target_type = target_2.class.name
247
-
248
- #don't assign directly and destroy new target
249
- target_2.destroy
250
-
251
- #Ask for deleted target (or not deleted). Will NOT cache
252
- # Run this before default accessor to test scope has been reset.
253
- node.target_with_deleted.should == target_2
254
-
255
- #Respect what's expected
256
- node.target.should be_nil
257
-
258
- #Ask only for deleted target. Will NOT cache
259
- node.target_only_deleted.should == target_2
260
-
261
- #Confirm we haven't invaded the target namespace
262
- node.target.should be_nil
263
- end
264
-
265
- it "should reload immortal polymorphic associations using deleted reader (direct assignment)" do
266
- #setup
267
- node = ImmortalNode.create! title: 'testing association 1'
268
- target_1 = ImmortalSomeTarget.create! title: 'target 1'
269
- target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
270
-
271
- #confirm initial state
272
- node.target.should be_nil
273
-
274
- #load target & confirm
275
- node.target = target_1
276
- node.target.should == target_1
277
-
278
- #switch target directly
279
- node.target = target_2
280
-
281
- node.target.should == target_2
282
- node.target_with_deleted.should == target_2
283
-
284
- #don't assign directly and destroy new target
285
- target_2.destroy
286
-
287
- #Respect what's expected
288
- node.target(true).should be_nil
289
-
290
- #Ask for deleted target (or not deleted). Will NOT cache
291
- node.target_with_deleted.should == target_2
292
-
293
- #Confirm we haven't invaded the target namespace
294
- node.target.should be_nil
295
- end
296
-
297
- it "deleted readers should respect staleness" do
298
- #setup
299
- node = ImmortalNode.create! title: 'testing association 1'
300
- target_1 = ImmortalSomeTarget.create! title: 'target 1'
301
- target_2 = ImmortalSomeOtherTarget.create! title: 'target 2'
302
-
303
- #confirm initial state
304
- node.target.should be_nil
305
- node.target_with_deleted.should be_nil
306
- node.target_only_deleted.should be_nil
307
-
308
- #load target & confirm
309
- node.target = target_1
310
- node.target.should == target_1
311
- node.target_with_deleted.should == target_1
312
- node.target_only_deleted.should be_nil
313
-
314
- #switch target directly
315
- node.target = target_2
316
-
317
- node.target.should == target_2
318
- node.target_with_deleted.should == target_2
319
-
320
- #don't assign directly and destroy new target
321
- target_2.destroy
322
-
323
- #Respect what's expected
324
- node.target(true).should be_nil
325
-
326
- #Ask for deleted target (or not deleted).
327
- node.target_with_deleted.should == target_2
328
- node.target_only_deleted.should == target_2
329
-
330
- #Confirm we haven't invaded the target namespace
331
- node.target.should be_nil
332
-
333
- node.target_id = target_1.id
334
- node.target_type = target_1.class.name
335
- node.target.should == target_1
336
- node.target_with_deleted.should == target_1
337
- node.target_only_deleted.should be_nil
338
- end
339
-
340
- it "should not unscope associations when using with_deleted scope" do
341
- m1 = ImmortalModel.create! title: 'previously created model'
342
- n1 = ImmortalNode.create! title: 'previously created association'
343
- ImmortalJoin.create! immortal_model: m1, immortal_node: n1
344
-
345
- @n = ImmortalNode.create! title: 'testing association'
346
- @join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
347
-
348
- @join.destroy
349
-
350
- @m.nodes.count.should == 0
351
- @n.joins.count.should == 0
352
-
353
- @m.nodes.count_with_deleted.should == 1
354
- @n.joins.count_with_deleted.should == 1
355
- end
356
-
357
- it "should not unscope associations when using only_deleted scope" do
358
- m1 = ImmortalModel.create! title: 'previously created model'
359
- n1 = ImmortalNode.create! title: 'previously created association'
360
- ImmortalJoin.create! immortal_model: m1, immortal_node: n1
361
-
362
- @n = ImmortalNode.create! title: 'testing association'
363
- @join = ImmortalJoin.create! immortal_model: @m, immortal_node: @n
364
-
365
- @join.destroy
366
-
367
- @m.nodes.count.should == 0
368
- @n.joins.count.should == 0
369
-
370
- @m.nodes.count_only_deleted
371
- @m.nodes.count_only_deleted.should == 1
372
- @n.joins.count_only_deleted.should == 1
373
- end
374
-
375
- it 'warn when deleted column is nullable' do
376
- Kernel.should_receive(:warn)
377
-
378
- class ImmortalNullableDeleted
379
- include Immortal
380
- end
381
- end
382
-
383
- end
@@ -1,145 +0,0 @@
1
- Bundler.require(:default, :development)
2
- require 'rspec'
3
- require File.expand_path("../../lib/immortal", __FILE__)
4
- require 'active_record'
5
- require 'sqlite3'
6
- require 'logger'
7
-
8
- RSpec.configure do |config|
9
- config.before(:each) do
10
- ActiveRecord::Base.connection.execute('delete from immortal_models')
11
- end
12
-
13
- config.after(:all) do
14
- end
15
- end
16
-
17
-
18
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
19
- ActiveRecord::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
20
-
21
- old_stdout = $stdout
22
- $stdout = StringIO.new
23
-
24
- begin
25
- ActiveRecord::Schema.define do
26
- create_table :immortal_models do |t|
27
- t.string :title
28
- t.integer :value
29
- t.boolean :deleted, default: false, null: false
30
- t.timestamps
31
- end
32
- create_table :immortal_joins do |t|
33
- t.integer :immortal_model_id
34
- t.integer :immortal_node_id
35
- t.boolean :deleted, default: false, null: false
36
- t.timestamps
37
- end
38
- create_table :immortal_nodes do |t|
39
- t.integer :target_id
40
- t.string :target_type
41
- t.string :title
42
- t.integer :value
43
- t.boolean :deleted, default: false, null: false
44
- t.timestamps
45
- end
46
-
47
- create_table :immortal_some_targets do |t|
48
- t.string :title
49
- t.boolean :deleted, default: false, null: false
50
- t.timestamps
51
- end
52
-
53
- create_table :immortal_some_other_targets do |t|
54
- t.string :title
55
- t.boolean :deleted, default: false, null: false
56
- t.timestamps
57
- end
58
-
59
- create_table :immortal_nullable_deleteds do |t|
60
- t.string :title
61
- t.boolean :deleted, default: false
62
- t.timestamps
63
- end
64
- end
65
- ensure
66
- $stdout = old_stdout
67
- end
68
-
69
- class ImmortalJoin < ActiveRecord::Base
70
- include Immortal
71
-
72
- belongs_to :immortal_model
73
- belongs_to :immortal_node, dependent: :destroy
74
- end
75
-
76
- class ImmortalNode < ActiveRecord::Base
77
- include Immortal
78
-
79
- has_many :immortal_joins
80
- has_many :immortal_models, through: :immortal_joins
81
-
82
- has_many :joins, class_name: 'ImmortalJoin'
83
- has_many :models, through: :joins, source: :immortal_model
84
-
85
- belongs_to :target, polymorphic: true
86
- end
87
-
88
- class ImmortalSomeTarget < ActiveRecord::Base
89
- include Immortal
90
-
91
- has_many :immortal_nodes, as: :target
92
- end
93
-
94
- class ImmortalSomeOtherTarget < ActiveRecord::Base
95
- include Immortal
96
-
97
- has_many :immortal_nodes, as: :target
98
- end
99
-
100
-
101
- class ImmortalModel < ActiveRecord::Base
102
- include Immortal
103
-
104
- has_many :immortal_nodes, through: :immortal_joins, dependent: :destroy
105
- has_many :immortal_joins, dependent: :delete_all
106
-
107
- has_many :joins, class_name: 'ImmortalJoin', dependent: :delete_all
108
- has_many :nodes, through: :joins, source: :immortal_node, dependent: :destroy
109
-
110
- attr_accessor :before_d, :after_d, :before_u, :after_u, :after_commit, :before_return
111
-
112
- before_destroy :set_before
113
- after_destroy :set_after
114
- before_update :set_before_update
115
- after_update :set_after_update
116
- after_commit :set_after_commit, on: :destroy
117
-
118
- private
119
-
120
- def set_before
121
- @before_d = true
122
- @before_return
123
- end
124
-
125
- def set_after
126
- @after_d = true
127
- end
128
-
129
- def set_after_update
130
- @after_u = true
131
- end
132
-
133
- def set_after_commit
134
- @after_commit = true
135
- end
136
-
137
- def set_before_update
138
- @before_u = true
139
- end
140
-
141
- end
142
-
143
- class ImmortalNullableDeleted < ActiveRecord::Base
144
- end
145
-