mongoid_archival 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Mongoid::Archivable::Protected do
4
+
5
+ let(:sport) do
6
+ Sport.create
7
+ end
8
+
9
+ describe '#delete and #delete!' do
10
+
11
+ context 'when the document is a root' do
12
+
13
+ it 'prevents delete' do
14
+ expect { sport.delete }.to raise_error(RuntimeError)
15
+ end
16
+
17
+ it 'allows delete!' do
18
+ sport.delete!
19
+ expect { sport.reload }.to raise_error(Mongoid::Errors::DocumentNotFound)
20
+ end
21
+ end
22
+
23
+ # context 'when the document is embedded' do
24
+ # end
25
+ end
26
+
27
+ describe '#destroy and #destroy!' do
28
+
29
+ context 'when the document is a root' do
30
+
31
+ it 'prevents destroy' do
32
+ expect { sport.destroy }.to raise_error(RuntimeError)
33
+ end
34
+
35
+ it 'allows destroy!' do
36
+ sport.destroy!
37
+ expect { sport.reload }.to raise_error(Mongoid::Errors::DocumentNotFound)
38
+ end
39
+ end
40
+
41
+ # context 'when the document is embedded' do
42
+ # end
43
+ end
44
+ end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Mongoid::Archivable#restore' do
4
+
5
+ describe '#restore' do
6
+
7
+ context 'when the document is a root' do
8
+
9
+ let(:post) do
10
+ ArchivablePost.create(title: 'testing')
11
+ end
12
+
13
+ before do
14
+ post.archive
15
+ post.restore
16
+ end
17
+
18
+ it 'removes the archived at time' do
19
+ expect(post.archived_at).to be_nil
20
+ end
21
+
22
+ it 'persists the change' do
23
+ expect(post.reload.archived_at).to be_nil
24
+ end
25
+
26
+ it 'marks document again as persisted' do
27
+ expect(post.persisted?).to be_truthy
28
+ end
29
+
30
+ context 'will run callback' do
31
+
32
+ it 'before restore' do
33
+ expect(post.before_restore_called).to be_truthy
34
+ end
35
+
36
+ it 'after restore' do
37
+ expect(post.after_restore_called).to be_truthy
38
+ end
39
+
40
+ it 'around restore' do
41
+ expect(post.around_before_restore_called).to be_truthy
42
+ expect(post.around_after_restore_called).to be_truthy
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'when the document is embedded' do
48
+
49
+ let(:person) do
50
+ Person.create
51
+ end
52
+
53
+ let(:phone) do
54
+ person.archivable_phones.create(number: '911')
55
+ end
56
+
57
+ before do
58
+ phone.archive
59
+ phone.restore
60
+ end
61
+
62
+ it 'removes the archived at time' do
63
+ expect(phone.archived_at).to be_nil
64
+ end
65
+
66
+ it 'persists the change' do
67
+ expect(person.reload.archivable_phones.first.archived_at).to be_nil
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#restore_relations' do
73
+
74
+ subject { ArchBase.create }
75
+
76
+ let!(:arch_has_one) { subject.arch_has_one = ArchHasOne.create }
77
+ let!(:arch_has_many) { 2.times.map { subject.arch_has_many.create } }
78
+ let!(:arch_habtm) { 3.times.map { subject.arch_habtm.create } }
79
+ let!(:arch_belongs_to) { subject.arch_belongs_to = ArchBelongsTo.create }
80
+ let!(:arch_embeds_one) { subject.arch_embeds_one = ArchEmbedsOne.new }
81
+ let!(:arch_embeds_many) { 2.times.map { subject.arch_embeds_many.build } }
82
+
83
+ let!(:norm_has_one) { subject.norm_has_one = NormHasOne.create }
84
+ let!(:norm_has_many) { 2.times.map { subject.norm_has_many.create } }
85
+ let!(:norm_habtm) { 3.times.map { subject.norm_habtm.create } }
86
+ let!(:norm_belongs_to) { subject.norm_belongs_to = NormBelongsTo.create }
87
+ let!(:norm_embeds_one) { subject.norm_embeds_one = NormEmbedsOne.new }
88
+ let!(:norm_embeds_many) { 2.times.map { subject.norm_embeds_many.build } }
89
+
90
+ let(:prepare) do
91
+ subject.archive
92
+ subject.restore
93
+ end
94
+
95
+ context 'restores archivable associations' do
96
+ before { prepare }
97
+
98
+ it do
99
+ subject.restore_relations
100
+ end
101
+
102
+ it { expect { subject.restore_relations }.to change { ArchHasOne.current.count }.by(1) }
103
+ it { expect { subject.restore_relations }.to change { ArchHasMany.current.count }.by(2) }
104
+ it { expect { subject.restore_relations }.to change { ArchHabtm.current.count }.by(3) }
105
+ it { expect { subject.restore_relations }.to change { ArchBelongsTo.current.count }.by(1) }
106
+ end
107
+
108
+ context 'does not affect embedded archivable documents' do
109
+ before { prepare }
110
+
111
+ it { expect{ subject.restore_relations}.to_not change{ subject.arch_embeds_one } }
112
+ it { expect{ subject.restore_relations}.to_not change{ subject.arch_embeds_many.current.count } }
113
+ end
114
+
115
+ context 'does not affect non-archivable documents' do
116
+ before { prepare }
117
+
118
+ it { expect{ subject.restore_relations}.to_not change{ NormHasOne.count } }
119
+ it { expect{ subject.restore_relations}.to_not change{ NormHasMany.count } }
120
+ it { expect{ subject.restore_relations}.to_not change{ NormHabtm.count } }
121
+ it { expect{ subject.restore_relations}.to_not change{ NormBelongsTo.count } }
122
+ it { expect{ subject.restore_relations}.to_not change{ subject.norm_embeds_one } }
123
+ it { expect{ subject.restore_relations}.to_not change{ subject.norm_embeds_many.count } }
124
+ end
125
+
126
+ context 'recursion' do
127
+ let!(:arch_habtm_norm_has_one) { subject.arch_habtm.first.norm_has_one = NormHasOne.create } # not restored
128
+ let!(:arch_habtm_arch_has_one) { subject.arch_habtm.first.arch_has_one = ArchHasOne.create } # restored
129
+ let!(:arch_habtm_norm_has_many) { 2.times.map { subject.arch_habtm.first.norm_has_many = NormHasMany.create } } # not restored
130
+ let!(:arch_habtm_arch_has_many) { 3.times.map { subject.arch_habtm.second.arch_has_many = ArchHasMany.create } } # restored
131
+
132
+ before do
133
+ subject.archive
134
+ subject.restore
135
+ end
136
+
137
+ it { expect { subject.restore_relations}.to change { ArchHasOne.current.count }.by(2) }
138
+ it { expect { subject.restore_relations}.to change { ArchHasMany.current.count }.by(3) }
139
+ it { expect { subject.restore_relations }.to_not change { NormHasOne.count } }
140
+ it { expect { subject.restore_relations }.to_not change { NormHasMany.count } }
141
+ it { expect { subject.restore_relations }.to_not change { NormHabtm.count } }
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Mongoid::Archivable scopes' do
4
+
5
+ context 'when the document is archivable' do
6
+
7
+ context 'when calling a class method' do
8
+
9
+ let(:criteria) do
10
+ Fish.fresh
11
+ end
12
+
13
+ it 'includes the archived_at criteria in the selector' do
14
+ expect(criteria.selector).to eq({ 'fresh' => true })
15
+ end
16
+ end
17
+
18
+ context 'when chaining a class method to unscoped' do
19
+
20
+ let(:criteria) do
21
+ Fish.unscoped.fresh
22
+ end
23
+
24
+ it 'does not include the archived_at in the selector' do
25
+ expect(criteria.selector).to eq({ 'fresh' => true })
26
+ end
27
+ end
28
+
29
+ context 'when chaining a class method to archived' do
30
+
31
+ let(:criteria) do
32
+ Fish.archived.fresh
33
+ end
34
+
35
+ it 'includes the archived_at $ne criteria in the selector' do
36
+ expect(criteria.selector).to eq({
37
+ 'archived_at' => { '$ne' => nil }, 'fresh' => true
38
+ })
39
+ end
40
+ end
41
+
42
+ context 'when chaining a where to unscoped' do
43
+
44
+ let(:criteria) do
45
+ Fish.unscoped.where(fresh: true)
46
+ end
47
+
48
+ it 'includes no default scoping information in the selector' do
49
+ expect(criteria.selector).to eq({ 'fresh' => true })
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '.scoped' do
55
+
56
+ it 'returns a scoped criteria' do
57
+ expect(ArchivablePost.scoped.selector).to eq({})
58
+ end
59
+ end
60
+
61
+ describe '.archived' do
62
+
63
+ context 'when called on a root document' do
64
+
65
+ let(:post) do
66
+ ArchivablePost.create(title: 'testing')
67
+ end
68
+
69
+ before do
70
+ post.archive
71
+ end
72
+
73
+ let(:archived) do
74
+ ArchivablePost.archived
75
+ end
76
+
77
+ it 'returns the archived documents' do
78
+ expect(archived).to eq([ post ])
79
+ end
80
+ end
81
+
82
+ context 'when called on an embedded document' do
83
+
84
+ let(:person) do
85
+ Person.create
86
+ end
87
+
88
+ let(:phone) do
89
+ person.archivable_phones.create
90
+ end
91
+
92
+ before do
93
+ phone.archive
94
+ person.reload
95
+ end
96
+
97
+ it 'returns the archived documents' do
98
+ expect(person.archivable_phones.archived.to_a).to eq([ phone ])
99
+ end
100
+
101
+ it 'returns the correct count' do
102
+ expect(person.archivable_phones.archived.count).to eq(1)
103
+ end
104
+ end
105
+ end
106
+
107
+ describe '.unscoped' do
108
+
109
+ let(:unscoped) do
110
+ ArchivablePost.unscoped
111
+ end
112
+
113
+ it 'returns an unscoped criteria' do
114
+ expect(unscoped.selector).to eq({})
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Mongoid::Archivable uniqueness validator' do
4
+
5
+ describe '#valid?' do
6
+
7
+ context 'when the document is a root document' do
8
+
9
+ context 'when the document is archivable' do
10
+ before do
11
+ ArchivablePost.validates(:title, uniqueness: { conditions: -> { ArchivablePost.where(archived_at: nil) } })
12
+ end
13
+
14
+ after do
15
+ ArchivablePost.reset_callbacks(:validate)
16
+ end
17
+
18
+ let!(:post) do
19
+ ArchivablePost.create(title: 'testing')
20
+ end
21
+
22
+ context 'when the field is unique' do
23
+
24
+ let(:new_post) do
25
+ ArchivablePost.new(title: 'test')
26
+ end
27
+
28
+ it 'returns true' do
29
+ expect(new_post).to be_valid
30
+ end
31
+ end
32
+
33
+ context 'when the field is unique for non archived docs' do
34
+
35
+ before do
36
+ post.delete
37
+ end
38
+
39
+ let(:new_post) do
40
+ ArchivablePost.new(title: 'testing')
41
+ end
42
+
43
+ it 'returns true' do
44
+ expect(new_post).to be_valid
45
+ end
46
+ end
47
+
48
+ context 'when the field is not unique for archived docs' do
49
+
50
+ before do
51
+ post = ArchivablePost.create(title: 'test')
52
+ post.archive
53
+ end
54
+
55
+ let(:new_post) do
56
+ ArchivablePost.new(title: 'test')
57
+ end
58
+
59
+ it 'returns true' do
60
+ expect(new_post).to be_valid
61
+ end
62
+ end
63
+
64
+ context 'when the field is not unique' do
65
+
66
+ let(:new_post) do
67
+ ArchivablePost.new(title: 'testing')
68
+ end
69
+
70
+ it 'returns false' do
71
+ expect(new_post).not_to be_valid
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,43 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'mongoid'
5
+ require 'mongoid_archival'
6
+ require 'rspec'
7
+
8
+ # When testing locally we use the database named mongoid_test. However when
9
+ # tests are running in parallel on Travis we need to use different database
10
+ # names for each process running since we do not have transactions and want a
11
+ # clean slate before each spec run.
12
+ def database_id
13
+ 'mongoid_archival_test'
14
+ end
15
+
16
+ # Set the database that the spec suite connects to.
17
+ Mongoid.configure do |config|
18
+ config.belongs_to_required_by_default = false
19
+ config.connect_to(database_id)
20
+ end
21
+
22
+ RSpec.configure do |config|
23
+
24
+ # Drop all collections
25
+ config.before(:each) do
26
+ Mongoid.purge!
27
+ end
28
+
29
+ config.before(:all) do
30
+ Mongoid.logger.level = Logger::INFO
31
+ Mongo::Logger.logger.level = Logger::INFO
32
+ end
33
+
34
+ config.after(:all) do
35
+ Mongoid.purge!
36
+ end
37
+ end
38
+
39
+ ActiveSupport::Inflector.inflections do |inflect|
40
+ inflect.singular('address_components', 'address_component')
41
+ end
42
+
43
+ Dir[File.join(File.dirname(__FILE__), 'app/models/*.rb')].each {|f| require(f) }
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid_archival
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Durran Jordan
8
+ - Josef Šimánek
9
+ - Johnny Shields
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2021-07-25 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongoid
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '7.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '7.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: rspec
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rubocop
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.8.1
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.8.1
57
+ description: Enables archiving (soft delete) of Mongoid documents.
58
+ email:
59
+ - durran@gmail.com
60
+ - retro@ballgag.cz
61
+ - info@tablecheck.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - LICENSE
67
+ - README.md
68
+ - lib/mongoid/archivable.rb
69
+ - lib/mongoid/archivable/configuration.rb
70
+ - lib/mongoid/archivable/depending.rb
71
+ - lib/mongoid/archivable/protected.rb
72
+ - lib/mongoid/archivable/version.rb
73
+ - lib/mongoid_archival.rb
74
+ - perf/scope.rb
75
+ - spec/app/models/address.rb
76
+ - spec/app/models/appointment.rb
77
+ - spec/app/models/archivable_phone.rb
78
+ - spec/app/models/archivable_post.rb
79
+ - spec/app/models/author.rb
80
+ - spec/app/models/fish.rb
81
+ - spec/app/models/person.rb
82
+ - spec/app/models/phone.rb
83
+ - spec/app/models/relations.rb
84
+ - spec/app/models/sport.rb
85
+ - spec/app/models/tag.rb
86
+ - spec/app/models/title.rb
87
+ - spec/mongoid/archive_spec.rb
88
+ - spec/mongoid/configuration_spec.rb
89
+ - spec/mongoid/document_spec.rb
90
+ - spec/mongoid/nested_attributes_spec.rb
91
+ - spec/mongoid/protected_spec.rb
92
+ - spec/mongoid/restore_spec.rb
93
+ - spec/mongoid/scopes_spec.rb
94
+ - spec/mongoid/validatable/uniqueness_spec.rb
95
+ - spec/spec_helper.rb
96
+ homepage: https://github.com/tablecheck/mongoid_archival
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.1.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Archivable documents
119
+ test_files:
120
+ - perf/scope.rb
121
+ - spec/app/models/address.rb
122
+ - spec/app/models/appointment.rb
123
+ - spec/app/models/archivable_phone.rb
124
+ - spec/app/models/archivable_post.rb
125
+ - spec/app/models/author.rb
126
+ - spec/app/models/fish.rb
127
+ - spec/app/models/person.rb
128
+ - spec/app/models/phone.rb
129
+ - spec/app/models/relations.rb
130
+ - spec/app/models/sport.rb
131
+ - spec/app/models/tag.rb
132
+ - spec/app/models/title.rb
133
+ - spec/mongoid/archive_spec.rb
134
+ - spec/mongoid/configuration_spec.rb
135
+ - spec/mongoid/document_spec.rb
136
+ - spec/mongoid/nested_attributes_spec.rb
137
+ - spec/mongoid/protected_spec.rb
138
+ - spec/mongoid/restore_spec.rb
139
+ - spec/mongoid/scopes_spec.rb
140
+ - spec/mongoid/validatable/uniqueness_spec.rb
141
+ - spec/spec_helper.rb