activerecord-multi-tenant 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|