apartment 1.0.2 → 1.1.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +5 -8
  4. data/Gemfile +1 -0
  5. data/README.md +79 -4
  6. data/apartment.gemspec +2 -2
  7. data/gemfiles/rails_3_2.gemfile +2 -0
  8. data/lib/apartment.rb +22 -2
  9. data/lib/apartment/adapters/abstract_adapter.rb +70 -16
  10. data/lib/apartment/adapters/abstract_jdbc_adapter.rb +4 -9
  11. data/lib/apartment/adapters/jdbc_mysql_adapter.rb +2 -13
  12. data/lib/apartment/adapters/jdbc_postgresql_adapter.rb +5 -16
  13. data/lib/apartment/adapters/mysql2_adapter.rb +8 -19
  14. data/lib/apartment/adapters/postgresql_adapter.rb +16 -41
  15. data/lib/apartment/adapters/sqlite3_adapter.rb +6 -3
  16. data/lib/apartment/elevators/first_subdomain.rb +1 -1
  17. data/lib/apartment/elevators/generic.rb +5 -3
  18. data/lib/apartment/version.rb +1 -1
  19. data/lib/generators/apartment/install/templates/apartment.rb +26 -1
  20. data/lib/tasks/apartment.rake +0 -1
  21. data/spec/adapters/jdbc_mysql_adapter_spec.rb +1 -1
  22. data/spec/adapters/jdbc_postgresql_adapter_spec.rb +1 -1
  23. data/spec/adapters/mysql2_adapter_spec.rb +2 -1
  24. data/spec/adapters/postgresql_adapter_spec.rb +1 -0
  25. data/spec/adapters/sqlite3_adapter_spec.rb +56 -0
  26. data/spec/apartment_spec.rb +2 -2
  27. data/spec/examples/connection_adapter_examples.rb +1 -1
  28. data/spec/examples/generic_adapter_custom_configuration_example.rb +90 -0
  29. data/spec/examples/generic_adapter_examples.rb +15 -15
  30. data/spec/examples/schema_adapter_examples.rb +25 -25
  31. data/spec/integration/apartment_rake_integration_spec.rb +4 -4
  32. data/spec/integration/query_caching_spec.rb +2 -2
  33. data/spec/spec_helper.rb +11 -0
  34. data/spec/support/apartment_helpers.rb +8 -2
  35. data/spec/support/setup.rb +3 -3
  36. data/spec/tasks/apartment_rake_spec.rb +11 -11
  37. data/spec/tenant_spec.rb +12 -12
  38. data/spec/unit/config_spec.rb +53 -23
  39. data/spec/unit/elevators/domain_spec.rb +4 -4
  40. data/spec/unit/elevators/first_subdomain_spec.rb +7 -2
  41. data/spec/unit/elevators/generic_spec.rb +19 -2
  42. data/spec/unit/elevators/host_hash_spec.rb +2 -2
  43. data/spec/unit/elevators/subdomain_spec.rb +6 -6
  44. data/spec/unit/migrator_spec.rb +1 -1
  45. data/spec/unit/reloader_spec.rb +2 -2
  46. metadata +11 -9
@@ -60,7 +60,7 @@ describe Apartment::Tenant do
60
60
  describe "#adapter" do
61
61
  it "should load postgresql adapter" do
62
62
  subject.adapter
63
- Apartment::Adapters::PostgresqlAdapter.should be_a(Class)
63
+ expect(Apartment::Adapters::PostgresqlAdapter).to be_a(Class)
64
64
  end
65
65
 
66
66
  it "raises exception with invalid adapter specified" do
@@ -77,9 +77,9 @@ describe Apartment::Tenant do
77
77
 
78
78
  it 'has a threadsafe adapter' do
79
79
  subject.switch!(db1)
80
- thread = Thread.new { subject.current.should == Apartment.default_tenant }
80
+ thread = Thread.new { expect(subject.current).to eq(Apartment.default_tenant) }
81
81
  thread.join
82
- subject.current.should == db1
82
+ expect(subject.current).to eq(db1)
83
83
  end
84
84
  end
85
85
  end
@@ -100,7 +100,7 @@ describe Apartment::Tenant do
100
100
  describe "#create" do
101
101
  it "should seed data" do
102
102
  subject.switch! db1
103
- User.count.should be > 0
103
+ expect(User.count).to be > 0
104
104
  end
105
105
  end
106
106
 
@@ -121,10 +121,10 @@ describe Apartment::Tenant do
121
121
  db_count = User.count + x.times{ User.create }
122
122
 
123
123
  subject.switch! db2
124
- User.count.should == db2_count
124
+ expect(User.count).to eq(db2_count)
125
125
 
126
126
  subject.switch! db1
127
- User.count.should == db_count
127
+ expect(User.count).to eq(db_count)
128
128
  end
129
129
  end
130
130
 
@@ -143,9 +143,9 @@ describe Apartment::Tenant do
143
143
 
144
144
  subject.switch! db1
145
145
  x.times{ Company.create }
146
- Company.count.should == count + x
146
+ expect(Company.count).to eq(count + x)
147
147
  subject.reset
148
- Company.count.should == count + x
148
+ expect(Company.count).to eq(count + x)
149
149
  end
150
150
  end
151
151
  end
@@ -165,8 +165,8 @@ describe Apartment::Tenant do
165
165
  it 'should seed from default path' do
166
166
  subject.create db1
167
167
  subject.switch! db1
168
- User.count.should eq(3)
169
- User.first.name.should eq('Some User 0')
168
+ expect(User.count).to eq(3)
169
+ expect(User.first.name).to eq('Some User 0')
170
170
  end
171
171
 
172
172
  it 'should seed from custom path' do
@@ -175,8 +175,8 @@ describe Apartment::Tenant do
175
175
  end
176
176
  subject.create db1
177
177
  subject.switch! db1
178
- User.count.should eq(6)
179
- User.first.name.should eq('Different User 0')
178
+ expect(User.count).to eq(6)
179
+ expect(User.first.name).to eq('Different User 0')
180
180
  end
181
181
  end
182
182
  end
@@ -7,10 +7,16 @@ describe Apartment do
7
7
  let(:excluded_models){ ["Company"] }
8
8
  let(:seed_data_file_path){ "#{Rails.root}/db/seeds/import.rb" }
9
9
 
10
+ def tenant_names_from_array(names)
11
+ names.each_with_object({}) do |tenant, hash|
12
+ hash[tenant] = Apartment.connection_config
13
+ end.with_indifferent_access
14
+ end
15
+
10
16
  it "should yield the Apartment object" do
11
17
  Apartment.configure do |config|
12
18
  config.excluded_models = []
13
- config.should == Apartment
19
+ expect(config).to eq(Apartment)
14
20
  end
15
21
  end
16
22
 
@@ -18,7 +24,7 @@ describe Apartment do
18
24
  Apartment.configure do |config|
19
25
  config.excluded_models = excluded_models
20
26
  end
21
- Apartment.excluded_models.should == excluded_models
27
+ expect(Apartment.excluded_models).to eq(excluded_models)
22
28
  end
23
29
 
24
30
  it "should set use_schemas" do
@@ -26,14 +32,14 @@ describe Apartment do
26
32
  config.excluded_models = []
27
33
  config.use_schemas = false
28
34
  end
29
- Apartment.use_schemas.should be false
35
+ expect(Apartment.use_schemas).to be false
30
36
  end
31
37
 
32
38
  it "should set seed_data_file" do
33
39
  Apartment.configure do |config|
34
40
  config.seed_data_file = seed_data_file_path
35
41
  end
36
- Apartment.seed_data_file.should eq(seed_data_file_path)
42
+ expect(Apartment.seed_data_file).to eq(seed_data_file_path)
37
43
  end
38
44
 
39
45
  it "should set seed_after_create" do
@@ -41,47 +47,71 @@ describe Apartment do
41
47
  config.excluded_models = []
42
48
  config.seed_after_create = true
43
49
  end
44
- Apartment.seed_after_create.should be true
50
+ expect(Apartment.seed_after_create).to be true
45
51
  end
46
52
 
47
53
  it "should set tld_length" do
48
54
  Apartment.configure do |config|
49
55
  config.tld_length = 2
50
56
  end
51
- Apartment.tld_length.should == 2
57
+ expect(Apartment.tld_length).to eq(2)
52
58
  end
53
59
 
54
60
  context "databases" do
55
- it "should return object if it doesnt respond_to call" do
56
- tenant_names = ['users', 'companies']
61
+ let(:users_conf_hash) { { port: 5444 } }
57
62
 
63
+ before do
58
64
  Apartment.configure do |config|
59
- config.excluded_models = []
60
65
  config.tenant_names = tenant_names
61
66
  end
62
- Apartment.tenant_names.should == tenant_names
63
67
  end
64
68
 
65
- it "should invoke the proc if appropriate" do
66
- tenant_names = lambda{ ['users', 'users'] }
67
- tenant_names.should_receive(:call)
69
+ context "tenant_names as string array" do
70
+ let(:tenant_names) { ['users', 'companies'] }
68
71
 
69
- Apartment.configure do |config|
70
- config.excluded_models = []
71
- config.tenant_names = tenant_names
72
+ it "should return object if it doesnt respond_to call" do
73
+ expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names).keys)
74
+ end
75
+
76
+ it "should set tenants_with_config" do
77
+ expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names))
72
78
  end
73
- Apartment.tenant_names
74
79
  end
75
80
 
76
- it "should return the invoked proc if appropriate" do
77
- dbs = lambda{ Company.all }
81
+ context "tenant_names as proc returning an array" do
82
+ let(:tenant_names) { lambda { ['users', 'companies'] } }
78
83
 
79
- Apartment.configure do |config|
80
- config.excluded_models = []
81
- config.tenant_names = dbs
84
+ it "should return object if it doesnt respond_to call" do
85
+ expect(Apartment.tenant_names).to eq(tenant_names_from_array(tenant_names.call).keys)
86
+ end
87
+
88
+ it "should set tenants_with_config" do
89
+ expect(Apartment.tenants_with_config).to eq(tenant_names_from_array(tenant_names.call))
90
+ end
91
+ end
92
+
93
+ context "tenant_names as Hash" do
94
+ let(:tenant_names) { { users: users_conf_hash }.with_indifferent_access }
95
+
96
+ it "should return object if it doesnt respond_to call" do
97
+ expect(Apartment.tenant_names).to eq(tenant_names.keys)
98
+ end
99
+
100
+ it "should set tenants_with_config" do
101
+ expect(Apartment.tenants_with_config).to eq(tenant_names)
82
102
  end
103
+ end
104
+
105
+ context "tenant_names as proc returning a Hash" do
106
+ let(:tenant_names) { lambda { { users: users_conf_hash }.with_indifferent_access } }
83
107
 
84
- Apartment.tenant_names.should == Company.all
108
+ it "should return object if it doesnt respond_to call" do
109
+ expect(Apartment.tenant_names).to eq(tenant_names.call.keys)
110
+ end
111
+
112
+ it "should set tenants_with_config" do
113
+ expect(Apartment.tenants_with_config).to eq(tenant_names.call)
114
+ end
85
115
  end
86
116
  end
87
117
 
@@ -8,23 +8,23 @@ describe Apartment::Elevators::Domain do
8
8
  describe "#parse_tenant_name" do
9
9
  it "parses the host for a domain name" do
10
10
  request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
11
- elevator.parse_tenant_name(request).should == 'example'
11
+ expect(elevator.parse_tenant_name(request)).to eq('example')
12
12
  end
13
13
 
14
14
  it "ignores a www prefix and domain suffix" do
15
15
  request = ActionDispatch::Request.new('HTTP_HOST' => 'www.example.bc.ca')
16
- elevator.parse_tenant_name(request).should == 'example'
16
+ expect(elevator.parse_tenant_name(request)).to eq('example')
17
17
  end
18
18
 
19
19
  it "returns nil if there is no host" do
20
20
  request = ActionDispatch::Request.new('HTTP_HOST' => '')
21
- elevator.parse_tenant_name(request).should be_nil
21
+ expect(elevator.parse_tenant_name(request)).to be_nil
22
22
  end
23
23
  end
24
24
 
25
25
  describe "#call" do
26
26
  it "switches to the proper tenant" do
27
- Apartment::Tenant.should_receive(:switch!).with('example')
27
+ expect(Apartment::Tenant).to receive(:switch).with('example')
28
28
 
29
29
  elevator.call('HTTP_HOST' => 'www.example.com')
30
30
  end
@@ -8,12 +8,17 @@ describe Apartment::Elevators::FirstSubdomain do
8
8
 
9
9
  context "one subdomain" do
10
10
  let(:subdomain) { "test" }
11
- it { should == "test" }
11
+ it { is_expected.to eq("test") }
12
12
  end
13
13
 
14
14
  context "nested subdomains" do
15
15
  let(:subdomain) { "test1.test2" }
16
- it { should == "test1" }
16
+ it { is_expected.to eq("test1") }
17
+ end
18
+
19
+ context "no subdomain" do
20
+ let(:subdomain) { nil }
21
+ it { is_expected.to eq(nil) }
17
22
  end
18
23
  end
19
24
  end
@@ -15,7 +15,7 @@ describe Apartment::Elevators::Generic do
15
15
  it "calls the processor if given" do
16
16
  elevator = described_class.new(Proc.new{}, Proc.new{'tenant1'})
17
17
 
18
- Apartment::Tenant.should_receive(:switch!).with('tenant1')
18
+ expect(Apartment::Tenant).to receive(:switch).with('tenant1')
19
19
 
20
20
  elevator.call('HTTP_HOST' => 'foo.bar.com')
21
21
  end
@@ -29,7 +29,24 @@ describe Apartment::Elevators::Generic do
29
29
  it "switches to the parsed db_name" do
30
30
  elevator = MyElevator.new(Proc.new{})
31
31
 
32
- Apartment::Tenant.should_receive(:switch!).with('tenant2')
32
+ expect(Apartment::Tenant).to receive(:switch).with('tenant2')
33
+
34
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
35
+ end
36
+
37
+ it "calls the block implementation of `switch`" do
38
+ elevator = MyElevator.new(Proc.new{}, Proc.new{'tenant2'})
39
+
40
+ expect(Apartment::Tenant).to receive(:switch).with('tenant2').and_yield
41
+ elevator.call('HTTP_HOST' => 'foo.bar.com')
42
+ end
43
+
44
+ it "does not call `switch` if no database given" do
45
+ app = Proc.new{}
46
+ elevator = MyElevator.new(app, Proc.new{})
47
+
48
+ expect(Apartment::Tenant).not_to receive(:switch)
49
+ expect(app).to receive :call
33
50
 
34
51
  elevator.call('HTTP_HOST' => 'foo.bar.com')
35
52
  end
@@ -8,7 +8,7 @@ describe Apartment::Elevators::HostHash do
8
8
  describe "#parse_tenant_name" do
9
9
  it "parses the host for a domain name" do
10
10
  request = ActionDispatch::Request.new('HTTP_HOST' => 'example.com')
11
- elevator.parse_tenant_name(request).should == 'example_tenant'
11
+ expect(elevator.parse_tenant_name(request)).to eq('example_tenant')
12
12
  end
13
13
 
14
14
  it "raises TenantNotFound exception if there is no host" do
@@ -24,7 +24,7 @@ describe Apartment::Elevators::HostHash do
24
24
 
25
25
  describe "#call" do
26
26
  it "switches to the proper tenant" do
27
- Apartment::Tenant.should_receive(:switch!).with('example_tenant')
27
+ expect(Apartment::Tenant).to receive(:switch).with('example_tenant')
28
28
 
29
29
  elevator.call('HTTP_HOST' => 'example.com')
30
30
  end
@@ -9,12 +9,12 @@ describe Apartment::Elevators::Subdomain do
9
9
  context "assuming tld_length of 1" do
10
10
  it "should parse subdomain" do
11
11
  request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.com')
12
- elevator.parse_tenant_name(request).should == 'foo'
12
+ expect(elevator.parse_tenant_name(request)).to eq('foo')
13
13
  end
14
14
 
15
15
  it "should return nil when no subdomain" do
16
16
  request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.com')
17
- elevator.parse_tenant_name(request).should be_nil
17
+ expect(elevator.parse_tenant_name(request)).to be_nil
18
18
  end
19
19
  end
20
20
 
@@ -27,26 +27,26 @@ describe Apartment::Elevators::Subdomain do
27
27
 
28
28
  it "should parse subdomain in the third level domain" do
29
29
  request = ActionDispatch::Request.new('HTTP_HOST' => 'foo.bar.co.uk')
30
- elevator.parse_tenant_name(request).should == "foo"
30
+ expect(elevator.parse_tenant_name(request)).to eq("foo")
31
31
  end
32
32
 
33
33
  it "should return nil when no subdomain in the third level domain" do
34
34
  request = ActionDispatch::Request.new('HTTP_HOST' => 'bar.co.uk')
35
- elevator.parse_tenant_name(request).should be_nil
35
+ expect(elevator.parse_tenant_name(request)).to be_nil
36
36
  end
37
37
  end
38
38
  end
39
39
 
40
40
  describe "#call" do
41
41
  it "switches to the proper tenant" do
42
- Apartment::Tenant.should_receive(:switch!).with('tenant1')
42
+ expect(Apartment::Tenant).to receive(:switch).with('tenant1')
43
43
  elevator.call('HTTP_HOST' => 'tenant1.example.com')
44
44
  end
45
45
 
46
46
  it "ignores excluded subdomains" do
47
47
  described_class.excluded_subdomains = %w{foo}
48
48
 
49
- Apartment::Tenant.should_not_receive(:switch!)
49
+ expect(Apartment::Tenant).not_to receive(:switch)
50
50
 
51
51
  elevator.call('HTTP_HOST' => 'foo.bar.com')
52
52
 
@@ -6,7 +6,7 @@ describe Apartment::Migrator do
6
6
  let(:tenant){ Apartment::Test.next_db }
7
7
 
8
8
  # Don't need a real switch here, just testing behaviour
9
- before { Apartment::Tenant.adapter.stub(:connect_to_new) }
9
+ before { allow(Apartment::Tenant.adapter).to receive(:connect_to_new) }
10
10
 
11
11
  describe "::migrate" do
12
12
  it "switches and migrates" do
@@ -16,9 +16,9 @@ describe Apartment::Reloader do
16
16
  subject{ Apartment::Reloader.new(double("Rack::Application", :call => nil)) }
17
17
 
18
18
  it "should initialize apartment when called" do
19
- Company.table_name.should_not include('public.')
19
+ expect(Company.table_name).not_to include('public.')
20
20
  subject.call(double('env'))
21
- Company.table_name.should include('public.')
21
+ expect(Company.table_name).to include('public.')
22
22
  end
23
23
  end
24
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apartment
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Brunner
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-07-02 00:00:00.000000000 Z
12
+ date: 2016-05-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -74,33 +74,33 @@ dependencies:
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0.9'
76
76
  - !ruby/object:Gem::Dependency
77
- name: rspec-rails
77
+ name: rspec
78
78
  requirement: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.14'
82
+ version: '3.4'
83
83
  type: :development
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '2.14'
89
+ version: '3.4'
90
90
  - !ruby/object:Gem::Dependency
91
- name: guard-rspec
91
+ name: rspec-rails
92
92
  requirement: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '4.2'
96
+ version: '3.4'
97
97
  type: :development
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '4.2'
103
+ version: '3.4'
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: capybara
106
106
  requirement: !ruby/object:Gem::Requirement
@@ -282,6 +282,7 @@ files:
282
282
  - spec/dummy_engine/test/dummy/config/routes.rb
283
283
  - spec/dummy_engine/test/dummy/config/secrets.yml
284
284
  - spec/examples/connection_adapter_examples.rb
285
+ - spec/examples/generic_adapter_custom_configuration_example.rb
285
286
  - spec/examples/generic_adapter_examples.rb
286
287
  - spec/examples/schema_adapter_examples.rb
287
288
  - spec/integration/apartment_rake_integration_spec.rb
@@ -340,7 +341,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
340
341
  version: '0'
341
342
  requirements: []
342
343
  rubyforge_project:
343
- rubygems_version: 2.4.5
344
+ rubygems_version: 2.5.1
344
345
  signing_key:
345
346
  specification_version: 4
346
347
  summary: A Ruby gem for managing database multitenancy
@@ -417,6 +418,7 @@ test_files:
417
418
  - spec/dummy_engine/test/dummy/config/routes.rb
418
419
  - spec/dummy_engine/test/dummy/config/secrets.yml
419
420
  - spec/examples/connection_adapter_examples.rb
421
+ - spec/examples/generic_adapter_custom_configuration_example.rb
420
422
  - spec/examples/generic_adapter_examples.rb
421
423
  - spec/examples/schema_adapter_examples.rb
422
424
  - spec/integration/apartment_rake_integration_spec.rb