mongoid-multitenancy 2.0.3 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -1
- data/README.md +25 -6
- data/gemfiles/Gemfile.mongoid-6 +1 -1
- data/gemfiles/Gemfile.mongoid-7 +1 -1
- data/gemfiles/Gemfile.mongoid-8 +14 -0
- data/gemfiles/Gemfile.mongoid-9 +14 -0
- data/lib/mongoid/multitenancy/document.rb +4 -2
- data/lib/mongoid/multitenancy/validators/tenant_uniqueness.rb +5 -1
- data/lib/mongoid/multitenancy/version.rb +1 -1
- data/mongoid-multitenancy.gemspec +1 -1
- data/spec/conditional_uniqueness_spec.rb +61 -0
- data/spec/indexable_spec.rb +49 -14
- data/spec/models/conditional_uniqueness.rb +14 -0
- data/spec/models/indexable.rb +53 -2
- data/spec/models/optional_exclude.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 485b7b5927867bd3f2e3d33aa0705a0f78422a81cba9b5f207b7c71ba56fda65
|
4
|
+
data.tar.gz: 07c63615e55a7a66d7776bf61b8fd741dd15105bfb14404742242dfe36cc0387
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 406b1104c97d9faa39822f114bb4c4b0687e2aedcf0f307e5dc2d90a96ef11a89509988a585f79030aec5ec2948ead959a351d558cc933152f55344b6ee3c96f
|
7
|
+
data.tar.gz: e46f79ec9b5dbe8adef7f3f5da17e6eb34397f600679e5c2f8c140b1c6911a88712b919b3c3e7a4fc9938f63731354c268e97345261441384ac821f83d2e3ebd
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [2.0.5] - 2024-09-20
|
8
|
+
### Fixed
|
9
|
+
|
10
|
+
* Fix uniqueness validator when used with conditions
|
11
|
+
|
12
|
+
## [2.0.4] - 2024-06-17
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
* Full Support of mongoid 8 & 9
|
16
|
+
|
7
17
|
## [2.0.3] - 2020-06-25
|
8
18
|
### Fixed
|
9
19
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -15,7 +15,7 @@ In addition, mongoid-multitenancy:
|
|
15
15
|
Compatibility
|
16
16
|
===============
|
17
17
|
|
18
|
-
mongoid-multitenancy 2
|
18
|
+
mongoid-multitenancy 2 is compatible with mongoid 6/7/8/9. For mongoid 4/5 compatiblity, use mongoid-multitenancy 1.2.
|
19
19
|
|
20
20
|
Installation
|
21
21
|
===============
|
@@ -226,16 +226,32 @@ class Article
|
|
226
226
|
end
|
227
227
|
```
|
228
228
|
|
229
|
+
TenantUniqueness validator also allow to specify additional `conditions` to limit the uniqueness of the constraint.
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
class Article
|
233
|
+
include Mongoid::Document
|
234
|
+
include Mongoid::Multitenancy::Document
|
235
|
+
|
236
|
+
tenant :tenant, optional: true
|
237
|
+
|
238
|
+
field :title
|
239
|
+
field :slug
|
240
|
+
|
241
|
+
validates_tenant_uniqueness_of :slug, exclude_shared: true, conditions: -> { ne(title: nil) }
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
229
245
|
Mongoid indexes
|
230
246
|
-------------------
|
231
247
|
|
232
|
-
mongoid-multitenancy automatically adds the tenant foreign key in all your mongoid indexes to avoid to redefine all your validators. If you prefer to define
|
248
|
+
mongoid-multitenancy automatically adds the tenant foreign key in all your mongoid indexes to avoid to redefine all your validators. If you prefer to define the indexes manually, you can use the option `full_indexes: false` on the tenant or `full_index: true/false` on the indexes.
|
233
249
|
|
234
250
|
To create a single index on the tenant field, you can use the option `index: true` like any `belongs_to` declaration (false by default)
|
235
251
|
|
236
|
-
On the example below, only one
|
252
|
+
On the example below, only one index will be created:
|
237
253
|
|
238
|
-
* { '
|
254
|
+
* { 'tenant_id' => 1, 'title' => 1 }
|
239
255
|
|
240
256
|
```ruby
|
241
257
|
class Article
|
@@ -250,10 +266,11 @@ class Article
|
|
250
266
|
end
|
251
267
|
```
|
252
268
|
|
253
|
-
On the example below,
|
269
|
+
On the example below, 3 indexes will be created:
|
254
270
|
|
255
271
|
* { 'tenant_id' => 1 }
|
256
|
-
* { '
|
272
|
+
* { 'tenant_id' => 1, 'title' => 1 }
|
273
|
+
* { 'name' => 1 }
|
257
274
|
|
258
275
|
```ruby
|
259
276
|
class Article
|
@@ -263,8 +280,10 @@ class Article
|
|
263
280
|
tenant :tenant, index: true
|
264
281
|
|
265
282
|
field :title
|
283
|
+
field :name
|
266
284
|
|
267
285
|
index({ :title => 1 })
|
286
|
+
index({ :name => 1 }, { full_index: false })
|
268
287
|
end
|
269
288
|
```
|
270
289
|
|
data/gemfiles/Gemfile.mongoid-6
CHANGED
data/gemfiles/Gemfile.mongoid-7
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'mongoid', '~> 8.0'
|
4
|
+
|
5
|
+
gem 'rake'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'database_cleaner-mongoid'
|
9
|
+
gem 'coveralls', require: false
|
10
|
+
gem 'rspec', '~> 3.1'
|
11
|
+
gem 'yard'
|
12
|
+
gem 'mongoid-rspec', git: 'https://github.com/mongoid-rspec/mongoid-rspec.git'
|
13
|
+
gem 'rubocop', require: false
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'mongoid', '~> 9.0'
|
4
|
+
|
5
|
+
gem 'rake'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'database_cleaner-mongoid'
|
9
|
+
gem 'coveralls', require: false
|
10
|
+
gem 'rspec', '~> 3.1'
|
11
|
+
gem 'yard'
|
12
|
+
gem 'mongoid-rspec', git: 'https://github.com/mongoid-rspec/mongoid-rspec.git'
|
13
|
+
gem 'rubocop', require: false
|
14
|
+
end
|
@@ -87,11 +87,13 @@ module Mongoid
|
|
87
87
|
|
88
88
|
# Redefine 'index' to include the tenant field in first position
|
89
89
|
def index(spec, options = nil)
|
90
|
-
|
90
|
+
super_options = (options || {}).dup
|
91
|
+
full_index = super_options.delete(:full_index)
|
92
|
+
if full_index.nil? ? tenant_options[:full_indexes] : full_index
|
91
93
|
spec = { tenant_field => 1 }.merge(spec)
|
92
94
|
end
|
93
95
|
|
94
|
-
super(spec,
|
96
|
+
super(spec, super_options)
|
95
97
|
end
|
96
98
|
|
97
99
|
# Redefine 'delete_all' to take in account the default scope
|
@@ -37,7 +37,11 @@ module Mongoid
|
|
37
37
|
|
38
38
|
# <<Add the tenant Criteria>>
|
39
39
|
criteria = with_tenant_criterion(criteria, klass, document)
|
40
|
-
|
40
|
+
# Add additional conditions
|
41
|
+
if options[:conditions]
|
42
|
+
conditions = klass.unscoped { options[:conditions].call }
|
43
|
+
criteria = criteria.merge(conditions)
|
44
|
+
end
|
41
45
|
|
42
46
|
if criteria.read(mode: :primary).exists?
|
43
47
|
add_error(document, attribute, value)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ConditionalUniqueness do
|
4
|
+
let(:client) do
|
5
|
+
Account.create!(name: 'client')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:another_client) do
|
9
|
+
Account.create!(name: 'another client')
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:item) do
|
13
|
+
ConditionalUniqueness.new(approved: true, slug: 'page-x')
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'a tenantable model'
|
17
|
+
|
18
|
+
describe '#valid?' do
|
19
|
+
context 'with a tenant' do
|
20
|
+
before do
|
21
|
+
Mongoid::Multitenancy.current_tenant = client
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is valid' do
|
25
|
+
expect(item).to be_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with a duplicate on the constraint' do
|
29
|
+
let(:duplicate) do
|
30
|
+
ConditionalUniqueness.new(approved: true, slug: 'page-x')
|
31
|
+
end
|
32
|
+
|
33
|
+
before do
|
34
|
+
item.save!
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'is not valid' do
|
38
|
+
expect(duplicate).not_to be_valid
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a duplicate outside the conditions' do
|
42
|
+
before do
|
43
|
+
item.update(approved: false)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'is valid' do
|
47
|
+
expect(duplicate).to be_valid
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with a different tenant' do
|
52
|
+
it 'is valid' do
|
53
|
+
Mongoid::Multitenancy.with_tenant(another_client) do
|
54
|
+
expect(duplicate).to be_valid
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/indexable_spec.rb
CHANGED
@@ -9,27 +9,62 @@ describe 'tenant' do
|
|
9
9
|
Mongoid::Multitenancy.current_tenant = client
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
describe 'tenant full_indexes option' do
|
13
|
+
context 'without index option' do
|
14
|
+
it 'does not create an index' do
|
15
|
+
expect(IndexableWithoutIndex).not_to have_index_for(tenant_id: 1)
|
16
|
+
end
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
context 'with index: false' do
|
20
|
+
it 'does not create an index' do
|
21
|
+
expect(IndexableWithIndexFalse).not_to have_index_for(tenant_id: 1)
|
22
|
+
end
|
21
23
|
end
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
context 'with index: true' do
|
26
|
+
it 'creates an index' do
|
27
|
+
expect(IndexableWithIndexTrue).to have_index_for(tenant_id: 1)
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
describe 'index full_index option' do
|
33
|
+
context 'without tenant full_indexes option specified' do
|
34
|
+
it 'adds the tenant field on each index' do
|
35
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(tenant_id: 1, title: 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'adds the tenant field on the index with full_index: true' do
|
39
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(tenant_id: 1, name: 1)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'does not add the tenant field on the index with full_index: false' do
|
43
|
+
expect(IndexableWithoutFullIndexes).not_to have_index_for(tenant_id: 1, slug: 1)
|
44
|
+
expect(IndexableWithoutFullIndexes).to have_index_for(slug: 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with full_indexes: true' do
|
49
|
+
it 'adds the tenant field on each index' do
|
50
|
+
expect(IndexableWithFullIndexesTrue).to have_index_for(tenant_id: 1, title: 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not add the tenant field on the index with full_index: false' do
|
54
|
+
expect(IndexableWithFullIndexesTrue).not_to have_index_for(tenant_id: 1, name: 1)
|
55
|
+
expect(IndexableWithFullIndexesTrue).to have_index_for(name: 1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with full_indexes: false' do
|
60
|
+
it 'does not add the tenant field on each index' do
|
61
|
+
expect(IndexableWithFullIndexesFalse).not_to have_index_for(tenant_id: 1, title: 1)
|
62
|
+
expect(IndexableWithFullIndexesFalse).to have_index_for(title: 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'does add the tenant field on the index with full_index: true' do
|
66
|
+
expect(IndexableWithFullIndexesFalse).to have_index_for(tenant_id: 1, name: 1)
|
67
|
+
end
|
33
68
|
end
|
34
69
|
end
|
35
70
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ConditionalUniqueness
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant(:tenant, class_name: 'Account', optional: true)
|
6
|
+
|
7
|
+
field :slug, type: String
|
8
|
+
field :approved, type: Boolean, default: false
|
9
|
+
|
10
|
+
validates_tenant_uniqueness_of :slug, conditions: -> { where(approved: true) }
|
11
|
+
validates_presence_of :slug
|
12
|
+
|
13
|
+
index(title: 1)
|
14
|
+
end
|
data/spec/models/indexable.rb
CHANGED
@@ -1,10 +1,61 @@
|
|
1
|
-
class
|
1
|
+
class IndexableWithoutIndex
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Multitenancy::Document
|
4
|
+
|
5
|
+
tenant :tenant, class_name: 'Account'
|
6
|
+
end
|
7
|
+
|
8
|
+
class IndexableWithIndexTrue
|
9
|
+
include Mongoid::Document
|
10
|
+
include Mongoid::Multitenancy::Document
|
11
|
+
|
12
|
+
tenant :tenant, class_name: 'Account', index: true
|
13
|
+
end
|
14
|
+
|
15
|
+
class IndexableWithIndexFalse
|
16
|
+
include Mongoid::Document
|
17
|
+
include Mongoid::Multitenancy::Document
|
18
|
+
|
19
|
+
tenant :tenant, class_name: 'Account', index: false
|
20
|
+
end
|
21
|
+
|
22
|
+
class IndexableWithoutFullIndexes
|
23
|
+
include Mongoid::Document
|
24
|
+
include Mongoid::Multitenancy::Document
|
25
|
+
|
26
|
+
field :title, type: String
|
27
|
+
field :name, type: String
|
28
|
+
field :slug, type: String
|
29
|
+
|
30
|
+
tenant :tenant, class_name: 'Account'
|
31
|
+
|
32
|
+
index(title: 1)
|
33
|
+
index({ name: 1 }, { full_index: true })
|
34
|
+
index({ slug: 1 }, { full_index: false })
|
35
|
+
end
|
36
|
+
|
37
|
+
class IndexableWithFullIndexesFalse
|
38
|
+
include Mongoid::Document
|
39
|
+
include Mongoid::Multitenancy::Document
|
40
|
+
|
41
|
+
field :title, type: String
|
42
|
+
field :name, type: String
|
43
|
+
|
44
|
+
tenant :tenant, class_name: 'Account', full_indexes: false
|
45
|
+
|
46
|
+
index(title: 1)
|
47
|
+
index({ name: 1 }, { full_index: true })
|
48
|
+
end
|
49
|
+
|
50
|
+
class IndexableWithFullIndexesTrue
|
2
51
|
include Mongoid::Document
|
3
52
|
include Mongoid::Multitenancy::Document
|
4
53
|
|
5
54
|
field :title, type: String
|
55
|
+
field :name, type: String
|
6
56
|
|
7
|
-
tenant :tenant, class_name: 'Account',
|
57
|
+
tenant :tenant, class_name: 'Account', full_indexes: true
|
8
58
|
|
9
59
|
index(title: 1)
|
60
|
+
index({ name: 1 }, { full_index: false })
|
10
61
|
end
|
@@ -7,7 +7,7 @@ class OptionalExclude
|
|
7
7
|
field :slug, type: String
|
8
8
|
field :title, type: String
|
9
9
|
|
10
|
-
validates_tenant_uniqueness_of :slug, exclude_shared: true
|
10
|
+
validates_tenant_uniqueness_of :slug, exclude_shared: true, conditions: -> { ne(title: nil) }
|
11
11
|
validates_presence_of :slug
|
12
12
|
validates_presence_of :title
|
13
13
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-multitenancy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aymeric Brisse
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '6'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '10'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '6'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '10'
|
33
33
|
description: MultiTenancy with Mongoid
|
34
34
|
email:
|
35
35
|
- aymeric.brisse@mperfect-memory.com
|
@@ -47,6 +47,8 @@ files:
|
|
47
47
|
- Rakefile
|
48
48
|
- gemfiles/Gemfile.mongoid-6
|
49
49
|
- gemfiles/Gemfile.mongoid-7
|
50
|
+
- gemfiles/Gemfile.mongoid-8
|
51
|
+
- gemfiles/Gemfile.mongoid-9
|
50
52
|
- lib/mongoid-multitenancy.rb
|
51
53
|
- lib/mongoid/multitenancy.rb
|
52
54
|
- lib/mongoid/multitenancy/document.rb
|
@@ -54,11 +56,13 @@ files:
|
|
54
56
|
- lib/mongoid/multitenancy/validators/tenant_uniqueness.rb
|
55
57
|
- lib/mongoid/multitenancy/version.rb
|
56
58
|
- mongoid-multitenancy.gemspec
|
59
|
+
- spec/conditional_uniqueness_spec.rb
|
57
60
|
- spec/immutable_spec.rb
|
58
61
|
- spec/indexable_spec.rb
|
59
62
|
- spec/inheritance_spec.rb
|
60
63
|
- spec/mandatory_spec.rb
|
61
64
|
- spec/models/account.rb
|
65
|
+
- spec/models/conditional_uniqueness.rb
|
62
66
|
- spec/models/immutable.rb
|
63
67
|
- spec/models/indexable.rb
|
64
68
|
- spec/models/mandatory.rb
|
@@ -95,17 +99,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
99
|
- !ruby/object:Gem::Version
|
96
100
|
version: '0'
|
97
101
|
requirements: []
|
98
|
-
|
99
|
-
rubygems_version: 2.6.14.4
|
102
|
+
rubygems_version: 3.3.27
|
100
103
|
signing_key:
|
101
104
|
specification_version: 4
|
102
105
|
summary: Support of a multi-tenant database with Mongoid
|
103
106
|
test_files:
|
107
|
+
- spec/conditional_uniqueness_spec.rb
|
104
108
|
- spec/immutable_spec.rb
|
105
109
|
- spec/indexable_spec.rb
|
106
110
|
- spec/inheritance_spec.rb
|
107
111
|
- spec/mandatory_spec.rb
|
108
112
|
- spec/models/account.rb
|
113
|
+
- spec/models/conditional_uniqueness.rb
|
109
114
|
- spec/models/immutable.rb
|
110
115
|
- spec/models/indexable.rb
|
111
116
|
- spec/models/mandatory.rb
|