activerecord-turntable 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +5 -2
  5. data/README.md +1 -1
  6. data/Rakefile +1 -1
  7. data/activerecord-turntable.gemspec +4 -4
  8. data/gemfiles/rails5_0_0.gemfile +2 -0
  9. data/gemfiles/rails5_0_1.gemfile +3 -0
  10. data/gemfiles/rails5_0_2.gemfile +3 -0
  11. data/gemfiles/rails5_0_3.gemfile +3 -0
  12. data/gemfiles/rails5_0_4.gemfile +3 -0
  13. data/gemfiles/rails5_0_5.gemfile +3 -0
  14. data/gemfiles/rails5_0_6.gemfile +3 -0
  15. data/gemfiles/rails5_0_7.gemfile +3 -0
  16. data/gemfiles/rails5_1_0.gemfile +3 -0
  17. data/gemfiles/rails5_1_1.gemfile +3 -0
  18. data/gemfiles/rails5_1_2.gemfile +3 -0
  19. data/gemfiles/rails5_1_3.gemfile +3 -0
  20. data/gemfiles/rails5_1_4.gemfile +3 -0
  21. data/gemfiles/rails5_1_5.gemfile +3 -0
  22. data/gemfiles/rails5_1_6.gemfile +3 -0
  23. data/gemfiles/rails5_2_0.gemfile +9 -0
  24. data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +22 -0
  25. data/lib/active_record/turntable/active_record_ext/association.rb +8 -2
  26. data/lib/active_record/turntable/active_record_ext/association_preloader.rb +16 -6
  27. data/lib/active_record/turntable/active_record_ext/fixtures.rb +47 -45
  28. data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +14 -7
  29. data/lib/active_record/turntable/active_record_ext/persistence.rb +69 -26
  30. data/lib/active_record/turntable/active_record_ext/query_cache.rb +3 -0
  31. data/lib/active_record/turntable/migration.rb +42 -1
  32. data/lib/active_record/turntable/pool_proxy.rb +5 -1
  33. data/lib/active_record/turntable/sharding_condition.rb +6 -3
  34. data/lib/active_record/turntable/util.rb +16 -1
  35. data/lib/active_record/turntable/version.rb +1 -1
  36. metadata +16 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 31aa02feae321af087a80d9a1f9177c0ff7c139a
4
- data.tar.gz: dbb3b7404067e3a2b756b96eaa5f76a51e27450d
2
+ SHA256:
3
+ metadata.gz: 4cced005d4106f1fe4e91d38fa233de92139928169754bb96303ab14e11e731b
4
+ data.tar.gz: 80e4e77bcc89380430968ee18b5831667db76ca0872c734879456f9b9aacccdf
5
5
  SHA512:
6
- metadata.gz: 3bb4919921852779beb4b1d31f67f524e5985921c5d00d613799417a769c80eeaf3eec5cd51deaa5ea061cdc0869b8295b785806a5febb2ca7979924482ac79b
7
- data.tar.gz: e5f313cc055e68af9520db17c29edcb717b8459b3ccb65819fe9d17e08010937a938277fc2baafa469b4fb8555a7f8f88a1344cf89064eff3a6d259e2cd6fe12
6
+ metadata.gz: '04769f9f47f94395e4bb5fda699e4807ca992283f5cf2c11abab2cb498757bd8e07ff6062d4cf8f130f6ec3244f65c844347f95adbb5e967555560bca07b4b9d'
7
+ data.tar.gz: 272bcec55c63d01b7488f5c480d0ce7dd77e0bfe57de18e3222736b5d838a53e460bee872e7040a29c6521541201fcfc70fda298bc636f02cf547cf98d995f98
@@ -27,6 +27,7 @@ gemfile:
27
27
  - gemfiles/rails5_1_4.gemfile
28
28
  - gemfiles/rails5_1_5.gemfile
29
29
  - gemfiles/rails5_1_6.gemfile
30
+ - gemfiles/rails5_2_0.gemfile
30
31
  - gemfiles/rails_edge.gemfile
31
32
 
32
33
  env:
@@ -1,3 +1,9 @@
1
+ ## activerecord-turntable 4.2.0 ##
2
+
3
+ ### Major Changes
4
+
5
+ * Support activerecord v5.2.0
6
+
1
7
  ## activerecord-turntable 4.1.0 ##
2
8
 
3
9
  ### Major Changes
data/Gemfile CHANGED
@@ -2,5 +2,8 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "activerecord", "~> 5.1.6"
6
- gem "activesupport", "~> 5.1.6"
5
+ gem "rails", "5.2.0"
6
+
7
+ gem "actionview", "5.2.0"
8
+ gem "activerecord", "5.2.0"
9
+ gem "activesupport", "5.2.0"
data/README.md CHANGED
@@ -27,7 +27,7 @@ MySQL only.
27
27
  Add to Gemfile:
28
28
 
29
29
  ```ruby
30
- gem 'activerecord-turntable', '~> 4.1.0'
30
+ gem 'activerecord-turntable', '~> 4.2.0'
31
31
  ```
32
32
 
33
33
  Run a bundle install:
data/Rakefile CHANGED
@@ -76,7 +76,7 @@ namespace :turntable do
76
76
  system(*%w|git submodule update --init|)
77
77
  system(*%w|git submodule foreach git fetch origin|)
78
78
  Dir.chdir("tmp/rails") do
79
- system(*%W|git checkout #{ENV['ARVERSION']}|)
79
+ system(*%W|git checkout #{ENV["ARVERSION"]}|)
80
80
  end
81
81
  FileUtils.rm_r("test") if File.directory?("test")
82
82
  FileUtils.cp_r("tmp/rails/activerecord/test", ".")
@@ -3,7 +3,7 @@ require "active_record/turntable/version"
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "activerecord-turntable"
5
5
  spec.version = ActiveRecord::Turntable::VERSION
6
- spec.authors = %w(gussan sue445)
6
+ spec.authors = %w[gussan sue445]
7
7
  spec.homepage = "https://github.com/drecom/activerecord-turntable"
8
8
  spec.summary = "ActiveRecord sharding extension"
9
9
  spec.description = "ActiveRecord sharding extension"
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "guard-rspec"
39
39
  spec.add_development_dependency "guard-rubocop"
40
40
  spec.add_development_dependency "httpclient", ">= 0"
41
- spec.add_development_dependency "mysql2"
41
+ spec.add_development_dependency "mysql2", "~> 0.4.4"
42
42
  spec.add_development_dependency "onkcop"
43
43
  spec.add_development_dependency "pry"
44
44
  spec.add_development_dependency "pry-byebug"
@@ -58,7 +58,7 @@ Gem::Specification.new do |spec|
58
58
  # activerecord testing dependencies
59
59
  spec.add_development_dependency "actionview"
60
60
  spec.add_development_dependency "bcrypt", "~> 3.1.11"
61
- spec.add_development_dependency "minitest", "< 5.3.4"
62
- spec.add_development_dependency "mocha", "~> 0.14"
61
+ spec.add_development_dependency "minitest"
62
+ spec.add_development_dependency "mocha"
63
63
  spec.add_development_dependency "sqlite3", "~> 1.3.6"
64
64
  end
@@ -5,4 +5,6 @@ gem "activesupport", "5.0.0"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+
8
10
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.1"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.2"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.3"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.4"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.5"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -5,4 +5,7 @@ gem "activesupport", "5.0.6"
5
5
 
6
6
  gem "mysql2", "~> 0.4.4"
7
7
 
8
+ gem "minitest", "< 5.3.4"
9
+ gem "mocha", "~> 0.14", require: false
10
+
8
11
  gemspec :path => '../'
@@ -3,4 +3,7 @@ source "https://rubygems.org"
3
3
  gem "activerecord", "5.0.7"
4
4
  gem "activesupport", "5.0.7"
5
5
 
6
+ gem "minitest", "< 5.3.4"
7
+ gem "mocha", "~> 0.14", require: false
8
+
6
9
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.0"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.1"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.2"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.3"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.4"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -6,4 +6,7 @@ gem "actionview", "5.1.5"
6
6
 
7
7
  gem "mysql2", "~> 0.4.4"
8
8
 
9
+ gem "minitest", "< 5.3.4"
10
+ gem "mocha", "~> 0.14", require: false
11
+
9
12
  gemspec :path => '../'
@@ -4,4 +4,7 @@ gem "activerecord", "5.1.6"
4
4
  gem "activesupport", "5.1.6"
5
5
  gem "actionview", "5.1.6"
6
6
 
7
+ gem "minitest", "< 5.3.4"
8
+ gem "mocha", "~> 0.14", require: false
9
+
7
10
  gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "5.2.0"
4
+ gem "railties", "5.2.0"
5
+ gem "activerecord", "5.2.0"
6
+ gem "activesupport", "5.2.0"
7
+ gem "actionview", "5.2.0"
8
+
9
+ gemspec :path => '../'
@@ -23,6 +23,28 @@ module ActiveRecord::Turntable
23
23
 
24
24
  # @note override for append current shard name
25
25
  # rubocop:disable Style/HashSyntax, Style/MultilineMethodCallBraceLayout
26
+ module V5_2
27
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
28
+ @instrumenter.instrument(
29
+ "sql.active_record",
30
+ sql: sql,
31
+ name: name,
32
+ binds: binds,
33
+ type_casted_binds: type_casted_binds,
34
+ statement_name: statement_name,
35
+ connection_id: object_id,
36
+ turntable_shard_name: turntable_shard_name) do
37
+ begin
38
+ @lock.synchronize do
39
+ yield
40
+ end
41
+ rescue => e
42
+ raise translate_exception_class(e, sql)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
26
48
  module V5_1
27
49
  def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
28
50
  @instrumenter.instrument(
@@ -24,8 +24,14 @@ module ActiveRecord::Turntable
24
24
 
25
25
  private
26
26
 
27
- def skip_statement_cache?
28
- super || should_use_shard_key?
27
+ if Util.ar52_or_later?
28
+ def skip_statement_cache?(scope)
29
+ super || should_use_shard_key?
30
+ end
31
+ else
32
+ def skip_statement_cache?
33
+ super || should_use_shard_key?
34
+ end
29
35
  end
30
36
  end
31
37
  end
@@ -4,14 +4,24 @@ module ActiveRecord::Turntable
4
4
  module ActiveRecordExt
5
5
  module AssociationPreloader
6
6
  include ShardingCondition
7
+ if Util.ar52_or_later?
8
+ def build_scope
9
+ returning_scope = super
10
+ if should_use_shard_key?
11
+ returning_scope = returning_scope.where(klass.turntable_shard_key => owners.map(&foreign_shard_key.to_sym).uniq)
12
+ end
13
+ returning_scope
7
14
 
8
- # @note Override to add sharding condition on preload
9
- def records_for(ids)
10
- returning_scope = super
11
- if should_use_shard_key?
12
- returning_scope = returning_scope.where(klass.turntable_shard_key => owners.map(&foreign_shard_key.to_sym).uniq)
13
15
  end
14
- returning_scope
16
+ else
17
+ # @note Override to add sharding condition on preload
18
+ def records_for(ids)
19
+ returning_scope = super
20
+ if should_use_shard_key?
21
+ returning_scope = returning_scope.where(klass.turntable_shard_key => owners.map(&foreign_shard_key.to_sym).uniq)
22
+ end
23
+ returning_scope
24
+ end
15
25
  end
16
26
  end
17
27
  end
@@ -9,63 +9,65 @@ module ActiveRecord
9
9
  extend ActiveRecord::Turntable::Util
10
10
 
11
11
  # rubocop:disable Style/MultilineMethodCallBraceLayout
12
- def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
13
- fixture_set_names = Array(fixture_set_names).map(&:to_s)
14
- class_names = ClassCache.new class_names, config
15
-
16
- # FIXME: Apparently JK uses this.
17
- connection = block_given? ? yield : ActiveRecord::Base.connection
18
-
19
- files_to_read = fixture_set_names.reject { |fs_name|
20
- fixture_is_cached?(connection, fs_name)
21
- }
22
-
23
- unless files_to_read.empty?
24
- connection.disable_referential_integrity do
25
- fixtures_map = {}
26
-
27
- fixture_sets = files_to_read.map do |fs_name|
28
- klass = class_names[fs_name]
29
- conn = klass ? klass.connection : connection
30
- fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
31
- conn,
32
- fs_name,
33
- klass,
34
- ::File.join(fixtures_directory, fs_name))
35
- end
12
+ unless ar52_or_later?
13
+ def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
14
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
15
+ class_names = ClassCache.new class_names, config
16
+
17
+ # FIXME: Apparently JK uses this.
18
+ connection = block_given? ? yield : ActiveRecord::Base.connection
19
+
20
+ files_to_read = fixture_set_names.reject { |fs_name|
21
+ fixture_is_cached?(connection, fs_name)
22
+ }
23
+
24
+ unless files_to_read.empty?
25
+ connection.disable_referential_integrity do
26
+ fixtures_map = {}
27
+
28
+ fixture_sets = files_to_read.map do |fs_name|
29
+ klass = class_names[fs_name]
30
+ conn = klass ? klass.connection : connection
31
+ fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
32
+ conn,
33
+ fs_name,
34
+ klass,
35
+ ::File.join(fixtures_directory, fs_name))
36
+ end
36
37
 
37
- update_all_loaded_fixtures fixtures_map
38
+ update_all_loaded_fixtures fixtures_map
38
39
 
39
- ActiveRecord::Base.force_transaction_all_shards!(requires_new: true) do
40
- deleted_tables = Hash.new { |h, k| h[k] = Set.new }
41
- fixture_sets.each do |fs|
42
- conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
43
- table_rows = fs.table_rows
40
+ ActiveRecord::Base.force_transaction_all_shards!(requires_new: true) do
41
+ deleted_tables = Hash.new { |h, k| h[k] = Set.new }
42
+ fixture_sets.each do |fs|
43
+ conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
44
+ table_rows = fs.table_rows
44
45
 
45
- table_rows.each_key do |table|
46
- unless deleted_tables[conn].include? table
47
- conn.delete "DELETE FROM #{conn.quote_table_name(table)}", "Fixture Delete"
46
+ table_rows.each_key do |table|
47
+ unless deleted_tables[conn].include? table
48
+ conn.delete "DELETE FROM #{conn.quote_table_name(table)}", "Fixture Delete"
49
+ end
50
+ deleted_tables[conn] << table
48
51
  end
49
- deleted_tables[conn] << table
50
- end
51
52
 
52
- table_rows.each do |fixture_set_name, rows|
53
- rows.each do |row|
54
- conn.insert_fixture(row, fixture_set_name)
53
+ table_rows.each do |fixture_set_name, rows|
54
+ rows.each do |row|
55
+ conn.insert_fixture(row, fixture_set_name)
56
+ end
55
57
  end
56
- end
57
58
 
58
- # Cap primary key sequences to max(pk).
59
- if connection.respond_to?(:reset_pk_sequence!)
60
- connection.reset_pk_sequence!(fs.table_name)
59
+ # Cap primary key sequences to max(pk).
60
+ if connection.respond_to?(:reset_pk_sequence!)
61
+ connection.reset_pk_sequence!(fs.table_name)
62
+ end
61
63
  end
62
64
  end
63
- end
64
65
 
65
- cache_fixtures(connection, fixtures_map)
66
+ cache_fixtures(connection, fixtures_map)
67
+ end
66
68
  end
69
+ cached_fixtures(connection, fixture_set_names)
67
70
  end
68
- cached_fixtures(connection, fixture_set_names)
69
71
  end
70
72
  # rubocop:enable Style/MultilineMethodCallLayout
71
73
  end
@@ -4,6 +4,7 @@ module ActiveRecord::Turntable
4
4
  if Util.ar_version_equals_or_later?("5.1.6")
5
5
  ::ActiveRecord::Locking::Optimistic.class_eval <<-EOD
6
6
  private
7
+
7
8
  def _update_row(attribute_names, attempted_action = "update")
8
9
  return super unless locking_enabled?
9
10
 
@@ -22,10 +23,17 @@ module ActiveRecord::Turntable
22
23
  constraints[self.class.turntable_shard_key] = self[self.class.turntable_shard_key]
23
24
  end
24
25
 
25
- affected_rows = self.class.unscoped._update_record(
26
- arel_attributes_with_values(attribute_names),
27
- constraints,
28
- )
26
+ if Util.ar52_or_later?
27
+ affected_rows = self.class._update_record(
28
+ attributes_with_values(attribute_names),
29
+ constraints,
30
+ )
31
+ else
32
+ affected_rows = self.class.unscoped._update_record(
33
+ arel_attributes_with_values(attribute_names),
34
+ constraints,
35
+ )
36
+ end
29
37
 
30
38
  if affected_rows != 1
31
39
  raise ActiveRecord::StaleObjectError.new(self, attempted_action)
@@ -40,8 +48,7 @@ module ActiveRecord::Turntable
40
48
  end
41
49
  end
42
50
  EOD
43
-
44
- elsif Util.ar51_or_later?
51
+ elsif Util.ar51?
45
52
  ::ActiveRecord::Locking::Optimistic.class_eval <<-EOD
46
53
  private
47
54
  # @note Override to add sharding condition on optimistic locking
@@ -91,7 +98,7 @@ module ActiveRecord::Turntable
91
98
  end
92
99
  end
93
100
  EOD
94
- else
101
+ elsif Util.earlier_than_ar51?
95
102
  ::ActiveRecord::Locking::Optimistic.class_eval <<-EOD
96
103
  private
97
104
  # @note Override to add sharding condition on optimistic locking
@@ -2,6 +2,7 @@ module ActiveRecord::Turntable
2
2
  module ActiveRecordExt
3
3
  module Persistence
4
4
  extend ActiveSupport::Concern
5
+ extend Compatibility
5
6
 
6
7
  ::ActiveRecord::Persistence.class_eval do
7
8
  # @note Override to add sharding scope on reloading
@@ -77,45 +78,61 @@ module ActiveRecord::Turntable
77
78
  true
78
79
  end
79
80
  end
81
+ # rubocop:enable Style/UnlessElse
80
82
  end
81
- # rubocop:enable Style/UnlessElse
82
83
 
83
84
  # @note Override to add sharding scope on `update_columns`
84
- def update_columns(attributes)
85
- raise ActiveRecord::ActiveRecordError, "cannot update a new record" if new_record?
86
- raise ActiveRecord::ActiveRecordError, "cannot update a destroyed record" if destroyed?
85
+ if Util.ar52_or_later?
86
+ def update_columns(attributes)
87
+ raise ActiveRecord::ActiveRecordError, "cannot update a new record" if new_record?
88
+ raise ActiveRecord::ActiveRecordError, "cannot update a destroyed record" if destroyed?
87
89
 
88
- attributes.each_key do |key|
89
- verify_readonly_attribute(key.to_s)
90
- end
90
+ attributes.each_key do |key|
91
+ verify_readonly_attribute(key.to_s)
92
+ end
91
93
 
92
- update_scope = if turntable_enabled? && self.class.primary_key != self.class.turntable_shard_key.to_s
93
- self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
94
- else
95
- self.class.unscoped
96
- end
94
+ constraints = { self.class.primary_key => id_in_database }
95
+ if self.class.sharding_condition_needed?
96
+ constraints[self.class.turntable_shard_key] = self[self.class.turntable_shard_key]
97
+ end
98
+
99
+ affected_rows = self.class._update_record(
100
+ attributes,
101
+ constraints,
102
+ )
97
103
 
98
- updated_count = update_scope.where(self.class.primary_key => id).update_all(attributes)
104
+ attributes.each do |k, v|
105
+ write_attribute_without_type_cast(k, v)
106
+ end
99
107
 
100
- attributes.each do |k, v|
101
- raw_write_attribute(k, v)
108
+ affected_rows == 1
102
109
  end
110
+ else
111
+ def update_columns(attributes)
112
+ raise ActiveRecord::ActiveRecordError, "cannot update a new record" if new_record?
113
+ raise ActiveRecord::ActiveRecordError, "cannot update a destroyed record" if destroyed?
103
114
 
104
- updated_count == 1
105
- end
115
+ attributes.each_key do |key|
116
+ verify_readonly_attribute(key.to_s)
117
+ end
106
118
 
107
- private
119
+ update_scope = if turntable_enabled? && self.class.primary_key != self.class.turntable_shard_key.to_s
120
+ self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
121
+ else
122
+ self.class.unscoped
123
+ end
108
124
 
109
- # @note Override to add sharding scope on destroying
110
- def relation_for_destroy
111
- klass = self.class
112
- relation = klass.unscoped.where(klass.primary_key => id)
125
+ updated_count = update_scope.where(self.class.primary_key => id).update_all(attributes)
113
126
 
114
- if klass.turntable_enabled? && klass.primary_key != klass.turntable_shard_key.to_s
115
- relation = relation.where(klass.turntable_shard_key => self[klass.turntable_shard_key])
127
+ attributes.each do |k, v|
128
+ raw_write_attribute(k, v)
116
129
  end
117
- relation
130
+
131
+ updated_count == 1
118
132
  end
133
+ end
134
+
135
+ private
119
136
 
120
137
  if Util.ar_version_equals_or_later?("5.1.6")
121
138
  def _update_row(attribute_names, attempted_action = "update")
@@ -124,12 +141,38 @@ module ActiveRecord::Turntable
124
141
  constraints[self.class.turntable_shard_key] = self[self.class.turntable_shard_key]
125
142
  end
126
143
 
144
+ attributes = Util.ar52_or_later? ? attributes_with_values(attribute_names) : arel_attributes_with_values(attribute_names)
145
+
127
146
  self.class.unscoped._update_record(
128
- arel_attributes_with_values(attribute_names),
147
+ attributes,
129
148
  constraints,
130
149
  )
131
150
  end
151
+ end
152
+
153
+ if Util.ar52_or_later?
154
+ def _delete_row
155
+ constraints = { self.class.primary_key => id_in_database }
156
+ if self.class.sharding_condition_needed?
157
+ constraints[self.class.turntable_shard_key] = self[self.class.turntable_shard_key]
158
+ end
159
+
160
+ self.class._delete_record(constraints)
161
+ end
132
162
  else
163
+ # @note Override to add sharding scope on destroying
164
+ def relation_for_destroy
165
+ klass = self.class
166
+ relation = klass.unscoped.where(klass.primary_key => id)
167
+
168
+ if klass.turntable_enabled? && klass.primary_key != klass.turntable_shard_key.to_s
169
+ relation = relation.where(klass.turntable_shard_key => self[klass.turntable_shard_key])
170
+ end
171
+ relation
172
+ end
173
+ end
174
+
175
+ if Util.ar_version_earlier_than?("5.1.6")
133
176
  # @note Override to add sharding scope on updating
134
177
  def _update_record(attribute_names = self.attribute_names)
135
178
  klass = self.class
@@ -10,6 +10,9 @@ module ActiveRecord::Turntable
10
10
  module ClassMethods
11
11
  extend Compatibility
12
12
 
13
+ module V5_2
14
+ end
15
+
13
16
  module V5_1
14
17
  def run
15
18
  result = super
@@ -7,7 +7,11 @@ module ActiveRecord::Turntable::Migration
7
7
  class_attribute :target_shards, :current_shard
8
8
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.include(SchemaStatementsExt)
9
9
  ::ActiveRecord::Migration::CommandRecorder.include(CommandRecorder)
10
- ::ActiveRecord::Migrator.prepend(Migrator)
10
+ if ActiveRecord::Turntable::Util.ar52_or_later?
11
+ ::ActiveRecord::MigrationContext.prepend(MigrationContext)
12
+ else
13
+ ::ActiveRecord::Migrator.prepend(Migrator)
14
+ end
11
15
  end
12
16
 
13
17
  module ShardDefinition
@@ -89,6 +93,43 @@ module ActiveRecord::Turntable::Migration
89
93
  end
90
94
  end
91
95
 
96
+ module MigrationContext
97
+ extend ActiveSupport::Concern
98
+
99
+ def up(target_version = nil)
100
+ result = super
101
+
102
+ ActiveRecord::Tasks::DatabaseTasks.each_current_turntable_cluster_connected(current_environment) do |name, configuration|
103
+ puts "[turntable] *** Migrating database: #{configuration['database']}(Shard: #{name})"
104
+ super(target_version)
105
+ end
106
+
107
+ result
108
+ end
109
+
110
+ def down(target_version = nil)
111
+ result = super
112
+
113
+ ActiveRecord::Tasks::DatabaseTasks.each_current_turntable_cluster_connected(current_environment) do |name, configuration|
114
+ puts "[turntable] *** Migrating database: #{configuration['database']}(Shard: #{name})"
115
+ super(target_version)
116
+ end
117
+
118
+ result
119
+ end
120
+
121
+ def run(direction, target_version)
122
+ result = super
123
+
124
+ ActiveRecord::Tasks::DatabaseTasks.each_current_turntable_cluster_connected(current_environment) do |name, configuration|
125
+ puts "[turntable] *** Migrating database: #{configuration['database']}(Shard: #{name})"
126
+ super(target_version)
127
+ end
128
+
129
+ result
130
+ end
131
+ end
132
+
92
133
  module Migrator
93
134
  extend ActiveSupport::Concern
94
135
 
@@ -12,7 +12,7 @@ module ActiveRecord::Turntable
12
12
  end
13
13
 
14
14
  delegate :connected?, :automatic_reconnect, :automatic_reconnect=, :checkout_timeout, :dead_connection_timeout,
15
- :spec, :connections, :size, :reaper, :table_exists?, to: :proxy
15
+ :spec, :connections, :size, :reaper, :table_exists?, :query_cache_enabled, :enable_query_cache!, to: :proxy
16
16
 
17
17
  %w(columns_hash column_defaults primary_keys).each do |name|
18
18
  define_method(name.to_sym) do
@@ -42,6 +42,10 @@ module ActiveRecord::Turntable
42
42
  end
43
43
  end
44
44
 
45
+ def discard!
46
+ # Nothing to do
47
+ end
48
+
45
49
  private
46
50
 
47
51
  def connection_pools_list
@@ -3,15 +3,18 @@ module ActiveRecord::Turntable
3
3
  private
4
4
 
5
5
  def foreign_shard_key
6
- options[:foreign_shard_key] || foreign_target_model.turntable_shard_key
6
+ reflection.options[:foreign_shard_key] || foreign_target_model.turntable_shard_key
7
7
  end
8
8
 
9
9
  def foreign_target_model
10
- respond_to?(:model) ? model : owner
10
+ return model if respond_to?(:model)
11
+ return @model if instance_variable_defined?(:@model) && @model
12
+
13
+ owner
11
14
  end
12
15
 
13
16
  def should_use_shard_key?
14
- sharded_by_same_key? || !!options[:foreign_shard_key]
17
+ sharded_by_same_key? || !!reflection.options[:foreign_shard_key]
15
18
  end
16
19
 
17
20
  def sharded_by_same_key?
@@ -19,14 +19,29 @@ module ActiveRecord::Turntable
19
19
  requirement.satisfied_by?(ar_version)
20
20
  end
21
21
 
22
+ def ar51?
23
+ ar51_or_later? && !ar52_or_later?
24
+ end
25
+
22
26
  def ar51_or_later?
23
27
  ar_version_equals_or_later?("5.1")
24
28
  end
25
29
 
30
+ def earlier_than_ar51?
31
+ ar_version_earlier_than?("5.1")
32
+ end
33
+
34
+ def ar52_or_later?
35
+ ar_version_equals_or_later?("5.2")
36
+ end
37
+
26
38
  module_function :ar_version_equals_or_later?,
27
39
  :ar_version_earlier_than?,
28
40
  :ar_version,
29
41
  :ar_version_satisfy?,
30
- :ar51_or_later?
42
+ :ar51?,
43
+ :earlier_than_ar51?,
44
+ :ar51_or_later?,
45
+ :ar52_or_later?
31
46
  end
32
47
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Turntable
3
- VERSION = "4.1.0".freeze
3
+ VERSION = "4.2.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-turntable
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - gussan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-04-24 00:00:00.000000000 Z
12
+ date: 2018-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -209,16 +209,16 @@ dependencies:
209
209
  name: mysql2
210
210
  requirement: !ruby/object:Gem::Requirement
211
211
  requirements:
212
- - - ">="
212
+ - - "~>"
213
213
  - !ruby/object:Gem::Version
214
- version: '0'
214
+ version: 0.4.4
215
215
  type: :development
216
216
  prerelease: false
217
217
  version_requirements: !ruby/object:Gem::Requirement
218
218
  requirements:
219
- - - ">="
219
+ - - "~>"
220
220
  - !ruby/object:Gem::Version
221
- version: '0'
221
+ version: 0.4.4
222
222
  - !ruby/object:Gem::Dependency
223
223
  name: onkcop
224
224
  requirement: !ruby/object:Gem::Requirement
@@ -461,30 +461,30 @@ dependencies:
461
461
  name: minitest
462
462
  requirement: !ruby/object:Gem::Requirement
463
463
  requirements:
464
- - - "<"
464
+ - - ">="
465
465
  - !ruby/object:Gem::Version
466
- version: 5.3.4
466
+ version: '0'
467
467
  type: :development
468
468
  prerelease: false
469
469
  version_requirements: !ruby/object:Gem::Requirement
470
470
  requirements:
471
- - - "<"
471
+ - - ">="
472
472
  - !ruby/object:Gem::Version
473
- version: 5.3.4
473
+ version: '0'
474
474
  - !ruby/object:Gem::Dependency
475
475
  name: mocha
476
476
  requirement: !ruby/object:Gem::Requirement
477
477
  requirements:
478
- - - "~>"
478
+ - - ">="
479
479
  - !ruby/object:Gem::Version
480
- version: '0.14'
480
+ version: '0'
481
481
  type: :development
482
482
  prerelease: false
483
483
  version_requirements: !ruby/object:Gem::Requirement
484
484
  requirements:
485
- - - "~>"
485
+ - - ">="
486
486
  - !ruby/object:Gem::Version
487
- version: '0.14'
487
+ version: '0'
488
488
  - !ruby/object:Gem::Dependency
489
489
  name: sqlite3
490
490
  requirement: !ruby/object:Gem::Requirement
@@ -538,6 +538,7 @@ files:
538
538
  - gemfiles/rails5_1_4.gemfile
539
539
  - gemfiles/rails5_1_5.gemfile
540
540
  - gemfiles/rails5_1_6.gemfile
541
+ - gemfiles/rails5_2_0.gemfile
541
542
  - gemfiles/rails_edge.gemfile
542
543
  - lib/active_record/turntable.rb
543
544
  - lib/active_record/turntable/active_record_ext.rb
@@ -635,7 +636,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
635
636
  version: '0'
636
637
  requirements: []
637
638
  rubyforge_project: activerecord-turntable
638
- rubygems_version: 2.6.14
639
+ rubygems_version: 2.7.6
639
640
  signing_key:
640
641
  specification_version: 4
641
642
  summary: ActiveRecord sharding extension