ar-octopus 0.9.0 → 0.9.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +10 -2
  4. data/Appraisals +4 -0
  5. data/README.mkdn +1 -1
  6. data/gemfiles/rails51.gemfile +7 -0
  7. data/lib/octopus.rb +11 -6
  8. data/lib/octopus/collection_association.rb +9 -3
  9. data/lib/octopus/finder_methods.rb +1 -1
  10. data/lib/octopus/load_balancing/round_robin.rb +1 -0
  11. data/lib/octopus/log_subscriber.rb +6 -2
  12. data/lib/octopus/migration.rb +25 -9
  13. data/lib/octopus/model.rb +17 -25
  14. data/lib/octopus/proxy.rb +78 -279
  15. data/lib/octopus/proxy_config.rb +252 -0
  16. data/lib/octopus/relation_proxy.rb +7 -1
  17. data/lib/octopus/scope_proxy.rb +1 -1
  18. data/lib/octopus/shard_tracking.rb +2 -1
  19. data/lib/octopus/version.rb +1 -1
  20. data/spec/migrations/10_create_users_using_replication.rb +1 -1
  21. data/spec/migrations/11_add_field_in_all_slaves.rb +1 -1
  22. data/spec/migrations/12_create_users_using_block.rb +1 -1
  23. data/spec/migrations/13_create_users_using_block_and_using.rb +1 -1
  24. data/spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb +1 -1
  25. data/spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb +1 -1
  26. data/spec/migrations/1_create_users_on_master.rb +1 -1
  27. data/spec/migrations/2_create_users_on_canada.rb +1 -1
  28. data/spec/migrations/3_create_users_on_both_shards.rb +1 -1
  29. data/spec/migrations/4_create_users_on_shards_of_a_group.rb +1 -1
  30. data/spec/migrations/5_create_users_on_multiples_groups.rb +1 -1
  31. data/spec/migrations/6_raise_exception_with_invalid_shard_name.rb +1 -1
  32. data/spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb +1 -1
  33. data/spec/migrations/8_raise_exception_with_invalid_group_name.rb +1 -1
  34. data/spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb +1 -1
  35. data/spec/octopus/association_shard_tracking_spec.rb +15 -15
  36. data/spec/octopus/load_balancing/round_robin_spec.rb +15 -0
  37. data/spec/octopus/log_subscriber_spec.rb +1 -1
  38. data/spec/octopus/model_spec.rb +34 -5
  39. data/spec/octopus/octopus_spec.rb +1 -1
  40. data/spec/octopus/proxy_spec.rb +16 -38
  41. data/spec/octopus/relation_proxy_spec.rb +4 -0
  42. data/spec/octopus/replication_spec.rb +5 -1
  43. data/spec/spec_helper.rb +2 -0
  44. data/spec/support/octopus_helper.rb +1 -2
  45. data/spec/tasks/octopus.rake_spec.rb +2 -4
  46. metadata +7 -6
  47. data/.ruby-version +0 -1
  48. data/init.rb +0 -1
  49. data/rails/init.rb +0 -1
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Octopus::LoadBalancing::RoundRobin do
4
+ it "raises an error when no shards are given" do
5
+ expect do
6
+ Octopus::LoadBalancing::RoundRobin.new([])
7
+ end.to raise_error Octopus::Exception
8
+ end
9
+
10
+ it "does not raise an error if slaves given" do
11
+ expect do
12
+ Octopus::LoadBalancing::RoundRobin.new([:stub])
13
+ end.to_not raise_error Octopus::Exception
14
+ end
15
+ end
@@ -9,7 +9,7 @@ describe Octopus::LogSubscriber, :shards => [:canada] do
9
9
  end
10
10
 
11
11
  after :each do
12
- ActiveRecord::Base.logger = nil
12
+ ActiveRecord::Base.logger = Logger.new(File.open('database.log', 'a'))
13
13
  end
14
14
 
15
15
  it 'should add to the default logger the shard name the query was sent to' do
@@ -90,7 +90,7 @@ describe Octopus::Model do
90
90
  Octopus.using(:canada) do
91
91
  fail 'Some Exception'
92
92
  end
93
- end.to raise_error
93
+ end.to raise_error(RuntimeError)
94
94
 
95
95
  expect(ActiveRecord::Base.connection.current_shard).to eq(:master)
96
96
  end
@@ -103,7 +103,7 @@ describe Octopus::Model do
103
103
  Octopus.using(:canada) do
104
104
  fail 'Some Exception'
105
105
  end
106
- end.to raise_error
106
+ end.to raise_error(RuntimeError)
107
107
 
108
108
  expect(ActiveRecord::Base.connection.current_shard).to eq(:brazil)
109
109
  Octopus.config[:master_shard] = nil
@@ -476,6 +476,34 @@ describe Octopus::Model do
476
476
  expect(User.using(:master).count).to eq(1)
477
477
  end
478
478
 
479
+ describe "#finder methods" do
480
+ before(:each) do
481
+ @user1 = User.using(:brazil).create!(:name => 'User1')
482
+ @user2 = User.using(:brazil).create!(:name => 'User2')
483
+ @user3 = User.using(:brazil).create!(:name => 'User3')
484
+ end
485
+
486
+ it "#find_each should work" do
487
+ result_array = []
488
+
489
+ User.using(:brazil).where("name is not NULL").find_each do |user|
490
+ result_array << user
491
+ end
492
+
493
+ expect(result_array).to eq([@user1, @user2, @user3])
494
+ end
495
+
496
+ it "#find_in_batches, should work" do
497
+ result_array = []
498
+
499
+ User.using(:brazil).where("name is not NULL").find_in_batches(batch_size: 1) do |user|
500
+ result_array << user
501
+ end
502
+
503
+ expect(result_array).to eq([[@user1], [@user2], [@user3]])
504
+ end
505
+ end
506
+
479
507
  describe 'deleting a record' do
480
508
  before(:each) do
481
509
  @user = User.using(:brazil).create!(:name => 'User1')
@@ -665,20 +693,21 @@ describe Octopus::Model do
665
693
  it 'should work correctly when using validations' do
666
694
  @key = Keyboard.create!(:name => 'Key')
667
695
  expect { Keyboard.using(:brazil).create!(:name => 'Key') }.not_to raise_error
668
- expect { Keyboard.create!(:name => 'Key') }.to raise_error
696
+ expect { Keyboard.create!(:name => 'Key') }.to raise_error(ActiveRecord::RecordInvalid)
669
697
  end
670
698
 
671
699
  it 'should work correctly when using validations with using syntax' do
672
700
  @key = Keyboard.using(:brazil).create!(:name => 'Key')
673
701
  expect { Keyboard.create!(:name => 'Key') }.not_to raise_error
674
- expect { Keyboard.using(:brazil).create!(:name => 'Key') }.to raise_error
702
+ expect { Keyboard.using(:brazil).create!(:name => 'Key') }
703
+ .to raise_error(ActiveRecord::RecordInvalid)
675
704
  end
676
705
  end
677
706
 
678
707
  describe '#replicated_model method' do
679
708
  it 'should be replicated' do
680
709
  OctopusHelper.using_environment :production_replicated do
681
- expect(ActiveRecord::Base.connection_proxy.instance_variable_get(:@replicated)).to be true
710
+ expect(ActiveRecord::Base.connection_proxy.replicated).to be true
682
711
  end
683
712
  end
684
713
 
@@ -37,7 +37,7 @@ describe Octopus, :shards => [] do
37
37
  end
38
38
 
39
39
  it 'should permit users to configure shards on initializer files, instead of on a yml file.' do
40
- expect { User.using(:crazy_shard).create!(:name => 'Joaquim') }.to raise_error
40
+ expect { User.using(:crazy_shard).create!(:name => 'Joaquim') }.to raise_error(RuntimeError)
41
41
 
42
42
  Octopus.setup do |config|
43
43
  config.shards = { :crazy_shard => { :adapter => 'mysql2', :database => 'octopus_shard_5', :username => 'root', :password => '' } }
@@ -6,10 +6,10 @@ describe Octopus::Proxy do
6
6
  describe 'creating a new instance', :shards => [] do
7
7
  it 'should initialize all shards and groups' do
8
8
  # FIXME: Don't test implementation details
9
- expect(proxy.instance_variable_get(:@shards)).to include('canada', 'brazil', 'master', 'sqlite_shard', 'russia', 'alone_shard',
9
+ expect(proxy.shards).to include('canada', 'brazil', 'master', 'sqlite_shard', 'russia', 'alone_shard',
10
10
  'aug2009', 'postgresql_shard', 'aug2010', 'aug2011')
11
11
 
12
- expect(proxy.instance_variable_get(:@shards)).to include('protocol_shard')
12
+ expect(proxy.shards).to include('protocol_shard')
13
13
 
14
14
  expect(proxy.has_group?('country_shards')).to be true
15
15
  expect(proxy.shards_for_group('country_shards')).to include(:canada, :brazil, :russia)
@@ -23,23 +23,17 @@ describe Octopus::Proxy do
23
23
  end
24
24
 
25
25
  it 'should initialize replicated attribute as false' do
26
- expect(proxy.instance_variable_get(:@replicated)).to be_falsey
26
+ expect(proxy.replicated).to be_falsey
27
27
  end
28
28
 
29
- it 'should work with thiking sphinx' do
30
- config = proxy.instance_variable_get(:@config)
29
+ it 'should work with thinking sphinx' do
30
+ config = proxy.config
31
31
  expect(config[:adapter]).to eq('mysql2')
32
32
  expect(config[:database]).to eq('octopus_shard_1')
33
33
  expect(config[:username]).to eq('root')
34
34
  end
35
35
 
36
- it 'should create a set with all adapters, to ensure that is needed to clean the table name.' do
37
- adapters = proxy.instance_variable_get(:@adapters)
38
- expect(adapters).to be_kind_of(Set)
39
- expect(adapters.to_a).to match_array(%w(sqlite3 mysql2 postgresql))
40
- end
41
-
42
- unless Octopus.rails5?
36
+ unless Octopus.rails50? || Octopus.rails51?
43
37
  it 'should respond correctly to respond_to?(:pk_and_sequence_for)' do
44
38
  expect(proxy.respond_to?(:pk_and_sequence_for)).to be true
45
39
  end
@@ -63,22 +57,6 @@ describe Octopus::Proxy do
63
57
  end
64
58
  end
65
59
 
66
- describe '#should_clean_table_name?' do
67
- it 'should return true when you have a environment with multiple database types' do
68
- expect(proxy.should_clean_table_name?).to be true
69
- end
70
-
71
- context 'when using a environment with a single table name' do
72
- before(:each) do
73
- OctopusHelper.octopus_env = 'production_replicated'
74
- end
75
-
76
- it 'should return false' do
77
- expect(proxy.should_clean_table_name?).to be false
78
- end
79
- end
80
- end
81
-
82
60
  describe 'should raise error if you have duplicated shard names' do
83
61
  before(:each) do
84
62
  OctopusHelper.octopus_env = 'production_raise_error'
@@ -95,11 +73,11 @@ describe Octopus::Proxy do
95
73
  end
96
74
 
97
75
  it 'should initialize just the master shard' do
98
- expect(proxy.instance_variable_get(:@shards).keys).to eq(['master'])
76
+ expect(proxy.shards.keys).to eq(['master'])
99
77
  end
100
78
 
101
79
  it 'should not initialize replication' do
102
- expect(proxy.instance_variable_get(:@replicated)).to be_nil
80
+ expect(proxy.replicated).to be_nil
103
81
  end
104
82
  end
105
83
  end
@@ -110,11 +88,11 @@ describe Octopus::Proxy do
110
88
  end
111
89
 
112
90
  it 'should have the replicated attribute as true' do
113
- expect(proxy.instance_variable_get(:@replicated)).to be true
91
+ expect(proxy.replicated).to be true
114
92
  end
115
93
 
116
94
  it 'should initialize the list of shards' do
117
- expect(proxy.instance_variable_get(:@slaves_list)).to eq(%w(slave1 slave2 slave3 slave4))
95
+ expect(proxy.slaves_list).to eq(%w(slave1 slave2 slave3 slave4))
118
96
  end
119
97
  end
120
98
 
@@ -137,7 +115,7 @@ describe Octopus::Proxy do
137
115
  Octopus.instance_variable_set(:@environments, nil)
138
116
  Octopus.config
139
117
 
140
- expect(proxy.instance_variable_get(:@replicated)).to be true
118
+ expect(proxy.replicated).to be true
141
119
  expect(Octopus.environments).to eq(%w(staging production))
142
120
  end
143
121
 
@@ -147,7 +125,7 @@ describe Octopus::Proxy do
147
125
  Octopus.instance_variable_set(:@environments, nil)
148
126
  Octopus.config
149
127
 
150
- expect(proxy.instance_variable_get(:@shards).keys.to_set).to eq(Set.new(%w(slave1 slave2 master)))
128
+ expect(proxy.shards.keys.to_set).to eq(Set.new(%w(slave1 slave2 master)))
151
129
  end
152
130
 
153
131
  it 'should initialize correctly the shard octopus_shard value for logging' do
@@ -156,7 +134,7 @@ describe Octopus::Proxy do
156
134
  Octopus.instance_variable_set(:@environments, nil)
157
135
  Octopus.config
158
136
 
159
- expect(proxy.instance_variable_get(:@shards)['slave1'].spec.config).to have_key :octopus_shard
137
+ expect(proxy.shards['slave1'].spec.config).to have_key :octopus_shard
160
138
  end
161
139
 
162
140
  it 'should initialize correctly the shards for the production environment' do
@@ -165,7 +143,7 @@ describe Octopus::Proxy do
165
143
  Octopus.instance_variable_set(:@environments, nil)
166
144
  Octopus.config
167
145
 
168
- expect(proxy.instance_variable_get(:@shards).keys.to_set).to eq(Set.new(%w(slave3 slave4 master)))
146
+ expect(proxy.shards.keys.to_set).to eq(Set.new(%w(slave3 slave4 master)))
169
147
  end
170
148
 
171
149
  describe 'using the master connection', :shards => [:russia, :master] do
@@ -234,12 +212,12 @@ describe Octopus::Proxy do
234
212
 
235
213
  describe 'should return the connection based on shard_name' do
236
214
  it 'when current_shard is empty' do
237
- expect(proxy.select_connection).to eq(proxy.instance_variable_get(:@shards)[:master].connection)
215
+ expect(proxy.select_connection).to eq(proxy.shards[:master].connection)
238
216
  end
239
217
 
240
218
  it 'when current_shard is a single shard' do
241
219
  proxy.current_shard = :canada
242
- expect(proxy.select_connection).to eq(proxy.instance_variable_get(:@shards)[:canada].connection)
220
+ expect(proxy.select_connection).to eq(proxy.shards[:canada].connection)
243
221
  end
244
222
  end
245
223
  end
@@ -38,6 +38,10 @@ describe Octopus::RelationProxy do
38
38
  end
39
39
  end
40
40
 
41
+ it "can deliver methods in ActiveRecord::Batches correctly" do
42
+ expect { @relation.find_each(&:inspect) }.not_to raise_error
43
+ end
44
+
41
45
  context 'under Rails 4' do
42
46
  it 'is an Octopus::RelationProxy' do
43
47
  expect{@relation.ar_relation}.not_to raise_error
@@ -42,7 +42,11 @@ describe 'when the database is replicated' do
42
42
  expect(Cat.find(cat3.id).id).to eq(cat3.id)
43
43
  expect(Cat.find(cat3.id).id).to eq(cat3.id)
44
44
 
45
- expect(counter.query_count).to eq(14)
45
+ # Rails 5.1 count the cached queries as regular queries.
46
+ # TODO: How we can verify if the queries are using cache on Rails 5.1? - @thiagopradi
47
+ expected_records = Octopus.rails51? ? 19 : 14
48
+
49
+ expect(counter.query_count).to eq(expected_records)
46
50
  end
47
51
  end
48
52
  end
@@ -5,6 +5,8 @@ require 'octopus'
5
5
 
6
6
  Octopus.instance_variable_set(:@directory, File.dirname(__FILE__))
7
7
 
8
+ BaseOctopusMigrationClass = (Octopus.rails4? ? ActiveRecord::Migration : ActiveRecord::Migration[ActiveRecord::VERSION::STRING[0..2]])
9
+
8
10
  # Requires supporting files with custom matchers and macros, etc,
9
11
  # in ./support/ and its subdirectories.
10
12
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -1,7 +1,7 @@
1
1
  module OctopusHelper
2
2
  def self.clean_all_shards(shards)
3
3
  if shards.nil?
4
- shards = BlankModel.using(:master).connection.instance_variable_get(:@shards).keys
4
+ shards = BlankModel.using(:master).connection.shards.keys
5
5
  end
6
6
 
7
7
  shards.each do |shard_symbol|
@@ -23,7 +23,6 @@ module OctopusHelper
23
23
  Thread.current['octopus.current_group'] = nil
24
24
  Thread.current['octopus.current_slave_group'] = nil
25
25
  Thread.current['octopus.block'] = nil
26
- Thread.current['octopus.last_current_shard'] = nil
27
26
 
28
27
  ActiveRecord::Base.class_variable_set(:@@connection_proxy, nil)
29
28
  end
@@ -24,10 +24,8 @@ describe 'octopus.rake' do
24
24
 
25
25
  Rake::Task['octopus:copy_schema_versions'].invoke
26
26
 
27
- # Skip SQLite shard for now - not sure why this test is failing.
28
- # TODO - Verify this test in the future.
29
- ActiveRecord::Base.connection.shard_names.reject { |sh_name| sh_name == 'sqlite_shard' }.each do |shard_name|
30
- expect(Octopus.using(shard_name) { ActiveRecord::Migrator.get_all_versions }).to eq([1, 2, 3])
27
+ ActiveRecord::Base.connection.shard_names.each do |shard_name|
28
+ expect(Octopus.using(shard_name) { ActiveRecord::SchemaMigration.all.pluck(:version).map(&:to_i).sort }).to eq([1, 2, 3])
31
29
  end
32
30
  end
33
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar-octopus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thiago Pradi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-12-08 00:00:00.000000000 Z
13
+ date: 2017-07-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -167,7 +167,6 @@ files:
167
167
  - ".rspec"
168
168
  - ".rubocop.yml"
169
169
  - ".rubocop_todo.yml"
170
- - ".ruby-version"
171
170
  - ".travis.yml"
172
171
  - Appraisals
173
172
  - Gemfile
@@ -179,7 +178,7 @@ files:
179
178
  - gemfiles/rails41.gemfile
180
179
  - gemfiles/rails42.gemfile
181
180
  - gemfiles/rails5.gemfile
182
- - init.rb
181
+ - gemfiles/rails51.gemfile
183
182
  - lib/ar-octopus.rb
184
183
  - lib/octopus.rb
185
184
  - lib/octopus/abstract_adapter.rb
@@ -197,6 +196,7 @@ files:
197
196
  - lib/octopus/model.rb
198
197
  - lib/octopus/persistence.rb
199
198
  - lib/octopus/proxy.rb
199
+ - lib/octopus/proxy_config.rb
200
200
  - lib/octopus/railtie.rb
201
201
  - lib/octopus/relation_proxy.rb
202
202
  - lib/octopus/scope_proxy.rb
@@ -207,7 +207,6 @@ files:
207
207
  - lib/octopus/slave_group.rb
208
208
  - lib/octopus/version.rb
209
209
  - lib/tasks/octopus.rake
210
- - rails/init.rb
211
210
  - sample_app/.gitignore
212
211
  - sample_app/.rspec
213
212
  - sample_app/Gemfile
@@ -301,6 +300,7 @@ files:
301
300
  - spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb
302
301
  - spec/octopus/association_shard_tracking_spec.rb
303
302
  - spec/octopus/collection_proxy_spec.rb
303
+ - spec/octopus/load_balancing/round_robin_spec.rb
304
304
  - spec/octopus/log_subscriber_spec.rb
305
305
  - spec/octopus/migration_spec.rb
306
306
  - spec/octopus/model_spec.rb
@@ -344,7 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
344
344
  version: '0'
345
345
  requirements: []
346
346
  rubyforge_project:
347
- rubygems_version: 2.4.5.1
347
+ rubygems_version: 2.2.2
348
348
  signing_key:
349
349
  specification_version: 4
350
350
  summary: Easy Database Sharding for ActiveRecord
@@ -367,6 +367,7 @@ test_files:
367
367
  - spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb
368
368
  - spec/octopus/association_shard_tracking_spec.rb
369
369
  - spec/octopus/collection_proxy_spec.rb
370
+ - spec/octopus/load_balancing/round_robin_spec.rb
370
371
  - spec/octopus/log_subscriber_spec.rb
371
372
  - spec/octopus/migration_spec.rb
372
373
  - spec/octopus/model_spec.rb
@@ -1 +0,0 @@
1
- 2.1.5
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'rails', 'init')
@@ -1 +0,0 @@
1
- require 'octopus'