activerecord-multi-tenant 2.0.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/active-record-multi-tenant-tests.yml +83 -0
  3. data/.gitignore +6 -0
  4. data/.readthedocs.yaml +15 -0
  5. data/.rspec +0 -0
  6. data/.rubocop.yml +51 -0
  7. data/Appraisals +6 -22
  8. data/CHANGELOG.md +42 -0
  9. data/Gemfile +3 -1
  10. data/LICENSE +0 -0
  11. data/README.md +3 -2
  12. data/Rakefile +1 -1
  13. data/activerecord-multi-tenant.gemspec +28 -22
  14. data/docker-compose.yml +24 -18
  15. data/docs/.gitignore +3 -0
  16. data/docs/Makefile +28 -0
  17. data/docs/api-reference.sh +10 -0
  18. data/docs/requirements.in +4 -0
  19. data/docs/requirements.txt +62 -0
  20. data/docs/source/_static/api-reference/ActiveRecord/Associations/Association.html +285 -0
  21. data/docs/source/_static/api-reference/ActiveRecord/Associations/ClassMethods.html +255 -0
  22. data/docs/source/_static/api-reference/ActiveRecord/Associations.html +117 -0
  23. data/docs/source/_static/api-reference/ActiveRecord/ConnectionAdapters/SchemaStatements.html +232 -0
  24. data/docs/source/_static/api-reference/ActiveRecord/ConnectionAdapters.html +126 -0
  25. data/docs/source/_static/api-reference/ActiveRecord/QueryMethods.html +336 -0
  26. data/docs/source/_static/api-reference/ActiveRecord/SchemaDumper.html +121 -0
  27. data/docs/source/_static/api-reference/ActiveRecord.html +130 -0
  28. data/docs/source/_static/api-reference/MultiTenant/ArelTenantVisitor.html +755 -0
  29. data/docs/source/_static/api-reference/MultiTenant/ArelVisitorsDepthFirst.html +208 -0
  30. data/docs/source/_static/api-reference/MultiTenant/BaseTenantEnforcementClause.html +462 -0
  31. data/docs/source/_static/api-reference/MultiTenant/Context.html +659 -0
  32. data/docs/source/_static/api-reference/MultiTenant/ControllerExtensions.html +202 -0
  33. data/docs/source/_static/api-reference/MultiTenant/CopyFromClient.html +186 -0
  34. data/docs/source/_static/api-reference/MultiTenant/CopyFromClientHelper.html +362 -0
  35. data/docs/source/_static/api-reference/MultiTenant/Current.html +124 -0
  36. data/docs/source/_static/api-reference/MultiTenant/DatabaseStatements.html +366 -0
  37. data/docs/source/_static/api-reference/MultiTenant/FastTruncate.html +226 -0
  38. data/docs/source/_static/api-reference/MultiTenant/MigrationExtensions.html +554 -0
  39. data/docs/source/_static/api-reference/MultiTenant/MissingTenantError.html +124 -0
  40. data/docs/source/_static/api-reference/MultiTenant/ModelExtensionsClassMethods.html +492 -0
  41. data/docs/source/_static/api-reference/MultiTenant/QueryMonitor.html +257 -0
  42. data/docs/source/_static/api-reference/MultiTenant/Table.html +419 -0
  43. data/docs/source/_static/api-reference/MultiTenant/TenantEnforcementClause.html +148 -0
  44. data/docs/source/_static/api-reference/MultiTenant/TenantIsImmutable.html +135 -0
  45. data/docs/source/_static/api-reference/MultiTenant/TenantJoinEnforcementClause.html +310 -0
  46. data/docs/source/_static/api-reference/MultiTenant/TenantValueVisitor.html +239 -0
  47. data/docs/source/_static/api-reference/MultiTenant.html +1454 -0
  48. data/docs/source/_static/api-reference/MultiTenantFindBy.html +180 -0
  49. data/docs/source/_static/api-reference/Sidekiq/Client.html +302 -0
  50. data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant/Client.html +217 -0
  51. data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant/Server.html +219 -0
  52. data/docs/source/_static/api-reference/Sidekiq/Middleware/MultiTenant.html +126 -0
  53. data/docs/source/_static/api-reference/Sidekiq.html +126 -0
  54. data/docs/source/_static/api-reference/_index.html +399 -0
  55. data/docs/source/_static/api-reference/class_list.html +51 -0
  56. data/docs/source/_static/api-reference/css/common.css +1 -0
  57. data/docs/source/_static/api-reference/css/full_list.css +58 -0
  58. data/docs/source/_static/api-reference/css/style.css +497 -0
  59. data/docs/source/_static/api-reference/file.README.html +167 -0
  60. data/docs/source/_static/api-reference/file_list.html +56 -0
  61. data/docs/source/_static/api-reference/frames.html +17 -0
  62. data/docs/source/_static/api-reference/index.html +167 -0
  63. data/docs/source/_static/api-reference/js/app.js +314 -0
  64. data/docs/source/_static/api-reference/js/full_list.js +216 -0
  65. data/docs/source/_static/api-reference/js/jquery.js +4 -0
  66. data/docs/source/_static/api-reference/method_list.html +715 -0
  67. data/docs/source/_static/api-reference/top-level-namespace.html +126 -0
  68. data/docs/source/_templates/.gitignore +4 -0
  69. data/docs/source/api-reference.rst +8 -0
  70. data/docs/source/appendix.rst +26 -0
  71. data/docs/source/changelog.rst +8 -0
  72. data/docs/source/community-and-support.rst +26 -0
  73. data/docs/source/conf.py +30 -0
  74. data/docs/source/contributing.rst +70 -0
  75. data/docs/source/getting-started.rst +37 -0
  76. data/docs/source/guides-and-tutorials.rst +129 -0
  77. data/docs/source/index.rst +54 -0
  78. data/docs/source/introduction.rst +33 -0
  79. data/docs/source/license.rst +22 -0
  80. data/docs/source/troubleshooting.rst +41 -0
  81. data/docs/source/usage-guide.rst +59 -0
  82. data/lib/activerecord-multi-tenant/arel_visitors_depth_first.rb +183 -174
  83. data/lib/activerecord-multi-tenant/controller_extensions.rb +15 -4
  84. data/lib/activerecord-multi-tenant/copy_from_client.rb +4 -0
  85. data/lib/activerecord-multi-tenant/fast_truncate.rb +4 -2
  86. data/lib/activerecord-multi-tenant/habtm.rb +50 -0
  87. data/lib/activerecord-multi-tenant/migrations.rb +87 -10
  88. data/lib/activerecord-multi-tenant/model_extensions.rb +96 -38
  89. data/lib/activerecord-multi-tenant/multi_tenant.rb +83 -24
  90. data/lib/activerecord-multi-tenant/query_monitor.rb +21 -5
  91. data/lib/activerecord-multi-tenant/query_rewriter.rb +121 -87
  92. data/lib/activerecord-multi-tenant/sidekiq.rb +46 -19
  93. data/lib/activerecord-multi-tenant/table_node.rb +13 -0
  94. data/lib/activerecord-multi-tenant/version.rb +1 -1
  95. data/lib/activerecord-multi-tenant.rb +3 -13
  96. data/lib/activerecord_multi_tenant.rb +13 -0
  97. data/spec/activerecord-multi-tenant/associations_spec.rb +42 -0
  98. data/spec/activerecord-multi-tenant/controller_extensions_spec.rb +3 -2
  99. data/spec/activerecord-multi-tenant/fast_truncate_spec.rb +8 -6
  100. data/spec/activerecord-multi-tenant/model_extensions_spec.rb +300 -147
  101. data/spec/activerecord-multi-tenant/multi_tenant_spec.rb +69 -13
  102. data/spec/activerecord-multi-tenant/query_rewriter_spec.rb +60 -59
  103. data/spec/activerecord-multi-tenant/record_callback_spec.rb +0 -0
  104. data/spec/activerecord-multi-tenant/record_finding_spec.rb +11 -11
  105. data/spec/activerecord-multi-tenant/record_modifications_spec.rb +23 -4
  106. data/spec/activerecord-multi-tenant/sidekiq_spec.rb +10 -10
  107. data/spec/database.yml +0 -0
  108. data/spec/schema.rb +20 -3
  109. data/spec/spec_helper.rb +46 -17
  110. data/spec/support/format_sql.rb +20 -0
  111. metadata +134 -32
  112. data/.github/workflows/CI.yml +0 -73
  113. data/gemfiles/.bundle/config +0 -2
  114. data/gemfiles/active_record_5.2.3.gemfile +0 -16
  115. data/gemfiles/active_record_5.2.gemfile +0 -16
  116. data/gemfiles/active_record_6.0.gemfile +0 -8
  117. data/gemfiles/active_record_6.1.gemfile +0 -8
  118. data/gemfiles/active_record_7.0.gemfile +0 -8
  119. data/gemfiles/rails_5.2.3.gemfile +0 -16
  120. data/gemfiles/rails_5.2.gemfile +0 -16
  121. data/gemfiles/rails_6.0.gemfile +0 -8
  122. data/gemfiles/rails_6.1.gemfile +0 -8
  123. data/gemfiles/rails_7.0.gemfile +0 -8
  124. data/lib/activerecord-multi-tenant/persistence_extension.rb +0 -13
  125. data/lib/activerecord-multi-tenant/with_lock.rb +0 -15
  126. 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 = Account.create! name: 'foo'
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,6 +72,24 @@ describe MultiTenant do
70
72
  it { expect(@partition_key_not_model_task.non_model_id).to be 77 }
71
73
  end
72
74
 
75
+ describe 'Tenant model with a nonstandard class name' do
76
+ let(:account_klass) do
77
+ Class.new(ActiveRecord::Base) do
78
+ self.table_name = 'account'
79
+
80
+ def self.name
81
+ 'UserAccount'
82
+ end
83
+
84
+ multi_tenant(:account)
85
+ end
86
+ end
87
+ it 'does not register the tenant model' do
88
+ expect(MultiTenant).not_to receive(:register_multi_tenant_model)
89
+ account_klass
90
+ end
91
+ end
92
+
73
93
  describe 'Changes table_name after multi_tenant called' do
74
94
  before do
75
95
  account_klass.has_many(:posts, anonymous_class: post_klass)
@@ -111,6 +131,13 @@ describe MultiTenant do
111
131
  it { expect(@posts).to eq([@post1]) }
112
132
  end
113
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
+
114
141
  # Scoping models
115
142
  describe 'Project.all should be scoped to the current tenant if set' do
116
143
  before do
@@ -153,16 +180,16 @@ describe MultiTenant do
153
180
  end
154
181
  end
155
182
 
156
- describe "It should be possible to use aliased associations" do
183
+ describe 'It should be possible to use aliased associations' do
157
184
  before do
158
185
  @account = Account.create! name: 'baz'
159
186
  MultiTenant.current_tenant = @account
160
187
  end
161
188
 
162
- it { expect(AliasedTask.create(:name => 'foo', :project_alias => @project2).valid?).to eq(true) }
189
+ it { expect(AliasedTask.create(name: 'foo', project_alias: @project2).valid?).to eq(true) }
163
190
  end
164
191
 
165
- describe "It should be possible to use associations with partition_key from polymorphic" do
192
+ describe 'It should be possible to use associations with partition_key from polymorphic' do
166
193
  before do
167
194
  @account = Account.create!(name: 'foo')
168
195
  MultiTenant.current_tenant = @account
@@ -186,13 +213,19 @@ describe MultiTenant do
186
213
  end
187
214
 
188
215
  it 'handles belongs_to with optional: true' do
189
- MultiTenant.with(account) do
190
- sub_task
191
- end
216
+ record = OptionalSubTask.create(sub_task_id: sub_task.id)
217
+ expect(record.reload.sub_task).to eq(sub_task)
218
+ expect(record.account_id).to eq(nil)
219
+ end
192
220
 
193
- record = sub_task.optional_sub_tasks.create!
221
+ it 'handles changing tenant from nil to a value' do
222
+ record = OptionalSubTask.create(sub_task_id: sub_task.id)
194
223
  expect(record.reload.sub_task).to eq(sub_task)
195
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)
196
229
  end
197
230
 
198
231
  it 'handles has_many through' do
@@ -213,7 +246,7 @@ describe MultiTenant do
213
246
  MultiTenant.with(account) do
214
247
  sub_task
215
248
  manager
216
- 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
217
250
  end
218
251
  end
219
252
  end
@@ -224,7 +257,8 @@ describe MultiTenant do
224
257
 
225
258
  it 'rewrites sub-selects correctly' do
226
259
  MultiTenant.with(account) do
227
- expect(Project.where(id: Project.where(id: project.id)).where(id: Project.where(id: project.id)).first).to eq project
260
+ expect(Project.where(id: Project.where(id: project.id))
261
+ .where(id: Project.where(id: project.id)).first).to eq project
228
262
  end
229
263
  end
230
264
  end
@@ -253,70 +287,132 @@ describe MultiTenant do
253
287
  end
254
288
 
255
289
  describe 'non-STI Subclass of abstract Multi Tenant Model' do
256
- let(:tenant_id_1) { 42 }
257
- let(:tenant_id_2) { 314158 }
290
+ let(:tenant_id1) { 42 }
291
+ let(:tenant_id2) { 314_158 }
258
292
  let(:name) { 'fooname' }
259
- let(:subclass_task_1) do
260
- MultiTenant.with(tenant_id_1) { SubclassTask.create! name: name }
293
+ let(:subclass_task1) do
294
+ MultiTenant.with(tenant_id1) { SubclassTask.create! name: name }
261
295
  end
262
- let(:subclass_task_2) do
263
- MultiTenant.with(tenant_id_2) { SubclassTask.create! name: name }
296
+ let(:subclass_task2) do
297
+ MultiTenant.with(tenant_id2) { SubclassTask.create! name: name }
264
298
  end
265
299
 
266
300
  before do
267
- subclass_task_1
268
- subclass_task_2
301
+ subclass_task1
302
+ subclass_task2
269
303
  end
270
304
 
271
305
  it 'injects tenant_id on create' do
272
- expect(subclass_task_1.non_model_id).to be tenant_id_1
273
- expect(subclass_task_2.non_model_id).to be tenant_id_2
306
+ expect(subclass_task1.non_model_id).to be tenant_id1
307
+ expect(subclass_task2.non_model_id).to be tenant_id2
274
308
  end
275
309
 
276
310
  it 'rewrites query' do
277
- MultiTenant.with(tenant_id_1) do
311
+ MultiTenant.with(tenant_id1) do
278
312
  expect(SubclassTask.where(name: name).count).to eq 1
279
- expect(SubclassTask.where(name: name).first).to eq subclass_task_1
313
+ expect(SubclassTask.where(name: name).first).to eq subclass_task1
280
314
  end
281
- MultiTenant.with(tenant_id_2) do
315
+ MultiTenant.with(tenant_id2) do
282
316
  expect(SubclassTask.where(name: name).count).to eq 1
283
- expect(SubclassTask.where(name: name).first).to eq subclass_task_2
317
+ expect(SubclassTask.where(name: name).first).to eq subclass_task2
318
+ end
319
+ end
320
+ end
321
+
322
+ # Joins
323
+ describe 'joins for models' do
324
+ context 'for models with where condition in associations' do
325
+ let(:account) { Account.create!(name: 'Account 1') }
326
+
327
+ it 'should add tenant condition to the queries when tenant is set' do
328
+ expected_join_sql = <<-SQL.strip
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
334
+ SQL
335
+
336
+ MultiTenant.with(account) do
337
+ expect(format_sql(Comment.joins(:task).to_sql)).to eq(format_sql(expected_join_sql))
338
+ end
339
+ end
340
+
341
+ it 'should add tenant condition to the queries when tenant is not set' do
342
+ MultiTenant.without do
343
+ expected_join_sql = <<-SQL.strip
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"
348
+ SQL
349
+ expect(format_sql(Comment.joins(:task).to_sql)).to eq(format_sql(expected_join_sql))
350
+ end
351
+ end
352
+ end
353
+
354
+ context 'for models with default associations' do
355
+ let(:account) { Account.create!(name: 'Account 1') }
356
+
357
+ it 'should add tenant condition to the queries when tenant is set' do
358
+ expected_join_sql = <<-SQL.strip
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
364
+ SQL
365
+
366
+ MultiTenant.with(account) do
367
+ expect(format_sql(Project.joins(:tasks).to_sql)).to eq(format_sql(expected_join_sql))
368
+ end
369
+ end
370
+
371
+ it 'should add tenant condition to the queries when tenant is not set' do
372
+ MultiTenant.without do
373
+ expected_join_sql = <<-SQL.strip
374
+ SELECT "projects".*
375
+ FROM "projects"
376
+ INNER JOIN "tasks" ON "tasks"."project_id" = "projects"."id"
377
+ AND "projects"."account_id" = "tasks"."account_id"
378
+ SQL
379
+ expect(format_sql(Project.joins(:tasks).to_sql)).to eq(format_sql(expected_join_sql))
380
+ end
284
381
  end
285
382
  end
286
383
  end
287
384
 
288
385
  # ::with
289
- describe "::with" do
290
- it "should set current_tenant to the specified tenant inside the block" do
291
- @account = Account.create!(:name => 'baz')
386
+ describe '::with' do
387
+ it 'should set current_tenant to the specified tenant inside the block' do
388
+ @account = Account.create!(name: 'baz')
292
389
 
293
390
  MultiTenant.with(@account) do
294
391
  expect(MultiTenant.current_tenant).to eq(@account)
295
392
  end
296
393
  end
297
394
 
298
- it "should reset current_tenant to the previous tenant once exiting the block" do
299
- @account1 = Account.create!(:name => 'foo')
300
- @account2 = Account.create!(:name => 'bar')
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')
301
398
 
302
399
  MultiTenant.current_tenant = @account1
303
400
  MultiTenant.with @account2 do
304
-
305
401
  end
306
402
 
307
403
  expect(MultiTenant.current_tenant).to eq(@account1)
308
404
  end
309
405
 
310
- it "should return the value of the block" do
311
- @account1 = Account.create!(:name => 'foo')
312
- @account2 = Account.create!(:name => 'bar')
406
+ it 'should return the value of the block' do
407
+ @account1 = Account.create!(name: 'foo')
408
+ @account2 = Account.create!(name: 'bar')
313
409
 
314
410
  MultiTenant.current_tenant = @account1
315
411
  value = MultiTenant.with @account2 do
316
- "something"
412
+ 'something'
317
413
  end
318
414
 
319
- expect(value).to eq "something"
415
+ expect(value).to eq 'something'
320
416
  end
321
417
 
322
418
  it 'supports reload inside the block' do
@@ -331,9 +427,9 @@ describe MultiTenant do
331
427
  end
332
428
 
333
429
  # ::without
334
- describe "::without" do
335
- it "should unset current_tenant inside the block" do
336
- @account = Account.create!(:name => 'baz')
430
+ describe '::without' do
431
+ it 'should unset current_tenant inside the block' do
432
+ @account = Account.create!(name: 'baz')
337
433
 
338
434
  MultiTenant.current_tenant = @account
339
435
  MultiTenant.without do
@@ -341,39 +437,25 @@ describe MultiTenant do
341
437
  end
342
438
  end
343
439
 
344
- it "should reset current_tenant to the previous tenant once exiting the block" do
345
- @account1 = Account.create!(:name => 'foo')
440
+ it 'should reset current_tenant to the previous tenant once exiting the block' do
441
+ @account1 = Account.create!(name: 'foo')
346
442
 
347
443
  MultiTenant.current_tenant = @account1
348
444
  MultiTenant.without do
349
-
350
445
  end
351
446
 
352
447
  expect(MultiTenant.current_tenant).to eq(@account1)
353
448
  end
354
449
 
355
- it "should return the value of the block" do
356
- @account1 = Account.create!(:name => 'foo')
450
+ it 'should return the value of the block' do
451
+ @account1 = Account.create!(name: 'foo')
357
452
 
358
453
  MultiTenant.current_tenant = @account1
359
454
  value = MultiTenant.without do
360
- "something"
455
+ 'something'
361
456
  end
362
457
 
363
- expect(value).to eq "something"
364
- end
365
- end
366
-
367
- describe '.with_lock' do
368
- it 'supports with_lock blocks inside the block' do
369
- @account = Account.create!(name: 'foo')
370
-
371
- MultiTenant.with @account do
372
- project = @account.projects.create!(name: 'project')
373
- project.with_lock do
374
- expect(project.name).to eq 'project'
375
- end
376
- end
458
+ expect(value).to eq 'something'
377
459
  end
378
460
  end
379
461
 
@@ -398,13 +480,20 @@ describe MultiTenant do
398
480
  end
399
481
  end
400
482
 
401
- it "applies the team_id conditions in the where clause" do
402
- option1 = <<-sql.strip
403
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "tasks"."project_id" = 1 AND "sub_tasks"."account_id" = 1 AND "tasks"."account_id" = 1
404
- sql
405
- option2 = <<-sql.strip
406
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "sub_tasks"."account_id" = 1 AND "tasks"."project_id" = 1 AND "tasks"."account_id" = 1
407
- sql
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
408
497
 
409
498
  account1 = Account.create! name: 'Account 1'
410
499
 
@@ -412,27 +501,38 @@ describe MultiTenant do
412
501
  project1 = Project.create! name: 'Project 1'
413
502
  task1 = Task.create! name: 'Task 1', project: project1
414
503
  subtask1 = SubTask.create! task: task1
415
- expect(project1.sub_tasks.to_sql).to eq(option1).or(eq(option2))
504
+ expect(format_sql(project1.sub_tasks.to_sql))
505
+ .to eq(format_sql(option1)).or(eq(format_sql(option2)))
416
506
  expect(project1.sub_tasks).to include(subtask1)
417
507
  end
418
508
 
419
509
  MultiTenant.without do
420
- expected_sql = <<-sql
421
- SELECT "sub_tasks".* FROM "sub_tasks" INNER JOIN "tasks" ON "sub_tasks"."task_id" = "tasks"."id" AND "sub_tasks"."account_id" = "tasks"."account_id" WHERE "tasks"."project_id" = 1
422
- sql
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
423
517
 
424
518
  project = Project.first
425
- 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))
426
520
  end
427
521
  end
428
522
 
429
- it "tests joins between distributed and reference table" do
430
- option1 = <<-sql.strip
431
- SELECT "categories".* FROM "categories" INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id" WHERE "project_categories"."project_id" = 1 AND "project_categories"."account_id" = 1
432
- sql
433
- option2 = <<-sql.strip
434
- SELECT "categories".* FROM "categories" INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id" WHERE "project_categories"."account_id" = 1 AND "project_categories"."project_id" = 1
435
- sql
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
436
536
 
437
537
  account1 = Account.create! name: 'Account 1'
438
538
  category1 = Category.create! name: 'Category 1'
@@ -441,47 +541,72 @@ describe MultiTenant do
441
541
  project1 = Project.create! name: 'Project 1'
442
542
  projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
443
543
 
444
- expect(project1.categories.to_sql).to eq(option1).or(eq(option2))
544
+ expect(format_sql(project1.categories.to_sql))
545
+ .to eq(format_sql(option1)).or(eq(format_sql(option2)))
445
546
  expect(project1.categories).to include(category1)
446
547
  expect(project1.project_categories).to include(projectcategory)
447
548
  end
448
549
 
449
550
  MultiTenant.without do
450
- expected_sql = <<-sql
451
- SELECT "categories".* FROM "categories" INNER JOIN "project_categories" ON "categories"."id" = "project_categories"."category_id" WHERE "project_categories"."project_id" = 1
452
- sql
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
453
557
 
454
558
  project = Project.first
455
- expect(project.categories.to_sql).to eq(expected_sql.strip)
559
+ expect(format_sql(project.categories.to_sql))
560
+ .to eq(format_sql(expected_sql.strip))
456
561
  expect(project.categories).to include(category1)
457
562
 
458
- expected_sql = <<-sql
459
- SELECT "projects".* FROM "projects" INNER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = "projects"."account_id" INNER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
460
- sql
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
461
570
 
462
- expect(Project.where(account_id: 1).joins(:categories).to_sql).to eq(expected_sql.strip)
571
+ expect(format_sql(Project.where(account_id: 1).joins(:categories).to_sql))
572
+ .to eq(format_sql(expected_sql.strip))
463
573
  project = Project.where(account_id: 1).joins(:categories).first
464
574
  expect(project.categories).to include(category1)
465
575
  end
466
576
  end
467
577
 
468
-
469
- it "test eager_load" do
578
+ it 'test eager_load' do
470
579
  account1 = Account.create! name: 'Account 1'
471
580
  category1 = Category.create! name: 'Category 1'
472
581
 
473
- option1 = <<-sql.strip
474
- SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = 1 AND "projects"."account_id" = 1 LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
475
- sql
476
- option2 = <<-sql.strip
477
- SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."account_id" = 1 AND "project_categories"."project_id" = "projects"."id" AND "projects"."account_id" = 1 LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" AND "project_categories"."account_id" = 1 WHERE "projects"."account_id" = 1
478
- sql
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
479
603
 
480
604
  MultiTenant.with(account1) do
481
605
  project1 = Project.create! name: 'Project 1'
482
606
  projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
483
607
 
484
- expect(Project.eager_load(:categories).to_sql).to eq(option1).or(eq(option2))
608
+ expect(format_sql(Project.eager_load(:categories).to_sql))
609
+ .to eq(format_sql(option1)).or(eq(format_sql(option2)))
485
610
 
486
611
  project = Project.eager_load(:categories).first
487
612
  expect(project.categories).to include(category1)
@@ -489,92 +614,120 @@ describe MultiTenant do
489
614
  end
490
615
 
491
616
  MultiTenant.without do
492
- expected_sql = <<-sql
493
- SELECT "projects"."id" AS t0_r0, "projects"."account_id" AS t0_r1, "projects"."name" AS t0_r2, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1 FROM "projects" LEFT OUTER JOIN "project_categories" ON "project_categories"."project_id" = "projects"."id" AND "project_categories"."account_id" = "projects"."account_id" LEFT OUTER JOIN "categories" ON "categories"."id" = "project_categories"."category_id" WHERE "projects"."account_id" = 1
494
- sql
495
-
496
- expect(Project.where(account_id: 1).eager_load(:categories).to_sql).to eq(expected_sql.strip)
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))
497
629
 
498
630
  project = Project.where(account_id: 1).eager_load(:categories).first
499
631
  expect(project.categories).to include(category1)
500
-
501
632
  end
502
633
  end
503
634
 
504
- it "test raw SQL joins" do
635
+ it 'test raw SQL joins' do
505
636
  account1 = Account.create! name: 'Account 1'
506
637
  category1 = Category.create! name: 'Category 1'
507
638
 
508
639
  MultiTenant.with(account1) do
509
- option1 = <<-sql.strip
510
- SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "projects"."account_id" = 1 LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
511
- sql
512
- option2 = <<-sql.strip
513
- SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."account_id" = 1 AND "projects"."id" = "tasks"."project_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
514
- sql
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
515
653
 
516
654
  project1 = Project.create! name: 'Project 1'
517
- projectcategory = ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
655
+ ProjectCategory.create! name: 'project cat 1', project: project1, category: category1
518
656
 
519
657
  project1.tasks.create! name: 'baz'
520
- expect(Task.joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql).to eq(option1).or(eq(option2))
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)))
521
663
  end
522
664
 
523
665
  MultiTenant.without do
524
- expected_sql = <<-sql
525
- SELECT "tasks".* FROM "tasks" INNER JOIN "projects" ON "projects"."id" = "tasks"."project_id" AND "projects"."account_id" = "tasks"."account_id" LEFT JOIN project_categories pc ON project.category_id = pc.id WHERE "tasks"."account_id" = 1
526
- sql
527
-
528
- expect(Task.where(account_id: 1).joins(:project).joins('LEFT JOIN project_categories pc ON project.category_id = pc.id').to_sql).to eq(expected_sql.strip)
529
-
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))
530
677
  end
531
-
532
678
  end
533
679
 
534
- it "only applies clauses when a tenant is set" do
680
+ it 'only applies clauses when a tenant is set' do
535
681
  account = Account.create! name: 'Account 1'
536
682
  project = Project.create! name: 'Project 1', account: account
537
683
  project2 = Project.create! name: 'Project 2', account: Account.create!(name: 'Account2')
538
684
 
539
685
  MultiTenant.with(account) do
540
- option1 = <<-sql.strip
541
- SELECT "projects".* FROM "projects" WHERE "projects"."account_id" = #{account.id} AND "projects"."id" = $1 LIMIT $2
542
- sql
543
- option2 = <<-sql.strip
544
- SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 AND "projects"."account_id" = #{account.id} LIMIT $2
545
- sql
546
- option3 = <<-sql.strip
547
- SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 AND "projects"."account_id" = #{account.id} LIMIT $2
548
- sql
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
549
699
 
550
700
  # Couldn't make the following line pass for some reason, so came up with an uglier alternative
551
- # expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)).or(eq(option3)), any_args).and_call_original
701
+ # expect(Project).to receive(:find_by_sql).with(eq(option1).
702
+ # or(eq(option2)).or(eq(option3)), any_args).and_call_original
552
703
  expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
553
- expect(args[0]).to(eq(option1).or(eq(option2)).or(eq(option3)))
554
- m.call(args[0], args[1], preparable:args[2][:preparable])
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])
555
707
  end
556
708
  expect(Project.find(project.id)).to eq(project)
557
709
  end
558
710
 
559
711
  MultiTenant.without do
560
- option1 = <<-sql.strip
561
- SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2
562
- sql
563
- option2 = <<-sql.strip
564
- SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2
565
- sql
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
566
720
 
567
721
  # Couldn't make the following line pass for some reason, so came up with an uglier alternative
568
722
  # expect(Project).to receive(:find_by_sql).with(eq(option1).or(eq(option2)), any_args).and_call_original
569
723
  expect(Project).to receive(:find_by_sql).and_wrap_original do |m, *args|
570
- expect(args[0]).to(eq(option1).or(eq(option2)))
571
- 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])
572
726
  end
573
727
  expect(Project.find(project2.id)).to eq(project2)
574
728
  end
575
729
  end
576
730
 
577
-
578
731
  describe 'with unsaved association' do
579
732
  before do
580
733
  @account = Account.create!(name: 'reflection tenant')
@@ -588,13 +741,13 @@ describe MultiTenant do
588
741
  end
589
742
  end
590
743
 
591
- it "test value of RETURNING insert in table with no pkey" do
744
+ it 'test value of RETURNING insert in table with no pkey' do
592
745
  account1 = Account.create(name: 'test1')
593
746
 
594
747
  MultiTenant.with(account1) do
595
- allowed_place = AllowedPlace.create! name: 'something1'
748
+ AllowedPlace.create! name: 'something1'
596
749
 
597
- project = Project.create! name: 'Project 1'
750
+ Project.create! name: 'Project 1'
598
751
  end
599
752
  end
600
753
  end