activerecord-multi-tenant 2.2.0 → 2.3.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/.github/workflows/active-record-multi-tenant-tests.yml +80 -0
- data/.gitignore +6 -0
- data/.readthedocs.yaml +15 -0
- data/.rspec +0 -0
- data/.rubocop.yml +51 -0
- data/Appraisals +0 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -1
- data/LICENSE +0 -0
- data/README.md +2 -1
- data/Rakefile +1 -1
- data/activerecord-multi-tenant.gemspec +28 -22
- data/docker-compose.yml +24 -18
- data/docs/.gitignore +3 -0
- data/docs/Makefile +28 -0
- data/docs/api-reference.sh +10 -0
- data/docs/requirements.in +4 -0
- data/docs/requirements.txt +62 -0
- data/docs/source/_static/api-reference/ActiveRecord/Associations/Association.html +285 -0
- data/docs/source/_static/api-reference/ActiveRecord/Associations/ClassMethods.html +255 -0
- data/docs/source/_static/api-reference/ActiveRecord/Associations.html +117 -0
- data/docs/source/_static/api-reference/ActiveRecord/ConnectionAdapters/SchemaStatements.html +232 -0
- data/docs/source/_static/api-reference/ActiveRecord/ConnectionAdapters.html +126 -0
- data/docs/source/_static/api-reference/ActiveRecord/QueryMethods.html +336 -0
- data/docs/source/_static/api-reference/ActiveRecord/SchemaDumper.html +121 -0
- data/docs/source/_static/api-reference/ActiveRecord.html +130 -0
- data/docs/source/_static/api-reference/MultiTenant/ArelTenantVisitor.html +755 -0
- data/docs/source/_static/api-reference/MultiTenant/ArelVisitorsDepthFirst.html +208 -0
- data/docs/source/_static/api-reference/MultiTenant/BaseTenantEnforcementClause.html +462 -0
- data/docs/source/_static/api-reference/MultiTenant/Context.html +659 -0
- data/docs/source/_static/api-reference/MultiTenant/ControllerExtensions.html +202 -0
- data/docs/source/_static/api-reference/MultiTenant/CopyFromClient.html +186 -0
- data/docs/source/_static/api-reference/MultiTenant/CopyFromClientHelper.html +362 -0
- data/docs/source/_static/api-reference/MultiTenant/Current.html +124 -0
- data/docs/source/_static/api-reference/MultiTenant/DatabaseStatements.html +366 -0
- data/docs/source/_static/api-reference/MultiTenant/FastTruncate.html +226 -0
- data/docs/source/_static/api-reference/MultiTenant/MigrationExtensions.html +554 -0
- data/docs/source/_static/api-reference/MultiTenant/MissingTenantError.html +124 -0
- data/docs/source/_static/api-reference/MultiTenant/ModelExtensionsClassMethods.html +492 -0
- data/docs/source/_static/api-reference/MultiTenant/QueryMonitor.html +257 -0
- data/docs/source/_static/api-reference/MultiTenant/Table.html +419 -0
- data/docs/source/_static/api-reference/MultiTenant/TenantEnforcementClause.html +148 -0
- data/docs/source/_static/api-reference/MultiTenant/TenantIsImmutable.html +135 -0
- data/docs/source/_static/api-reference/MultiTenant/TenantJoinEnforcementClause.html +310 -0
- data/docs/source/_static/api-reference/MultiTenant/TenantValueVisitor.html +239 -0
- data/docs/source/_static/api-reference/MultiTenant.html +1454 -0
- data/docs/source/_static/api-reference/MultiTenantFindBy.html +180 -0
- data/docs/source/_static/api-reference/Sidekiq/Client.html +302 -0
- data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant/Client.html +217 -0
- data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant/Server.html +219 -0
- data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant.html +126 -0
- data/docs/source/_static/api-reference/Sidekiq.html +126 -0
- data/docs/source/_static/api-reference/_index.html +399 -0
- data/docs/source/_static/api-reference/class_list.html +51 -0
- data/docs/source/_static/api-reference/css/common.css +1 -0
- data/docs/source/_static/api-reference/css/full_list.css +58 -0
- data/docs/source/_static/api-reference/css/style.css +497 -0
- data/docs/source/_static/api-reference/file.README.html +167 -0
- data/docs/source/_static/api-reference/file_list.html +56 -0
- data/docs/source/_static/api-reference/frames.html +17 -0
- data/docs/source/_static/api-reference/index.html +167 -0
- data/docs/source/_static/api-reference/js/app.js +314 -0
- data/docs/source/_static/api-reference/js/full_list.js +216 -0
- data/docs/source/_static/api-reference/js/jquery.js +4 -0
- data/docs/source/_static/api-reference/method_list.html +715 -0
- data/docs/source/_static/api-reference/top-level-namespace.html +126 -0
- data/docs/source/_templates/.gitignore +4 -0
- data/docs/source/api-reference.rst +8 -0
- data/docs/source/appendix.rst +26 -0
- data/docs/source/changelog.rst +8 -0
- data/docs/source/community-and-support.rst +26 -0
- data/docs/source/conf.py +30 -0
- data/docs/source/contributing.rst +70 -0
- data/docs/source/getting-started.rst +37 -0
- data/docs/source/guides-and-tutorials.rst +129 -0
- data/docs/source/index.rst +54 -0
- data/docs/source/introduction.rst +33 -0
- data/docs/source/license.rst +22 -0
- data/docs/source/troubleshooting.rst +41 -0
- data/docs/source/usage-guide.rst +59 -0
- data/lib/activerecord-multi-tenant/arel_visitors_depth_first.rb +183 -174
- data/lib/activerecord-multi-tenant/controller_extensions.rb +15 -4
- data/lib/activerecord-multi-tenant/copy_from_client.rb +4 -0
- data/lib/activerecord-multi-tenant/fast_truncate.rb +4 -2
- data/lib/activerecord-multi-tenant/habtm.rb +50 -0
- data/lib/activerecord-multi-tenant/migrations.rb +18 -8
- data/lib/activerecord-multi-tenant/model_extensions.rb +78 -37
- data/lib/activerecord-multi-tenant/multi_tenant.rb +40 -21
- data/lib/activerecord-multi-tenant/query_monitor.rb +21 -5
- data/lib/activerecord-multi-tenant/query_rewriter.rb +111 -80
- data/lib/activerecord-multi-tenant/sidekiq.rb +31 -20
- data/lib/activerecord-multi-tenant/version.rb +1 -1
- data/lib/activerecord-multi-tenant.rb +3 -12
- data/lib/activerecord_multi_tenant.rb +12 -0
- data/spec/activerecord-multi-tenant/associations_spec.rb +21 -0
- data/spec/activerecord-multi-tenant/controller_extensions_spec.rb +3 -2
- data/spec/activerecord-multi-tenant/fast_truncate_spec.rb +8 -6
- data/spec/activerecord-multi-tenant/model_extensions_spec.rb +233 -153
- data/spec/activerecord-multi-tenant/multi_tenant_spec.rb +15 -13
- data/spec/activerecord-multi-tenant/query_rewriter_spec.rb +60 -59
- data/spec/activerecord-multi-tenant/record_callback_spec.rb +0 -0
- data/spec/activerecord-multi-tenant/record_finding_spec.rb +11 -11
- data/spec/activerecord-multi-tenant/record_modifications_spec.rb +4 -4
- data/spec/activerecord-multi-tenant/sidekiq_spec.rb +10 -10
- data/spec/database.yml +0 -0
- data/spec/schema.rb +20 -2
- data/spec/spec_helper.rb +46 -17
- data/spec/support/format_sql.rb +20 -0
- metadata +130 -25
- data/.github/workflows/CI.yml +0 -47
- data/gemfiles/.bundle/config +0 -2
- data/gemfiles/active_record_6.0.gemfile +0 -8
- data/gemfiles/active_record_6.1.gemfile +0 -8
- data/gemfiles/active_record_7.0.gemfile +0 -8
- data/gemfiles/rails_6.0.gemfile +0 -8
- data/gemfiles/rails_6.1.gemfile +0 -8
- data/gemfiles/rails_7.0.gemfile +0 -8
- data/lib/activerecord-multi-tenant/with_lock.rb +0 -15
- data/spec/activerecord-multi-tenant/schema_dumper_tester.rb +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe MultiTenant do
|
|
@@ -10,11 +12,11 @@ describe MultiTenant do
|
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
describe 'is_scoped_as_tenant should return the correct value when true' do
|
|
13
|
-
it {expect(Project.respond_to?(:scoped_by_tenant?)).to eq(true)}
|
|
15
|
+
it { expect(Project.respond_to?(:scoped_by_tenant?)).to eq(true) }
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
describe 'is_scoped_as_tenant should return the correct value when false' do
|
|
17
|
-
it {expect(UnscopedModel.respond_to?(:scoped_by_tenant?)).to eq(false)}
|
|
19
|
+
it { expect(UnscopedModel.respond_to?(:scoped_by_tenant?)).to eq(false) }
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
context 'immutability' do
|
|
@@ -43,17 +45,17 @@ describe MultiTenant do
|
|
|
43
45
|
@account = Account.create! name: 'foo'
|
|
44
46
|
MultiTenant.current_tenant = @account
|
|
45
47
|
end
|
|
46
|
-
it {expect(Project.new.account_id).to eq(@account.id)}
|
|
48
|
+
it { expect(Project.new.account_id).to eq(@account.id) }
|
|
47
49
|
it 'should handle partial selects' do
|
|
48
50
|
project = Project.create!
|
|
49
|
-
expect{project = Project.select(:name).find(project.id)}.not_to raise_error
|
|
51
|
+
expect { project = Project.select(:name).find(project.id) }.not_to raise_error
|
|
50
52
|
expect(project.account_id).to eq(@account.id)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
describe 'Handles custom partition_key on tenant model' do
|
|
55
57
|
before do
|
|
56
|
-
@account
|
|
58
|
+
@account = Account.create! name: 'foo'
|
|
57
59
|
MultiTenant.current_tenant = @account
|
|
58
60
|
@custom_partition_key_task = CustomPartitionKeyTask.create! name: 'foo'
|
|
59
61
|
end
|
|
@@ -70,11 +72,11 @@ describe MultiTenant do
|
|
|
70
72
|
it { expect(@partition_key_not_model_task.non_model_id).to be 77 }
|
|
71
73
|
end
|
|
72
74
|
|
|
73
|
-
|
|
74
75
|
describe 'Tenant model with a nonstandard class name' do
|
|
75
76
|
let(:account_klass) do
|
|
76
77
|
Class.new(ActiveRecord::Base) do
|
|
77
78
|
self.table_name = 'account'
|
|
79
|
+
|
|
78
80
|
def self.name
|
|
79
81
|
'UserAccount'
|
|
80
82
|
end
|
|
@@ -82,7 +84,7 @@ describe MultiTenant do
|
|
|
82
84
|
multi_tenant(:account)
|
|
83
85
|
end
|
|
84
86
|
end
|
|
85
|
-
it
|
|
87
|
+
it 'does not register the tenant model' do
|
|
86
88
|
expect(MultiTenant).not_to receive(:register_multi_tenant_model)
|
|
87
89
|
account_klass
|
|
88
90
|
end
|
|
@@ -129,6 +131,13 @@ describe MultiTenant do
|
|
|
129
131
|
it { expect(@posts).to eq([@post1]) }
|
|
130
132
|
end
|
|
131
133
|
|
|
134
|
+
describe 'inspect method filters senstive column values' do
|
|
135
|
+
it 'filters senstive value' do
|
|
136
|
+
account = Account.new(name: 'foo', password: 'baz')
|
|
137
|
+
expect(account.inspect).to eq '#<Account id: nil, name: nil, subdomain: nil, domain: nil, password: [FILTERED]>'
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
132
141
|
# Scoping models
|
|
133
142
|
describe 'Project.all should be scoped to the current tenant if set' do
|
|
134
143
|
before do
|
|
@@ -171,16 +180,16 @@ describe MultiTenant do
|
|
|
171
180
|
end
|
|
172
181
|
end
|
|
173
182
|
|
|
174
|
-
describe
|
|
183
|
+
describe 'It should be possible to use aliased associations' do
|
|
175
184
|
before do
|
|
176
185
|
@account = Account.create! name: 'baz'
|
|
177
186
|
MultiTenant.current_tenant = @account
|
|
178
187
|
end
|
|
179
188
|
|
|
180
|
-
it { expect(AliasedTask.create(:
|
|
189
|
+
it { expect(AliasedTask.create(name: 'foo', project_alias: @project2).valid?).to eq(true) }
|
|
181
190
|
end
|
|
182
191
|
|
|
183
|
-
describe
|
|
192
|
+
describe 'It should be possible to use associations with partition_key from polymorphic' do
|
|
184
193
|
before do
|
|
185
194
|
@account = Account.create!(name: 'foo')
|
|
186
195
|
MultiTenant.current_tenant = @account
|
|
@@ -237,7 +246,7 @@ describe MultiTenant do
|
|
|
237
246
|
MultiTenant.with(account) do
|
|
238
247
|
sub_task
|
|
239
248
|
manager
|
|
240
|
-
expect(Project.eager_load([{manager: :project}, {tasks: :project}]).first).to eq project
|
|
249
|
+
expect(Project.eager_load([{ manager: :project }, { tasks: :project }]).first).to eq project
|
|
241
250
|
end
|
|
242
251
|
end
|
|
243
252
|
end
|
|
@@ -248,7 +257,8 @@ describe MultiTenant do
|
|
|
248
257
|
|
|
249
258
|
it 'rewrites sub-selects correctly' do
|
|
250
259
|
MultiTenant.with(account) do
|
|
251
|
-
expect(Project.where(id: Project.where(id: project.id))
|
|
260
|
+
expect(Project.where(id: Project.where(id: project.id))
|
|
261
|
+
.where(id: Project.where(id: project.id)).first).to eq project
|
|
252
262
|
end
|
|
253
263
|
end
|
|
254
264
|
end
|
|
@@ -277,34 +287,34 @@ describe MultiTenant do
|
|
|
277
287
|
end
|
|
278
288
|
|
|
279
289
|
describe 'non-STI Subclass of abstract Multi Tenant Model' do
|
|
280
|
-
let(:
|
|
281
|
-
let(:
|
|
290
|
+
let(:tenant_id1) { 42 }
|
|
291
|
+
let(:tenant_id2) { 314_158 }
|
|
282
292
|
let(:name) { 'fooname' }
|
|
283
|
-
let(:
|
|
284
|
-
MultiTenant.with(
|
|
293
|
+
let(:subclass_task1) do
|
|
294
|
+
MultiTenant.with(tenant_id1) { SubclassTask.create! name: name }
|
|
285
295
|
end
|
|
286
|
-
let(:
|
|
287
|
-
MultiTenant.with(
|
|
296
|
+
let(:subclass_task2) do
|
|
297
|
+
MultiTenant.with(tenant_id2) { SubclassTask.create! name: name }
|
|
288
298
|
end
|
|
289
299
|
|
|
290
300
|
before do
|
|
291
|
-
|
|
292
|
-
|
|
301
|
+
subclass_task1
|
|
302
|
+
subclass_task2
|
|
293
303
|
end
|
|
294
304
|
|
|
295
305
|
it 'injects tenant_id on create' do
|
|
296
|
-
expect(
|
|
297
|
-
expect(
|
|
306
|
+
expect(subclass_task1.non_model_id).to be tenant_id1
|
|
307
|
+
expect(subclass_task2.non_model_id).to be tenant_id2
|
|
298
308
|
end
|
|
299
309
|
|
|
300
310
|
it 'rewrites query' do
|
|
301
|
-
MultiTenant.with(
|
|
311
|
+
MultiTenant.with(tenant_id1) do
|
|
302
312
|
expect(SubclassTask.where(name: name).count).to eq 1
|
|
303
|
-
expect(SubclassTask.where(name: name).first).to eq
|
|
313
|
+
expect(SubclassTask.where(name: name).first).to eq subclass_task1
|
|
304
314
|
end
|
|
305
|
-
MultiTenant.with(
|
|
315
|
+
MultiTenant.with(tenant_id2) do
|
|
306
316
|
expect(SubclassTask.where(name: name).count).to eq 1
|
|
307
|
-
expect(SubclassTask.where(name: name).first).to eq
|
|
317
|
+
expect(SubclassTask.where(name: name).first).to eq subclass_task2
|
|
308
318
|
end
|
|
309
319
|
end
|
|
310
320
|
end
|
|
@@ -316,20 +326,27 @@ describe MultiTenant do
|
|
|
316
326
|
|
|
317
327
|
it 'should add tenant condition to the queries when tenant is set' do
|
|
318
328
|
expected_join_sql = <<-SQL.strip
|
|
319
|
-
SELECT "comments"
|
|
329
|
+
SELECT "comments".*#{' '}
|
|
330
|
+
FROM "comments"#{' '}
|
|
331
|
+
INNER JOIN "tasks" ON "tasks"."id" = "comments"."commentable_id"#{' '}
|
|
332
|
+
AND "comments"."commentable_type" = 'Task' AND "tasks"."account_id" = 1#{' '}
|
|
333
|
+
WHERE "comments"."account_id" = 1
|
|
320
334
|
SQL
|
|
321
335
|
|
|
322
336
|
MultiTenant.with(account) do
|
|
323
|
-
expect(Comment.joins(:task).to_sql).to eq(expected_join_sql)
|
|
337
|
+
expect(format_sql(Comment.joins(:task).to_sql)).to eq(format_sql(expected_join_sql))
|
|
324
338
|
end
|
|
325
339
|
end
|
|
326
340
|
|
|
327
341
|
it 'should add tenant condition to the queries when tenant is not set' do
|
|
328
342
|
MultiTenant.without do
|
|
329
343
|
expected_join_sql = <<-SQL.strip
|
|
330
|
-
SELECT "comments"
|
|
344
|
+
SELECT "comments".*#{' '}
|
|
345
|
+
FROM "comments"#{' '}
|
|
346
|
+
INNER JOIN "tasks" ON "tasks"."id" = "comments"."commentable_id"#{' '}
|
|
347
|
+
AND "comments"."commentable_type" = 'Task' AND "comments"."account_id" = "tasks"."account_id"
|
|
331
348
|
SQL
|
|
332
|
-
expect(Comment.joins(:task).to_sql).to eq(expected_join_sql)
|
|
349
|
+
expect(format_sql(Comment.joins(:task).to_sql)).to eq(format_sql(expected_join_sql))
|
|
333
350
|
end
|
|
334
351
|
end
|
|
335
352
|
end
|
|
@@ -339,57 +356,63 @@ describe MultiTenant do
|
|
|
339
356
|
|
|
340
357
|
it 'should add tenant condition to the queries when tenant is set' do
|
|
341
358
|
expected_join_sql = <<-SQL.strip
|
|
342
|
-
SELECT "projects"
|
|
359
|
+
SELECT "projects".*#{' '}
|
|
360
|
+
FROM "projects"#{' '}
|
|
361
|
+
INNER JOIN "tasks" ON "tasks"."project_id" = "projects"."id"#{' '}
|
|
362
|
+
AND "tasks"."account_id" = 1#{' '}
|
|
363
|
+
WHERE "projects"."account_id" = 1
|
|
343
364
|
SQL
|
|
344
365
|
|
|
345
366
|
MultiTenant.with(account) do
|
|
346
|
-
expect(Project.joins(:tasks).to_sql).to eq(expected_join_sql)
|
|
367
|
+
expect(format_sql(Project.joins(:tasks).to_sql)).to eq(format_sql(expected_join_sql))
|
|
347
368
|
end
|
|
348
369
|
end
|
|
349
370
|
|
|
350
371
|
it 'should add tenant condition to the queries when tenant is not set' do
|
|
351
372
|
MultiTenant.without do
|
|
352
373
|
expected_join_sql = <<-SQL.strip
|
|
353
|
-
SELECT "projects".*
|
|
374
|
+
SELECT "projects".*
|
|
375
|
+
FROM "projects"
|
|
376
|
+
INNER JOIN "tasks" ON "tasks"."project_id" = "projects"."id"
|
|
377
|
+
AND "projects"."account_id" = "tasks"."account_id"
|
|
354
378
|
SQL
|
|
355
|
-
expect(Project.joins(:tasks).to_sql).to eq(expected_join_sql)
|
|
379
|
+
expect(format_sql(Project.joins(:tasks).to_sql)).to eq(format_sql(expected_join_sql))
|
|
356
380
|
end
|
|
357
381
|
end
|
|
358
382
|
end
|
|
359
383
|
end
|
|
360
384
|
|
|
361
385
|
# ::with
|
|
362
|
-
describe
|
|
363
|
-
it
|
|
364
|
-
@account = Account.create!(:
|
|
386
|
+
describe '::with' do
|
|
387
|
+
it 'should set current_tenant to the specified tenant inside the block' do
|
|
388
|
+
@account = Account.create!(name: 'baz')
|
|
365
389
|
|
|
366
390
|
MultiTenant.with(@account) do
|
|
367
391
|
expect(MultiTenant.current_tenant).to eq(@account)
|
|
368
392
|
end
|
|
369
393
|
end
|
|
370
394
|
|
|
371
|
-
it
|
|
372
|
-
@account1 = Account.create!(:
|
|
373
|
-
@account2 = Account.create!(:
|
|
395
|
+
it 'should reset current_tenant to the previous tenant once exiting the block' do
|
|
396
|
+
@account1 = Account.create!(name: 'foo')
|
|
397
|
+
@account2 = Account.create!(name: 'bar')
|
|
374
398
|
|
|
375
399
|
MultiTenant.current_tenant = @account1
|
|
376
400
|
MultiTenant.with @account2 do
|
|
377
|
-
|
|
378
401
|
end
|
|
379
402
|
|
|
380
403
|
expect(MultiTenant.current_tenant).to eq(@account1)
|
|
381
404
|
end
|
|
382
405
|
|
|
383
|
-
it
|
|
384
|
-
@account1 = Account.create!(:
|
|
385
|
-
@account2 = Account.create!(:
|
|
406
|
+
it 'should return the value of the block' do
|
|
407
|
+
@account1 = Account.create!(name: 'foo')
|
|
408
|
+
@account2 = Account.create!(name: 'bar')
|
|
386
409
|
|
|
387
410
|
MultiTenant.current_tenant = @account1
|
|
388
411
|
value = MultiTenant.with @account2 do
|
|
389
|
-
|
|
412
|
+
'something'
|
|
390
413
|
end
|
|
391
414
|
|
|
392
|
-
expect(value).to eq
|
|
415
|
+
expect(value).to eq 'something'
|
|
393
416
|
end
|
|
394
417
|
|
|
395
418
|
it 'supports reload inside the block' do
|
|
@@ -404,9 +427,9 @@ describe MultiTenant do
|
|
|
404
427
|
end
|
|
405
428
|
|
|
406
429
|
# ::without
|
|
407
|
-
describe
|
|
408
|
-
it
|
|
409
|
-
@account = Account.create!(:
|
|
430
|
+
describe '::without' do
|
|
431
|
+
it 'should unset current_tenant inside the block' do
|
|
432
|
+
@account = Account.create!(name: 'baz')
|
|
410
433
|
|
|
411
434
|
MultiTenant.current_tenant = @account
|
|
412
435
|
MultiTenant.without do
|
|
@@ -414,39 +437,25 @@ describe MultiTenant do
|
|
|
414
437
|
end
|
|
415
438
|
end
|
|
416
439
|
|
|
417
|
-
it
|
|
418
|
-
@account1 = Account.create!(:
|
|
440
|
+
it 'should reset current_tenant to the previous tenant once exiting the block' do
|
|
441
|
+
@account1 = Account.create!(name: 'foo')
|
|
419
442
|
|
|
420
443
|
MultiTenant.current_tenant = @account1
|
|
421
444
|
MultiTenant.without do
|
|
422
|
-
|
|
423
445
|
end
|
|
424
446
|
|
|
425
447
|
expect(MultiTenant.current_tenant).to eq(@account1)
|
|
426
448
|
end
|
|
427
449
|
|
|
428
|
-
it
|
|
429
|
-
@account1 = Account.create!(:
|
|
450
|
+
it 'should return the value of the block' do
|
|
451
|
+
@account1 = Account.create!(name: 'foo')
|
|
430
452
|
|
|
431
453
|
MultiTenant.current_tenant = @account1
|
|
432
454
|
value = MultiTenant.without do
|
|
433
|
-
|
|
455
|
+
'something'
|
|
434
456
|
end
|
|
435
457
|
|
|
436
|
-
expect(value).to eq
|
|
437
|
-
end
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
describe '.with_lock' do
|
|
441
|
-
it 'supports with_lock blocks inside the block' do
|
|
442
|
-
@account = Account.create!(name: 'foo')
|
|
443
|
-
|
|
444
|
-
MultiTenant.with @account do
|
|
445
|
-
project = @account.projects.create!(name: 'project')
|
|
446
|
-
project.with_lock do
|
|
447
|
-
expect(project.name).to eq 'project'
|
|
448
|
-
end
|
|
449
|
-
end
|
|
458
|
+
expect(value).to eq 'something'
|
|
450
459
|
end
|
|
451
460
|
end
|
|
452
461
|
|
|
@@ -471,13 +480,20 @@ describe MultiTenant do
|
|
|
471
480
|
end
|
|
472
481
|
end
|
|
473
482
|
|
|
474
|
-
it
|
|
475
|
-
option1 = <<-
|
|
476
|
-
SELECT "sub_tasks"
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
483
|
+
it 'applies the team_id conditions in the where clause' do
|
|
484
|
+
option1 = <<-SQL.strip
|
|
485
|
+
SELECT "sub_tasks".*#{' '}
|
|
486
|
+
FROM "sub_tasks"#{' '}
|
|
487
|
+
INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "tasks"."account_id" = "sub_tasks"."account_id"#{' '}
|
|
488
|
+
WHERE "tasks"."project_id" = 1 AND "sub_tasks"."account_id" = 1 AND "tasks"."account_id" = 1
|
|
489
|
+
SQL
|
|
490
|
+
option2 = <<-SQL.strip
|
|
491
|
+
SELECT "sub_tasks".*#{' '}
|
|
492
|
+
FROM "sub_tasks"#{' '}
|
|
493
|
+
INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id"#{' '}
|
|
494
|
+
AND "tasks"."account_id" = "sub_tasks"."account_id"#{' '}
|
|
495
|
+
WHERE "sub_tasks"."account_id" = 1 AND "tasks"."project_id" = 1 AND "tasks"."account_id" = 1
|
|
496
|
+
SQL
|
|
481
497
|
|
|
482
498
|
account1 = Account.create! name: 'Account 1'
|
|
483
499
|
|
|
@@ -485,27 +501,38 @@ describe MultiTenant do
|
|
|
485
501
|
project1 = Project.create! name: 'Project 1'
|
|
486
502
|
task1 = Task.create! name: 'Task 1', project: project1
|
|
487
503
|
subtask1 = SubTask.create! task: task1
|
|
488
|
-
expect(project1.sub_tasks.to_sql)
|
|
504
|
+
expect(format_sql(project1.sub_tasks.to_sql))
|
|
505
|
+
.to eq(format_sql(option1)).or(eq(format_sql(option2)))
|
|
489
506
|
expect(project1.sub_tasks).to include(subtask1)
|
|
490
507
|
end
|
|
491
508
|
|
|
492
509
|
MultiTenant.without do
|
|
493
|
-
expected_sql = <<-
|
|
494
|
-
|
|
495
|
-
|
|
510
|
+
expected_sql = <<-SQL
|
|
511
|
+
SELECT "sub_tasks".*#{' '}
|
|
512
|
+
FROM "sub_tasks"#{' '}
|
|
513
|
+
INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id"#{' '}
|
|
514
|
+
AND "tasks"."account_id" = "sub_tasks"."account_id"#{' '}
|
|
515
|
+
WHERE "tasks"."project_id" = 1
|
|
516
|
+
SQL
|
|
496
517
|
|
|
497
518
|
project = Project.first
|
|
498
|
-
expect(project.sub_tasks.to_sql).to eq(expected_sql.strip)
|
|
519
|
+
expect(format_sql(project.sub_tasks.to_sql)).to eq(format_sql(expected_sql.strip))
|
|
499
520
|
end
|
|
500
521
|
end
|
|
501
522
|
|
|
502
|
-
it
|
|
503
|
-
option1 = <<-
|
|
504
|
-
SELECT "categories"
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
523
|
+
it 'tests joins between distributed and reference table' do
|
|
524
|
+
option1 = <<-SQL.strip
|
|
525
|
+
SELECT "categories".*#{' '}
|
|
526
|
+
FROM "categories"#{' '}
|
|
527
|
+
INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
528
|
+
WHERE "project_categories"."project_id" = 1 AND "project_categories"."account_id" = 1
|
|
529
|
+
SQL
|
|
530
|
+
option2 = <<-SQL.strip
|
|
531
|
+
SELECT "categories".*#{' '}
|
|
532
|
+
FROM "categories"#{' '}
|
|
533
|
+
INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
534
|
+
WHERE "project_categories"."account_id" = 1 AND "project_categories"."project_id" = 1
|
|
535
|
+
SQL
|
|
509
536
|
|
|
510
537
|
account1 = Account.create! name: 'Account 1'
|
|
511
538
|
category1 = Category.create! name: 'Category 1'
|
|
@@ -514,47 +541,72 @@ describe MultiTenant do
|
|
|
514
541
|
project1 = Project.create! name: 'Project 1'
|
|
515
542
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
516
543
|
|
|
517
|
-
expect(project1.categories.to_sql)
|
|
544
|
+
expect(format_sql(project1.categories.to_sql))
|
|
545
|
+
.to eq(format_sql(option1)).or(eq(format_sql(option2)))
|
|
518
546
|
expect(project1.categories).to include(category1)
|
|
519
547
|
expect(project1.project_categories).to include(projectcategory)
|
|
520
548
|
end
|
|
521
549
|
|
|
522
550
|
MultiTenant.without do
|
|
523
|
-
expected_sql = <<-
|
|
524
|
-
|
|
525
|
-
|
|
551
|
+
expected_sql = <<-SQL
|
|
552
|
+
SELECT "categories".*#{' '}
|
|
553
|
+
FROM "categories"#{' '}
|
|
554
|
+
INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
555
|
+
WHERE "project_categories"."project_id" = 1
|
|
556
|
+
SQL
|
|
526
557
|
|
|
527
558
|
project = Project.first
|
|
528
|
-
expect(project.categories.to_sql)
|
|
559
|
+
expect(format_sql(project.categories.to_sql))
|
|
560
|
+
.to eq(format_sql(expected_sql.strip))
|
|
529
561
|
expect(project.categories).to include(category1)
|
|
530
562
|
|
|
531
|
-
expected_sql = <<-
|
|
532
|
-
|
|
533
|
-
|
|
563
|
+
expected_sql = <<-SQL
|
|
564
|
+
SELECT "projects".* FROM "projects"#{' '}
|
|
565
|
+
INNER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id"#{' '}
|
|
566
|
+
AND "projects"."account_id" = "project_categories"."account_id"#{' '}
|
|
567
|
+
INNER JOIN "categories" ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
568
|
+
WHERE "projects"."account_id" = 1
|
|
569
|
+
SQL
|
|
534
570
|
|
|
535
|
-
expect(Project.where(account_id: 1).joins(:categories).to_sql)
|
|
571
|
+
expect(format_sql(Project.where(account_id: 1).joins(:categories).to_sql))
|
|
572
|
+
.to eq(format_sql(expected_sql.strip))
|
|
536
573
|
project = Project.where(account_id: 1).joins(:categories).first
|
|
537
574
|
expect(project.categories).to include(category1)
|
|
538
575
|
end
|
|
539
576
|
end
|
|
540
577
|
|
|
541
|
-
|
|
542
|
-
it "test eager_load" do
|
|
578
|
+
it 'test eager_load' do
|
|
543
579
|
account1 = Account.create! name: 'Account 1'
|
|
544
580
|
category1 = Category.create! name: 'Category 1'
|
|
545
581
|
|
|
546
|
-
option1 = <<-
|
|
547
|
-
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2,
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
582
|
+
option1 = <<-SQL.strip
|
|
583
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2,
|
|
584
|
+
"categories"."id" AS t1_r0, "categories"."name" AS t1_r1
|
|
585
|
+
FROM "projects"
|
|
586
|
+
LEFT OUTER JOIN "project_categories"
|
|
587
|
+
ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = 1
|
|
588
|
+
AND "projects"."account_id" = 1#{' '}
|
|
589
|
+
LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id"
|
|
590
|
+
AND "project_categories"."account_id" = 1
|
|
591
|
+
WHERE "projects"."account_id" = 1
|
|
592
|
+
SQL
|
|
593
|
+
option2 = <<-SQL.strip
|
|
594
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2,#{' '}
|
|
595
|
+
"categories"."id" AS t1_r0, "categories"."name" AS t1_r1#{' '}
|
|
596
|
+
FROM "projects"#{' '}
|
|
597
|
+
LEFT OUTER JOIN "project_categories"#{' '}
|
|
598
|
+
ON "project_categories"."account_id" = 1#{' '}
|
|
599
|
+
AND "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = 1#{' '}
|
|
600
|
+
LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
601
|
+
AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
|
|
602
|
+
SQL
|
|
552
603
|
|
|
553
604
|
MultiTenant.with(account1) do
|
|
554
605
|
project1 = Project.create! name: 'Project 1'
|
|
555
606
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
556
607
|
|
|
557
|
-
expect(Project.eager_load(:categories).to_sql)
|
|
608
|
+
expect(format_sql(Project.eager_load(:categories).to_sql))
|
|
609
|
+
.to eq(format_sql(option1)).or(eq(format_sql(option2)))
|
|
558
610
|
|
|
559
611
|
project = Project.eager_load(:categories).first
|
|
560
612
|
expect(project.categories).to include(category1)
|
|
@@ -562,92 +614,120 @@ describe MultiTenant do
|
|
|
562
614
|
end
|
|
563
615
|
|
|
564
616
|
MultiTenant.without do
|
|
565
|
-
expected_sql = <<-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
617
|
+
expected_sql = <<-SQL
|
|
618
|
+
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2,#{' '}
|
|
619
|
+
"categories"."id" AS t1_r0, "categories"."name" AS t1_r1#{' '}
|
|
620
|
+
FROM "projects" LEFT OUTER JOIN "project_categories"#{' '}
|
|
621
|
+
ON "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = "project_categories"."account_id"#{' '}
|
|
622
|
+
LEFT OUTER JOIN "categories"#{' '}
|
|
623
|
+
ON "categories"."id" = "project_categories"."category_id"#{' '}
|
|
624
|
+
WHERE "projects"."account_id" = 1
|
|
625
|
+
SQL
|
|
626
|
+
|
|
627
|
+
expect(format_sql(Project.where(account_id: 1).eager_load(:categories).to_sql))
|
|
628
|
+
.to eq(format_sql(expected_sql.strip))
|
|
570
629
|
|
|
571
630
|
project = Project.where(account_id: 1).eager_load(:categories).first
|
|
572
631
|
expect(project.categories).to include(category1)
|
|
573
|
-
|
|
574
632
|
end
|
|
575
633
|
end
|
|
576
634
|
|
|
577
|
-
it
|
|
635
|
+
it 'test raw SQL joins' do
|
|
578
636
|
account1 = Account.create! name: 'Account 1'
|
|
579
637
|
category1 = Category.create! name: 'Category 1'
|
|
580
638
|
|
|
581
639
|
MultiTenant.with(account1) do
|
|
582
|
-
option1 = <<-
|
|
583
|
-
SELECT "tasks".* FROM "tasks"
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
640
|
+
option1 = <<-SQL.strip
|
|
641
|
+
SELECT "tasks".* FROM "tasks"
|
|
642
|
+
INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "projects"."account_id" = 1
|
|
643
|
+
LEFT JOIN project_categories pc ON project.category_id = pc.id#{' '}
|
|
644
|
+
WHERE "tasks"."account_id" = 1
|
|
645
|
+
SQL
|
|
646
|
+
option2 = <<-SQL.strip
|
|
647
|
+
SELECT "tasks".* FROM "tasks"
|
|
648
|
+
INNER JOIN "projects" ON "projects"."account_id" = 1#{' '}
|
|
649
|
+
AND "projects"."id" = "tasks"."project_id"
|
|
650
|
+
LEFT JOIN project_categories pc ON project.category_id = pc.id#{' '}
|
|
651
|
+
WHERE "tasks"."account_id" = 1
|
|
652
|
+
SQL
|
|
588
653
|
|
|
589
654
|
project1 = Project.create! name: 'Project 1'
|
|
590
|
-
|
|
655
|
+
ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
591
656
|
|
|
592
657
|
project1.tasks.create! name: 'baz'
|
|
593
|
-
expect(
|
|
658
|
+
expect(
|
|
659
|
+
format_sql(
|
|
660
|
+
Task.joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql
|
|
661
|
+
)
|
|
662
|
+
).to eq(format_sql(option1)).or(eq(format_sql(option2)))
|
|
594
663
|
end
|
|
595
664
|
|
|
596
665
|
MultiTenant.without do
|
|
597
|
-
expected_sql = <<-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
666
|
+
expected_sql = <<-SQL.strip
|
|
667
|
+
SELECT "tasks".* FROM "tasks"
|
|
668
|
+
INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id"
|
|
669
|
+
AND "tasks"."account_id" = "projects"."account_id"
|
|
670
|
+
LEFT JOIN project_categories pc ON project.category_id = pc.id
|
|
671
|
+
WHERE "tasks"."account_id" = 1
|
|
672
|
+
SQL
|
|
673
|
+
|
|
674
|
+
expect(format_sql(Task.where(account_id: 1).joins(:project)
|
|
675
|
+
.joins('LEFT JOIN project_categories pc ON project.category_id = pc.id')
|
|
676
|
+
.to_sql)).to eq(format_sql(expected_sql.strip))
|
|
603
677
|
end
|
|
604
|
-
|
|
605
678
|
end
|
|
606
679
|
|
|
607
|
-
it
|
|
680
|
+
it 'only applies clauses when a tenant is set' do
|
|
608
681
|
account = Account.create! name: 'Account 1'
|
|
609
682
|
project = Project.create! name: 'Project 1', account: account
|
|
610
683
|
project2 = Project.create! name: 'Project 2', account: Account.create!(name: 'Account2')
|
|
611
684
|
|
|
612
685
|
MultiTenant.with(account) do
|
|
613
|
-
option1 = <<-
|
|
614
|
-
SELECT "projects".* FROM "projects"
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
686
|
+
option1 = <<-SQL.strip
|
|
687
|
+
SELECT "projects".* FROM "projects"#{' '}
|
|
688
|
+
WHERE "projects"."account_id" = #{account.id} AND "projects"."id" = $1 LIMIT $2
|
|
689
|
+
SQL
|
|
690
|
+
option2 = <<-SQL.strip
|
|
691
|
+
SELECT "projects".* FROM "projects"#{' '}
|
|
692
|
+
WHERE "projects"."id" = $1 AND "projects"."account_id" = #{account.id} LIMIT $2
|
|
693
|
+
SQL
|
|
694
|
+
option3 = <<-SQL.strip
|
|
695
|
+
SELECT "projects".* FROM "projects"
|
|
696
|
+
WHERE "projects"."id" = $1
|
|
697
|
+
AND "projects"."account_id" = #{account.id} LIMIT $2
|
|
698
|
+
SQL
|
|
622
699
|
|
|
623
700
|
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
|
624
|
-
# expect(Project).to receive(:find_by_sql).with(eq(option1).
|
|
701
|
+
# expect(Project).to receive(:find_by_sql).with(eq(option1).
|
|
702
|
+
# or(eq(option2)).or(eq(option3)), any_args).and_call_original
|
|
625
703
|
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
|
626
|
-
expect(args[0]).to(eq(option1)
|
|
627
|
-
|
|
704
|
+
expect(format_sql(args[0])).to(eq(format_sql(option1))
|
|
705
|
+
.or(eq(format_sql(option2))).or(eq(format_sql(option3))))
|
|
706
|
+
m.call(args[0], args[1], preparable: args[2][:preparable])
|
|
628
707
|
end
|
|
629
708
|
expect(Project.find(project.id)).to eq(project)
|
|
630
709
|
end
|
|
631
710
|
|
|
632
711
|
MultiTenant.without do
|
|
633
|
-
option1 = <<-
|
|
634
|
-
SELECT "projects".* FROM "projects"
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
712
|
+
option1 = <<-SQL.strip
|
|
713
|
+
SELECT "projects".* FROM "projects"#{' '}
|
|
714
|
+
WHERE "projects"."id" = $1 LIMIT $2
|
|
715
|
+
SQL
|
|
716
|
+
option2 = <<-SQL.strip
|
|
717
|
+
SELECT "projects".* FROM "projects"#{' '}
|
|
718
|
+
WHERE "projects"."id" = $1 LIMIT $2
|
|
719
|
+
SQL
|
|
639
720
|
|
|
640
721
|
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
|
641
722
|
# expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)), any_args).and_call_original
|
|
642
723
|
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
|
643
|
-
expect(args[0]).to(eq(option1).or(eq(option2)))
|
|
644
|
-
m.call(args[0], args[1], preparable:args[2][:preparable])
|
|
724
|
+
expect(format_sql(args[0])).to(eq(format_sql(option1)).or(eq(format_sql(option2))))
|
|
725
|
+
m.call(args[0], args[1], preparable: args[2][:preparable])
|
|
645
726
|
end
|
|
646
727
|
expect(Project.find(project2.id)).to eq(project2)
|
|
647
728
|
end
|
|
648
729
|
end
|
|
649
730
|
|
|
650
|
-
|
|
651
731
|
describe 'with unsaved association' do
|
|
652
732
|
before do
|
|
653
733
|
@account = Account.create!(name: 'reflection tenant')
|
|
@@ -661,13 +741,13 @@ describe MultiTenant do
|
|
|
661
741
|
end
|
|
662
742
|
end
|
|
663
743
|
|
|
664
|
-
it
|
|
744
|
+
it 'test value of RETURNING insert in table with no pkey' do
|
|
665
745
|
account1 = Account.create(name: 'test1')
|
|
666
746
|
|
|
667
747
|
MultiTenant.with(account1) do
|
|
668
|
-
|
|
748
|
+
AllowedPlace.create! name: 'something1'
|
|
669
749
|
|
|
670
|
-
|
|
750
|
+
Project.create! name: 'Project 1'
|
|
671
751
|
end
|
|
672
752
|
end
|
|
673
753
|
end
|