mongoid_archival 0.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.
@@ -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