activerecord-multi-tenant 2.1.6 → 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 -24
- data/CHANGELOG.md +12 -0
- data/Gemfile +3 -1
- data/LICENSE +0 -0
- data/README.md +3 -2
- 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 +19 -9
- data/lib/activerecord-multi-tenant/model_extensions.rb +82 -40
- data/lib/activerecord-multi-tenant/multi_tenant.rb +42 -23
- 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 +243 -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 +132 -29
- data/.github/workflows/CI.yml +0 -63
- data/gemfiles/.bundle/config +0 -2
- data/gemfiles/active_record_5.2.gemfile +0 -16
- 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_5.2.gemfile +0 -16
- 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
|
|
@@ -209,6 +218,16 @@ describe MultiTenant do
|
|
|
209
218
|
expect(record.account_id).to eq(nil)
|
|
210
219
|
end
|
|
211
220
|
|
|
221
|
+
it 'handles changing tenant from nil to a value' do
|
|
222
|
+
record = OptionalSubTask.create(sub_task_id: sub_task.id)
|
|
223
|
+
expect(record.reload.sub_task).to eq(sub_task)
|
|
224
|
+
expect(record.account_id).to eq(nil)
|
|
225
|
+
|
|
226
|
+
record.account = account
|
|
227
|
+
record.save!
|
|
228
|
+
expect(record.reload.account_id).to eq(account.id)
|
|
229
|
+
end
|
|
230
|
+
|
|
212
231
|
it 'handles has_many through' do
|
|
213
232
|
MultiTenant.with(account) do
|
|
214
233
|
expect(project.sub_tasks).to eq [sub_task]
|
|
@@ -227,7 +246,7 @@ describe MultiTenant do
|
|
|
227
246
|
MultiTenant.with(account) do
|
|
228
247
|
sub_task
|
|
229
248
|
manager
|
|
230
|
-
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
|
|
231
250
|
end
|
|
232
251
|
end
|
|
233
252
|
end
|
|
@@ -238,7 +257,8 @@ describe MultiTenant do
|
|
|
238
257
|
|
|
239
258
|
it 'rewrites sub-selects correctly' do
|
|
240
259
|
MultiTenant.with(account) do
|
|
241
|
-
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
|
|
242
262
|
end
|
|
243
263
|
end
|
|
244
264
|
end
|
|
@@ -267,34 +287,34 @@ describe MultiTenant do
|
|
|
267
287
|
end
|
|
268
288
|
|
|
269
289
|
describe 'non-STI Subclass of abstract Multi Tenant Model' do
|
|
270
|
-
let(:
|
|
271
|
-
let(:
|
|
290
|
+
let(:tenant_id1) { 42 }
|
|
291
|
+
let(:tenant_id2) { 314_158 }
|
|
272
292
|
let(:name) { 'fooname' }
|
|
273
|
-
let(:
|
|
274
|
-
MultiTenant.with(
|
|
293
|
+
let(:subclass_task1) do
|
|
294
|
+
MultiTenant.with(tenant_id1) { SubclassTask.create! name: name }
|
|
275
295
|
end
|
|
276
|
-
let(:
|
|
277
|
-
MultiTenant.with(
|
|
296
|
+
let(:subclass_task2) do
|
|
297
|
+
MultiTenant.with(tenant_id2) { SubclassTask.create! name: name }
|
|
278
298
|
end
|
|
279
299
|
|
|
280
300
|
before do
|
|
281
|
-
|
|
282
|
-
|
|
301
|
+
subclass_task1
|
|
302
|
+
subclass_task2
|
|
283
303
|
end
|
|
284
304
|
|
|
285
305
|
it 'injects tenant_id on create' do
|
|
286
|
-
expect(
|
|
287
|
-
expect(
|
|
306
|
+
expect(subclass_task1.non_model_id).to be tenant_id1
|
|
307
|
+
expect(subclass_task2.non_model_id).to be tenant_id2
|
|
288
308
|
end
|
|
289
309
|
|
|
290
310
|
it 'rewrites query' do
|
|
291
|
-
MultiTenant.with(
|
|
311
|
+
MultiTenant.with(tenant_id1) do
|
|
292
312
|
expect(SubclassTask.where(name: name).count).to eq 1
|
|
293
|
-
expect(SubclassTask.where(name: name).first).to eq
|
|
313
|
+
expect(SubclassTask.where(name: name).first).to eq subclass_task1
|
|
294
314
|
end
|
|
295
|
-
MultiTenant.with(
|
|
315
|
+
MultiTenant.with(tenant_id2) do
|
|
296
316
|
expect(SubclassTask.where(name: name).count).to eq 1
|
|
297
|
-
expect(SubclassTask.where(name: name).first).to eq
|
|
317
|
+
expect(SubclassTask.where(name: name).first).to eq subclass_task2
|
|
298
318
|
end
|
|
299
319
|
end
|
|
300
320
|
end
|
|
@@ -306,20 +326,27 @@ describe MultiTenant do
|
|
|
306
326
|
|
|
307
327
|
it 'should add tenant condition to the queries when tenant is set' do
|
|
308
328
|
expected_join_sql = <<-SQL.strip
|
|
309
|
-
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
|
|
310
334
|
SQL
|
|
311
335
|
|
|
312
336
|
MultiTenant.with(account) do
|
|
313
|
-
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))
|
|
314
338
|
end
|
|
315
339
|
end
|
|
316
340
|
|
|
317
341
|
it 'should add tenant condition to the queries when tenant is not set' do
|
|
318
342
|
MultiTenant.without do
|
|
319
343
|
expected_join_sql = <<-SQL.strip
|
|
320
|
-
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"
|
|
321
348
|
SQL
|
|
322
|
-
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))
|
|
323
350
|
end
|
|
324
351
|
end
|
|
325
352
|
end
|
|
@@ -329,57 +356,63 @@ describe MultiTenant do
|
|
|
329
356
|
|
|
330
357
|
it 'should add tenant condition to the queries when tenant is set' do
|
|
331
358
|
expected_join_sql = <<-SQL.strip
|
|
332
|
-
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
|
|
333
364
|
SQL
|
|
334
365
|
|
|
335
366
|
MultiTenant.with(account) do
|
|
336
|
-
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))
|
|
337
368
|
end
|
|
338
369
|
end
|
|
339
370
|
|
|
340
371
|
it 'should add tenant condition to the queries when tenant is not set' do
|
|
341
372
|
MultiTenant.without do
|
|
342
373
|
expected_join_sql = <<-SQL.strip
|
|
343
|
-
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"
|
|
344
378
|
SQL
|
|
345
|
-
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))
|
|
346
380
|
end
|
|
347
381
|
end
|
|
348
382
|
end
|
|
349
383
|
end
|
|
350
384
|
|
|
351
385
|
# ::with
|
|
352
|
-
describe
|
|
353
|
-
it
|
|
354
|
-
@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')
|
|
355
389
|
|
|
356
390
|
MultiTenant.with(@account) do
|
|
357
391
|
expect(MultiTenant.current_tenant).to eq(@account)
|
|
358
392
|
end
|
|
359
393
|
end
|
|
360
394
|
|
|
361
|
-
it
|
|
362
|
-
@account1 = Account.create!(:
|
|
363
|
-
@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')
|
|
364
398
|
|
|
365
399
|
MultiTenant.current_tenant = @account1
|
|
366
400
|
MultiTenant.with @account2 do
|
|
367
|
-
|
|
368
401
|
end
|
|
369
402
|
|
|
370
403
|
expect(MultiTenant.current_tenant).to eq(@account1)
|
|
371
404
|
end
|
|
372
405
|
|
|
373
|
-
it
|
|
374
|
-
@account1 = Account.create!(:
|
|
375
|
-
@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')
|
|
376
409
|
|
|
377
410
|
MultiTenant.current_tenant = @account1
|
|
378
411
|
value = MultiTenant.with @account2 do
|
|
379
|
-
|
|
412
|
+
'something'
|
|
380
413
|
end
|
|
381
414
|
|
|
382
|
-
expect(value).to eq
|
|
415
|
+
expect(value).to eq 'something'
|
|
383
416
|
end
|
|
384
417
|
|
|
385
418
|
it 'supports reload inside the block' do
|
|
@@ -394,9 +427,9 @@ describe MultiTenant do
|
|
|
394
427
|
end
|
|
395
428
|
|
|
396
429
|
# ::without
|
|
397
|
-
describe
|
|
398
|
-
it
|
|
399
|
-
@account = Account.create!(:
|
|
430
|
+
describe '::without' do
|
|
431
|
+
it 'should unset current_tenant inside the block' do
|
|
432
|
+
@account = Account.create!(name: 'baz')
|
|
400
433
|
|
|
401
434
|
MultiTenant.current_tenant = @account
|
|
402
435
|
MultiTenant.without do
|
|
@@ -404,39 +437,25 @@ describe MultiTenant do
|
|
|
404
437
|
end
|
|
405
438
|
end
|
|
406
439
|
|
|
407
|
-
it
|
|
408
|
-
@account1 = Account.create!(:
|
|
440
|
+
it 'should reset current_tenant to the previous tenant once exiting the block' do
|
|
441
|
+
@account1 = Account.create!(name: 'foo')
|
|
409
442
|
|
|
410
443
|
MultiTenant.current_tenant = @account1
|
|
411
444
|
MultiTenant.without do
|
|
412
|
-
|
|
413
445
|
end
|
|
414
446
|
|
|
415
447
|
expect(MultiTenant.current_tenant).to eq(@account1)
|
|
416
448
|
end
|
|
417
449
|
|
|
418
|
-
it
|
|
419
|
-
@account1 = Account.create!(:
|
|
450
|
+
it 'should return the value of the block' do
|
|
451
|
+
@account1 = Account.create!(name: 'foo')
|
|
420
452
|
|
|
421
453
|
MultiTenant.current_tenant = @account1
|
|
422
454
|
value = MultiTenant.without do
|
|
423
|
-
|
|
455
|
+
'something'
|
|
424
456
|
end
|
|
425
457
|
|
|
426
|
-
expect(value).to eq
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
describe '.with_lock' do
|
|
431
|
-
it 'supports with_lock blocks inside the block' do
|
|
432
|
-
@account = Account.create!(name: 'foo')
|
|
433
|
-
|
|
434
|
-
MultiTenant.with @account do
|
|
435
|
-
project = @account.projects.create!(name: 'project')
|
|
436
|
-
project.with_lock do
|
|
437
|
-
expect(project.name).to eq 'project'
|
|
438
|
-
end
|
|
439
|
-
end
|
|
458
|
+
expect(value).to eq 'something'
|
|
440
459
|
end
|
|
441
460
|
end
|
|
442
461
|
|
|
@@ -461,13 +480,20 @@ describe MultiTenant do
|
|
|
461
480
|
end
|
|
462
481
|
end
|
|
463
482
|
|
|
464
|
-
it
|
|
465
|
-
option1 = <<-
|
|
466
|
-
SELECT "sub_tasks"
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
|
471
497
|
|
|
472
498
|
account1 = Account.create! name: 'Account 1'
|
|
473
499
|
|
|
@@ -475,27 +501,38 @@ describe MultiTenant do
|
|
|
475
501
|
project1 = Project.create! name: 'Project 1'
|
|
476
502
|
task1 = Task.create! name: 'Task 1', project: project1
|
|
477
503
|
subtask1 = SubTask.create! task: task1
|
|
478
|
-
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)))
|
|
479
506
|
expect(project1.sub_tasks).to include(subtask1)
|
|
480
507
|
end
|
|
481
508
|
|
|
482
509
|
MultiTenant.without do
|
|
483
|
-
expected_sql = <<-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
|
486
517
|
|
|
487
518
|
project = Project.first
|
|
488
|
-
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))
|
|
489
520
|
end
|
|
490
521
|
end
|
|
491
522
|
|
|
492
|
-
it
|
|
493
|
-
option1 = <<-
|
|
494
|
-
SELECT "categories"
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
|
499
536
|
|
|
500
537
|
account1 = Account.create! name: 'Account 1'
|
|
501
538
|
category1 = Category.create! name: 'Category 1'
|
|
@@ -504,47 +541,72 @@ describe MultiTenant do
|
|
|
504
541
|
project1 = Project.create! name: 'Project 1'
|
|
505
542
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
506
543
|
|
|
507
|
-
expect(project1.categories.to_sql)
|
|
544
|
+
expect(format_sql(project1.categories.to_sql))
|
|
545
|
+
.to eq(format_sql(option1)).or(eq(format_sql(option2)))
|
|
508
546
|
expect(project1.categories).to include(category1)
|
|
509
547
|
expect(project1.project_categories).to include(projectcategory)
|
|
510
548
|
end
|
|
511
549
|
|
|
512
550
|
MultiTenant.without do
|
|
513
|
-
expected_sql = <<-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
516
557
|
|
|
517
558
|
project = Project.first
|
|
518
|
-
expect(project.categories.to_sql)
|
|
559
|
+
expect(format_sql(project.categories.to_sql))
|
|
560
|
+
.to eq(format_sql(expected_sql.strip))
|
|
519
561
|
expect(project.categories).to include(category1)
|
|
520
562
|
|
|
521
|
-
expected_sql = <<-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
|
524
570
|
|
|
525
|
-
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))
|
|
526
573
|
project = Project.where(account_id: 1).joins(:categories).first
|
|
527
574
|
expect(project.categories).to include(category1)
|
|
528
575
|
end
|
|
529
576
|
end
|
|
530
577
|
|
|
531
|
-
|
|
532
|
-
it "test eager_load" do
|
|
578
|
+
it 'test eager_load' do
|
|
533
579
|
account1 = Account.create! name: 'Account 1'
|
|
534
580
|
category1 = Category.create! name: 'Category 1'
|
|
535
581
|
|
|
536
|
-
option1 = <<-
|
|
537
|
-
SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2,
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
|
542
603
|
|
|
543
604
|
MultiTenant.with(account1) do
|
|
544
605
|
project1 = Project.create! name: 'Project 1'
|
|
545
606
|
projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
546
607
|
|
|
547
|
-
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)))
|
|
548
610
|
|
|
549
611
|
project = Project.eager_load(:categories).first
|
|
550
612
|
expect(project.categories).to include(category1)
|
|
@@ -552,92 +614,120 @@ describe MultiTenant do
|
|
|
552
614
|
end
|
|
553
615
|
|
|
554
616
|
MultiTenant.without do
|
|
555
|
-
expected_sql = <<-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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))
|
|
560
629
|
|
|
561
630
|
project = Project.where(account_id: 1).eager_load(:categories).first
|
|
562
631
|
expect(project.categories).to include(category1)
|
|
563
|
-
|
|
564
632
|
end
|
|
565
633
|
end
|
|
566
634
|
|
|
567
|
-
it
|
|
635
|
+
it 'test raw SQL joins' do
|
|
568
636
|
account1 = Account.create! name: 'Account 1'
|
|
569
637
|
category1 = Category.create! name: 'Category 1'
|
|
570
638
|
|
|
571
639
|
MultiTenant.with(account1) do
|
|
572
|
-
option1 = <<-
|
|
573
|
-
SELECT "tasks".* FROM "tasks"
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
|
578
653
|
|
|
579
654
|
project1 = Project.create! name: 'Project 1'
|
|
580
|
-
|
|
655
|
+
ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
|
|
581
656
|
|
|
582
657
|
project1.tasks.create! name: 'baz'
|
|
583
|
-
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)))
|
|
584
663
|
end
|
|
585
664
|
|
|
586
665
|
MultiTenant.without do
|
|
587
|
-
expected_sql = <<-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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))
|
|
593
677
|
end
|
|
594
|
-
|
|
595
678
|
end
|
|
596
679
|
|
|
597
|
-
it
|
|
680
|
+
it 'only applies clauses when a tenant is set' do
|
|
598
681
|
account = Account.create! name: 'Account 1'
|
|
599
682
|
project = Project.create! name: 'Project 1', account: account
|
|
600
683
|
project2 = Project.create! name: 'Project 2', account: Account.create!(name: 'Account2')
|
|
601
684
|
|
|
602
685
|
MultiTenant.with(account) do
|
|
603
|
-
option1 = <<-
|
|
604
|
-
SELECT "projects".* FROM "projects"
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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
|
|
612
699
|
|
|
613
700
|
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
|
614
|
-
# 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
|
|
615
703
|
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
|
616
|
-
expect(args[0]).to(eq(option1)
|
|
617
|
-
|
|
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])
|
|
618
707
|
end
|
|
619
708
|
expect(Project.find(project.id)).to eq(project)
|
|
620
709
|
end
|
|
621
710
|
|
|
622
711
|
MultiTenant.without do
|
|
623
|
-
option1 = <<-
|
|
624
|
-
SELECT "projects".* FROM "projects"
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
|
629
720
|
|
|
630
721
|
# Couldn't make the following line pass for some reason, so came up with an uglier alternative
|
|
631
722
|
# expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)), any_args).and_call_original
|
|
632
723
|
expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
|
|
633
|
-
expect(args[0]).to(eq(option1).or(eq(option2)))
|
|
634
|
-
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])
|
|
635
726
|
end
|
|
636
727
|
expect(Project.find(project2.id)).to eq(project2)
|
|
637
728
|
end
|
|
638
729
|
end
|
|
639
730
|
|
|
640
|
-
|
|
641
731
|
describe 'with unsaved association' do
|
|
642
732
|
before do
|
|
643
733
|
@account = Account.create!(name: 'reflection tenant')
|
|
@@ -651,13 +741,13 @@ describe MultiTenant do
|
|
|
651
741
|
end
|
|
652
742
|
end
|
|
653
743
|
|
|
654
|
-
it
|
|
744
|
+
it 'test value of RETURNING insert in table with no pkey' do
|
|
655
745
|
account1 = Account.create(name: 'test1')
|
|
656
746
|
|
|
657
747
|
MultiTenant.with(account1) do
|
|
658
|
-
|
|
748
|
+
AllowedPlace.create! name: 'something1'
|
|
659
749
|
|
|
660
|
-
|
|
750
|
+
Project.create! name: 'Project 1'
|
|
661
751
|
end
|
|
662
752
|
end
|
|
663
753
|
end
|