activerecord-turntable 2.1.0.beta1 → 2.1.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd8da73b8e0ac2f22797a0eb070c3624038b2ea3
4
- data.tar.gz: 57b762fbd0ef0d06c5f7562c4cf68d5cc3c8f8bb
3
+ metadata.gz: c2673c7fcde5190f1b2da9ac7d398ebf0e3faf1a
4
+ data.tar.gz: 40fa47723f339d79d3846aaa90aabccdc0232337
5
5
  SHA512:
6
- metadata.gz: 74cb71bdcd32cca8731ce965b5fd7d0e8b8dd9d7bde6484abb6aa83021d530c3a54ac22d33c73bc2bb8d7c491a0401562b827e78eef3e56eb3bb5e6a56121f8e
7
- data.tar.gz: 8ffc60cb0b0dd8e4428f4b3d76690a6135eeb2c60bf5bb0a7ffb0c8655e0be7a835c72bfa8580841c46b0a44bb60d57f88b04d7a48ae7b54ea620cc44f5bc909
6
+ metadata.gz: b79b1ecdbea938ab801be102982441244841af16ff2c83fd4bc1a003f10ec000adc95480a40ac2e743ddd10a9d8ad9d7a84ae12aecb70abe1d4be68ee3783f6c
7
+ data.tar.gz: 1b35bfd21a4a4bfa04506375785f3e1496eb03f1ab209776d03295deab494ea9983e6bc523341d83df8577da82272190e11c8de0d8511aa3b998142ae98800bc
@@ -8,9 +8,19 @@ require 'active_record'
8
8
  require 'active_record/fixtures'
9
9
  require 'active_support/concern'
10
10
  require 'active_record/turntable/error'
11
+ require 'active_record/turntable/util'
11
12
  require 'logger'
12
13
  require 'singleton'
13
14
 
15
+ # for 4.0.x series
16
+ module ActiveRecord
17
+ unless respond_to?(:gem_version)
18
+ class << self
19
+ alias_method :gem_version, :version
20
+ end
21
+ end
22
+ end
23
+
14
24
  module ActiveRecord::Turntable
15
25
  extend ActiveSupport::Concern
16
26
  extend ActiveSupport::Autoload
@@ -57,17 +67,5 @@ module ActiveRecord::Turntable
57
67
  end
58
68
  end
59
69
 
60
- def self.rails4?
61
- ActiveRecord::VERSION::MAJOR == 4
62
- end
63
-
64
- def self.rails41_later?
65
- rails4? && ActiveRecord::VERSION::MINOR >= 1
66
- end
67
-
68
- def self.rails42_later?
69
- rails4? && ActiveRecord::VERSION::MINOR >= 2
70
- end
71
-
72
70
  require "active_record/turntable/railtie" if defined?(Rails)
73
71
  end
@@ -17,7 +17,7 @@ module ActiveRecord::Turntable
17
17
  :turntable_shard_name => turntable_shard_name) { yield }
18
18
  rescue Exception => e
19
19
  message = "#{e.class.name}: #{e.message}: #{sql} : #{turntable_shard_name}"
20
- @logger.debug message if @logger
20
+ @logger.error message if @logger
21
21
  exception = translate_exception(e, message)
22
22
  exception.set_backtrace e.backtrace
23
23
  raise exception
@@ -24,7 +24,7 @@ module ActiveRecord::Turntable
24
24
  extend ActiveSupport::Concern
25
25
 
26
26
  included do
27
- if ActiveRecord::Turntable.rails42_later?
27
+ if Util.ar42_or_later?
28
28
  alias_method_chain :get_records, :turntable
29
29
  else
30
30
  alias_method_chain :find_target, :turntable
@@ -32,7 +32,7 @@ module ActiveRecord::Turntable
32
32
  end
33
33
 
34
34
  # @note Override to add sharding condition for singular association
35
- if ActiveRecord::Turntable.rails42_later?
35
+ if Util.ar42_or_later?
36
36
  def get_records_with_turntable
37
37
  if reflection.scope_chain.any?(&:any?) ||
38
38
  scope.eager_loading? ||
@@ -54,7 +54,7 @@ module ActiveRecord::Turntable
54
54
  binds = ActiveRecord::Associations::AssociationScope.get_bind_values(owner, reflection.chain)
55
55
  sc.execute binds, klass, klass.connection
56
56
  end
57
- elsif ActiveRecord::Turntable.rails41_later?
57
+ elsif Util.ar41_or_later?
58
58
  def find_target_with_turntable
59
59
  if record = turntable_scope(scope).take
60
60
  set_inverse_instance record
@@ -71,7 +71,7 @@ module ActiveRecord::Turntable
71
71
  extend ActiveSupport::Concern
72
72
 
73
73
  included do
74
- if ActiveRecord::Turntable.rails42_later?
74
+ if Util.ar42_or_later?
75
75
  alias_method_chain :get_records, :turntable
76
76
  else
77
77
  alias_method_chain :find_target, :turntable
@@ -80,7 +80,7 @@ module ActiveRecord::Turntable
80
80
 
81
81
  private
82
82
 
83
- if ActiveRecord::Turntable.rails42_later?
83
+ if Util.ar42_or_later?
84
84
  def get_records_with_turntable
85
85
  if reflection.scope_chain.any?(&:any?) ||
86
86
  scope.eager_loading? ||
@@ -1,48 +1,50 @@
1
- module ActiveRecord::Turntable::ActiveRecordExt
2
- module CleverLoad
3
- extend ActiveSupport::Concern
1
+ module ActiveRecord::Turntable
2
+ module ActiveRecordExt
3
+ module CleverLoad
4
+ extend ActiveSupport::Concern
4
5
 
5
- included do
6
- class << ActiveRecord::Base
7
- delegate :clever_load!, :to => :all
6
+ included do
7
+ class << ActiveRecord::Base
8
+ delegate :clever_load!, :to => :all
9
+ end
8
10
  end
9
- end
10
11
 
11
- def clever_load!(association_name)
12
- # load records
13
- records = self.to_a
14
- klass = records.first.class
15
- association_key = ActiveRecord::Turntable.rails42_later? ? association_name.to_s : association_name
16
- reflection = klass.reflections[association_key]
12
+ def clever_load!(association_name)
13
+ # load records
14
+ records = self.to_a
15
+ klass = records.first.class
16
+ association_key = Util.ar42_or_later? ? association_name.to_s : association_name
17
+ reflection = klass.reflections[association_key]
17
18
 
18
- if reflection
19
- foreign_class = reflection.klass
20
- foreign_objects = case reflection.macro
21
- when :has_one
22
- foreign_class.where(reflection.foreign_key => records.map(&reflection.association_primary_key.to_sym).uniq)
23
- when :belongs_to
24
- foreign_class.where(reflection.association_primary_key => records.map(&reflection.foreign_key.to_sym).uniq)
25
- else
26
- []
27
- end
19
+ if reflection
20
+ foreign_class = reflection.klass
21
+ foreign_objects = case reflection.macro
22
+ when :has_one
23
+ foreign_class.where(reflection.foreign_key => records.map(&reflection.association_primary_key.to_sym).uniq)
24
+ when :belongs_to
25
+ foreign_class.where(reflection.association_primary_key => records.map(&reflection.foreign_key.to_sym).uniq)
26
+ else
27
+ []
28
+ end
28
29
 
29
- self.each do |obj|
30
- matched_object = case reflection.macro
31
- when :has_one
32
- foreign_objects.find {|fo|
33
- obj.send(reflection.association_primary_key) == fo.send(reflection.foreign_key)
34
- }
35
- when :belongs_to
36
- foreign_objects.find {|fo|
37
- obj.send(reflection.foreign_key) == fo.send(reflection.association_primary_key)
38
- }
39
- end
40
- obj.association(association_name).target = matched_object
41
- obj.association(association_name).set_inverse_instance(matched_object) if matched_object
42
- obj.association(association_name).loaded!
30
+ self.each do |obj|
31
+ matched_object = case reflection.macro
32
+ when :has_one
33
+ foreign_objects.find {|fo|
34
+ obj.send(reflection.association_primary_key) == fo.send(reflection.foreign_key)
35
+ }
36
+ when :belongs_to
37
+ foreign_objects.find {|fo|
38
+ obj.send(reflection.foreign_key) == fo.send(reflection.association_primary_key)
39
+ }
40
+ end
41
+ obj.association(association_name).target = matched_object
42
+ obj.association(association_name).set_inverse_instance(matched_object) if matched_object
43
+ obj.association(association_name).loaded!
44
+ end
43
45
  end
46
+ records
44
47
  end
45
- records
46
48
  end
47
49
  end
48
50
  end
@@ -4,9 +4,9 @@
4
4
  require 'active_record/fixtures'
5
5
  module ActiveRecord
6
6
  class FixtureSet
7
- def self.create_fixtures(fixtures_directory, table_names, class_names = {}, config = ActiveRecord::Base)
7
+ def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
8
8
  fixture_set_names = Array(fixture_set_names).map(&:to_s)
9
- class_names = class_names.stringify_keys
9
+ class_names = ClassCache.new class_names, config
10
10
 
11
11
  # FIXME: Apparently JK uses this.
12
12
  connection = block_given? ? yield : ActiveRecord::Base.connection
@@ -20,21 +20,23 @@ module ActiveRecord
20
20
  fixtures_map = {}
21
21
 
22
22
  fixture_sets = files_to_read.map do |fs_name|
23
+ klass = class_names[fs_name]
24
+ conn = klass ? klass.connection : connection
23
25
  fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
24
- connection,
26
+ conn,
25
27
  fs_name,
26
- class_names[fs_name] || default_fixture_model_name(fs_name),
28
+ klass,
27
29
  ::File.join(fixtures_directory, fs_name))
28
30
  end
29
31
 
30
- all_loaded_fixtures.update(fixtures_map)
32
+ update_all_loaded_fixtures fixtures_map
31
33
 
32
34
  ActiveRecord::Turntable::Base.force_transaction_all_shards!(:requires_new => true) do
33
35
  fixture_sets.each do |fs|
34
36
  conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
35
37
  table_rows = fs.table_rows
36
38
 
37
- table_rows.keys.each do |table|
39
+ table_rows.each_key do |table|
38
40
  conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
39
41
  end
40
42
 
@@ -61,6 +63,8 @@ module ActiveRecord
61
63
  end
62
64
 
63
65
  module TestFixtures
66
+ extend ActiveRecord::Turntable::Util
67
+
64
68
  def setup_fixtures(config = ActiveRecord::Base)
65
69
  return unless !ActiveRecord::Base.configurations.blank?
66
70
 
@@ -101,43 +105,22 @@ module ActiveRecord
101
105
  ActiveRecord::Base.turntable_connections.values.map(&:connection)
102
106
  end
103
107
 
104
- def teardown_fixtures
105
- return if ActiveRecord::Base.configurations.blank?
106
-
107
- # Rollback changes if a transaction is active.
108
- if run_in_transaction?
109
- @fixture_connections.each do |connection|
110
- connection.rollback_transaction if connection.transaction_open?
111
- end
112
- @fixture_connections.clear
113
- else
114
- ActiveRecord::FixtureSet.reset_cache
115
- end
116
-
117
- ActiveRecord::Base.clear_active_connections!
118
- end
119
-
120
108
  private
121
109
 
122
110
  def turntable_load_fixtures(config)
123
- if ActiveRecord::Turntable.rails41_later?
111
+ if ar41_or_later?
124
112
  load_fixtures(config)
125
- elsif ActiveRecord::Turntable.rails4?
126
- load_fixtures
127
113
  else
128
- raise NotImplementedError
114
+ load_fixtures
129
115
  end
130
116
  end
131
117
 
132
118
  def turntable_instantiate_fixtures(config)
133
- if ActiveRecord::Turntable.rails41_later?
119
+ if ar41_or_later?
134
120
  instantiate_fixtures(config)
135
- elsif ActiveRecord::Turntable.rails4?
136
- instantiate_fixtures
137
121
  else
138
- raise NotImplementedError
122
+ instantiate_fixtures
139
123
  end
140
124
  end
141
-
142
125
  end
143
126
  end
@@ -1,158 +1,160 @@
1
- module ActiveRecord::Turntable::ActiveRecordExt
2
- module LockingOptimistic
3
- # @note Override to add sharding condition on optimistic locking
4
- ::ActiveRecord::Locking::Optimistic.class_eval do
5
-
6
- ar_version = ActiveRecord::VERSION::STRING
7
- if ar_version < "4.1"
8
- method_name = ar_version =~ /\A4\.0\.[0-5]\z/ ? "update_record" : "_update_record"
9
-
10
- class_eval <<-EOD
11
- def #{method_name}(attribute_names = @attributes.keys) #:nodoc:
12
- return super unless locking_enabled?
13
- return 0 if attribute_names.empty?
14
-
15
- klass = self.class
16
- lock_col = self.class.locking_column
17
- previous_lock_value = send(lock_col).to_i
18
- increment_lock
19
-
20
- attribute_names += [lock_col]
21
- attribute_names.uniq!
22
-
23
- begin
24
- relation = self.class.unscoped
25
-
26
- condition_scope = relation.where(
27
- relation.table[self.class.primary_key].eq(id).and(
28
- relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
29
- )
30
- )
31
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
32
- condition_scope = condition_scope.where(
33
- relation.table[klass.turntable_shard_key].eq(
34
- self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
1
+ module ActiveRecord::Turntable
2
+ module ActiveRecordExt
3
+ module LockingOptimistic
4
+ # @note Override to add sharding condition on optimistic locking
5
+ ::ActiveRecord::Locking::Optimistic.class_eval do
6
+
7
+ ar_version = ActiveRecord::VERSION::STRING
8
+ if Util.earlier_than_ar41?
9
+ method_name = Util.ar_version_earlier_than?("4.0.6") ? "update_record" : "_update_record"
10
+
11
+ class_eval <<-EOD
12
+ def #{method_name}(attribute_names = @attributes.keys) #:nodoc:
13
+ return super unless locking_enabled?
14
+ return 0 if attribute_names.empty?
15
+
16
+ klass = self.class
17
+ lock_col = self.class.locking_column
18
+ previous_lock_value = send(lock_col).to_i
19
+ increment_lock
20
+
21
+ attribute_names += [lock_col]
22
+ attribute_names.uniq!
23
+
24
+ begin
25
+ relation = self.class.unscoped
26
+
27
+ condition_scope = relation.where(
28
+ relation.table[self.class.primary_key].eq(id).and(
29
+ relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
35
30
  )
36
31
  )
37
- end
38
- stmt = condition_scope.arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
32
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
33
+ condition_scope = condition_scope.where(
34
+ relation.table[klass.turntable_shard_key].eq(
35
+ self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
36
+ )
37
+ )
38
+ end
39
+ stmt = condition_scope.arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
39
40
 
40
- affected_rows = self.class.connection.update stmt
41
+ affected_rows = self.class.connection.update stmt
41
42
 
42
- unless affected_rows == 1
43
- raise ActiveRecord::StaleObjectError.new(self, "update")
44
- end
43
+ unless affected_rows == 1
44
+ raise ActiveRecord::StaleObjectError.new(self, "update")
45
+ end
45
46
 
46
- affected_rows
47
+ affected_rows
47
48
 
48
- # If something went wrong, revert the version.
49
- rescue Exception
50
- send(lock_col + '=', previous_lock_value)
51
- raise
49
+ # If something went wrong, revert the version.
50
+ rescue Exception
51
+ send(lock_col + '=', previous_lock_value)
52
+ raise
53
+ end
52
54
  end
53
- end
54
- EOD
55
- elsif ar_version < "4.2"
56
- method_name = ar_version =~ /\A4\.1\.[01]\z/ ? "update_record" : "_update_record"
57
-
58
- class_eval <<-EOD
59
- def _update_record(attribute_names = @attributes.keys) #:nodoc:
60
- return super unless locking_enabled?
61
- return 0 if attribute_names.empty?
62
-
63
- klass = self.class
64
- lock_col = self.class.locking_column
65
- previous_lock_value = send(lock_col).to_i
66
- increment_lock
67
-
68
- attribute_names += [lock_col]
69
- attribute_names.uniq!
70
-
71
- begin
72
- relation = self.class.unscoped
73
-
74
- condition_scope = relation.where(
75
- relation.table[self.class.primary_key].eq(id).and(
76
- relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
77
- )
78
- )
79
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
80
- condition_scope = condition_scope.where(
81
- relation.table[klass.turntable_shard_key].eq(
82
- self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
55
+ EOD
56
+ elsif Util.earlier_than_ar42?
57
+ method_name = Util.ar_version_earlier_than?("4.1.2") ? "update_record" : "_update_record"
58
+
59
+ class_eval <<-EOD
60
+ def _update_record(attribute_names = @attributes.keys) #:nodoc:
61
+ return super unless locking_enabled?
62
+ return 0 if attribute_names.empty?
63
+
64
+ klass = self.class
65
+ lock_col = self.class.locking_column
66
+ previous_lock_value = send(lock_col).to_i
67
+ increment_lock
68
+
69
+ attribute_names += [lock_col]
70
+ attribute_names.uniq!
71
+
72
+ begin
73
+ relation = self.class.unscoped
74
+
75
+ condition_scope = relation.where(
76
+ relation.table[self.class.primary_key].eq(id).and(
77
+ relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
83
78
  )
84
79
  )
85
- end
86
- stmt = condition_scope.arel.compile_update(
87
- arel_attributes_with_values_for_update(attribute_names),
88
- self.class.primary_key
89
- )
80
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
81
+ condition_scope = condition_scope.where(
82
+ relation.table[klass.turntable_shard_key].eq(
83
+ self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
84
+ )
85
+ )
86
+ end
87
+ stmt = condition_scope.arel.compile_update(
88
+ arel_attributes_with_values_for_update(attribute_names),
89
+ self.class.primary_key
90
+ )
90
91
 
91
- affected_rows = self.class.connection.update stmt
92
+ affected_rows = self.class.connection.update stmt
92
93
 
93
- unless affected_rows == 1
94
- raise ActiveRecord::StaleObjectError.new(self, "update")
95
- end
94
+ unless affected_rows == 1
95
+ raise ActiveRecord::StaleObjectError.new(self, "update")
96
+ end
96
97
 
97
- affected_rows
98
+ affected_rows
98
99
 
99
- # If something went wrong, revert the version.
100
- rescue Exception
101
- send(lock_col + '=', previous_lock_value)
102
- raise
100
+ # If something went wrong, revert the version.
101
+ rescue Exception
102
+ send(lock_col + '=', previous_lock_value)
103
+ raise
104
+ end
103
105
  end
104
- end
105
- EOD
106
- else
107
- class_eval <<-EOD
108
- def _update_record(attribute_names = self.attribute_names) #:nodoc:
109
- return super unless locking_enabled?
110
- return 0 if attribute_names.empty?
111
-
112
- klass = self.class
113
- lock_col = self.class.locking_column
114
- previous_lock_value = send(lock_col).to_i
115
- increment_lock
116
-
117
- attribute_names += [lock_col]
118
- attribute_names.uniq!
119
-
120
- begin
121
- relation = self.class.unscoped
122
-
123
- condition_scope = relation.where(
124
- relation.table[self.class.primary_key].eq(id).and(
125
- relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
126
- )
127
- )
128
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
129
- condition_scope = condition_scope.where(
130
- relation.table[klass.turntable_shard_key].eq(
131
- self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
106
+ EOD
107
+ else
108
+ class_eval <<-EOD
109
+ def _update_record(attribute_names = self.attribute_names) #:nodoc:
110
+ return super unless locking_enabled?
111
+ return 0 if attribute_names.empty?
112
+
113
+ klass = self.class
114
+ lock_col = self.class.locking_column
115
+ previous_lock_value = send(lock_col).to_i
116
+ increment_lock
117
+
118
+ attribute_names += [lock_col]
119
+ attribute_names.uniq!
120
+
121
+ begin
122
+ relation = self.class.unscoped
123
+
124
+ condition_scope = relation.where(
125
+ relation.table[self.class.primary_key].eq(id).and(
126
+ relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
132
127
  )
133
128
  )
134
- end
129
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
130
+ condition_scope = condition_scope.where(
131
+ relation.table[klass.turntable_shard_key].eq(
132
+ self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
133
+ )
134
+ )
135
+ end
135
136
 
136
- stmt = condition_scope.arel.compile_update(
137
- arel_attributes_with_values_for_update(attribute_names),
138
- self.class.primary_key
139
- )
137
+ stmt = condition_scope.arel.compile_update(
138
+ arel_attributes_with_values_for_update(attribute_names),
139
+ self.class.primary_key
140
+ )
140
141
 
141
- affected_rows = self.class.connection.update stmt
142
+ affected_rows = self.class.connection.update stmt
142
143
 
143
- unless affected_rows == 1
144
- raise ActiveRecord::StaleObjectError.new(self, "update")
145
- end
144
+ unless affected_rows == 1
145
+ raise ActiveRecord::StaleObjectError.new(self, "update")
146
+ end
146
147
 
147
- affected_rows
148
+ affected_rows
148
149
 
149
- # If something went wrong, revert the version.
150
- rescue Exception
151
- send(lock_col + '=', previous_lock_value)
152
- raise
150
+ # If something went wrong, revert the version.
151
+ rescue Exception
152
+ send(lock_col + '=', previous_lock_value)
153
+ raise
154
+ end
153
155
  end
154
- end
155
- EOD
156
+ EOD
157
+ end
156
158
  end
157
159
  end
158
160
  end
@@ -1,182 +1,218 @@
1
- module ActiveRecord::Turntable::ActiveRecordExt
2
- module Persistence
3
- extend ActiveSupport::Concern
4
-
5
- ::ActiveRecord::Persistence.class_eval do
6
- # @note Override to add sharding scope on reloading
7
- def reload(options = nil)
8
- clear_aggregation_cache
9
- clear_association_cache
10
-
11
- finder_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
12
- self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
13
- else
14
- self.class.unscoped
15
- end
16
-
17
- fresh_object =
18
- if options && options[:lock]
19
- finder_scope.lock.find(id)
1
+ module ActiveRecord::Turntable
2
+ module ActiveRecordExt
3
+ module Persistence
4
+ extend ActiveSupport::Concern
5
+
6
+ ::ActiveRecord::Persistence.class_eval do
7
+ # @note Override to add sharding scope on reloading
8
+ def reload(options = nil)
9
+ clear_aggregation_cache
10
+ clear_association_cache
11
+
12
+ finder_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
13
+ self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
14
+ else
15
+ self.class.unscoped
16
+ end
17
+
18
+ fresh_object =
19
+ if options && options[:lock]
20
+ finder_scope.lock.find(id)
21
+ else
22
+ finder_scope.find(id)
23
+ end
24
+
25
+ if Util.ar42_or_later?
26
+ @attributes = fresh_object.instance_variable_get('@attributes')
20
27
  else
21
- finder_scope.find(id)
28
+ @attributes.update(fresh_object.instance_variable_get('@attributes'))
29
+
30
+ @column_types = self.class.column_types
31
+ @column_types_override = fresh_object.instance_variable_get('@column_types_override')
32
+ @attributes_cache = {}
22
33
  end
34
+ @new_record = false
35
+ self
36
+ end
23
37
 
24
- if ActiveRecord::Turntable.rails42_later?
25
- @attributes = fresh_object.instance_variable_get('@attributes')
26
- else
27
- @attributes.update(fresh_object.instance_variable_get('@attributes'))
38
+ # @note Override to add sharding scope on `touch`
39
+ if Util.ar42_or_later?
40
+ def touch(*names)
41
+ raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
28
42
 
29
- @column_types = self.class.column_types
30
- @column_types_override = fresh_object.instance_variable_get('@column_types_override')
31
- @attributes_cache = {}
32
- end
33
- @new_record = false
34
- self
35
- end
43
+ attributes = timestamp_attributes_for_update_in_model
44
+ attributes.concat(names)
45
+
46
+ unless attributes.empty?
47
+ current_time = current_time_from_proper_timezone
48
+ changes = {}
36
49
 
37
- # @note Override to add sharding scope on `touch`
38
- def touch(name = nil)
39
- raise ActiveRecordError, "can not touch on a new record object" unless persisted?
50
+ attributes.each do |column|
51
+ column = column.to_s
52
+ changes[column] = write_attribute(column, current_time)
53
+ end
54
+
55
+ changes[self.class.locking_column] = increment_lock if locking_enabled?
40
56
 
41
- attributes = timestamp_attributes_for_update_in_model
42
- attributes << name if name
57
+ clear_attribute_changes(changes.keys)
58
+ primary_key = self.class.primary_key
43
59
 
44
- unless attributes.empty?
45
- current_time = current_time_from_proper_timezone
46
- changes = {}
60
+ finder_scope = if turntable_enabled? and primary_key != self.class.turntable_shard_key.to_s
61
+ self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
62
+ else
63
+ self.class.unscoped
64
+ end
47
65
 
48
- attributes.each do |column|
49
- column = column.to_s
50
- changes[column] = write_attribute(column, current_time)
66
+ finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
67
+ else
68
+ true
69
+ end
51
70
  end
71
+ else
72
+ def touch(name = nil)
73
+ raise ActiveRecordError, "can not touch on a new record object" unless persisted?
52
74
 
53
- changes[self.class.locking_column] = increment_lock if locking_enabled?
75
+ attributes = timestamp_attributes_for_update_in_model
76
+ attributes << name if name
54
77
 
55
- @changed_attributes.except!(*changes.keys)
56
- primary_key = self.class.primary_key
78
+ unless attributes.empty?
79
+ current_time = current_time_from_proper_timezone
80
+ changes = {}
57
81
 
58
- finder_scope = if turntable_enabled? and primary_key != self.class.turntable_shard_key.to_s
59
- self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
60
- else
61
- self.class.unscoped
62
- end
82
+ attributes.each do |column|
83
+ column = column.to_s
84
+ changes[column] = write_attribute(column, current_time)
85
+ end
63
86
 
64
- finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
65
- else
66
- true
67
- end
68
- end
87
+ changes[self.class.locking_column] = increment_lock if locking_enabled?
88
+
89
+ @changed_attributes.except!(*changes.keys)
90
+ primary_key = self.class.primary_key
69
91
 
70
- # @note Override to add sharding scope on `update_columns`
71
- def update_columns(attributes)
72
- raise ActiveRecordError, "cannot update on a new record object" unless persisted?
92
+ finder_scope = if turntable_enabled? and 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
73
97
 
74
- attributes.each_key do |key|
75
- verify_readonly_attribute(key.to_s)
98
+ finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
99
+ else
100
+ true
101
+ end
102
+ end
76
103
  end
77
104
 
78
- update_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
79
- self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
80
- else
81
- self.class.unscoped
82
- end
105
+ # @note Override to add sharding scope on `update_columns`
106
+ def update_columns(attributes)
107
+ raise ActiveRecordError, "cannot update a new record" if new_record?
108
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
83
109
 
84
- updated_count = update_scope.where(self.class.primary_key => id).update_all(attributes)
110
+ attributes.each_key do |key|
111
+ verify_readonly_attribute(key.to_s)
112
+ end
85
113
 
86
- attributes.each do |k, v|
87
- raw_write_attribute(k, v)
88
- end
114
+ update_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
115
+ self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
116
+ else
117
+ self.class.unscoped
118
+ end
89
119
 
90
- updated_count == 1
91
- end
120
+ updated_count = update_scope.where(self.class.primary_key => id).update_all(attributes)
92
121
 
93
- private
122
+ attributes.each do |k, v|
123
+ raw_write_attribute(k, v)
124
+ end
94
125
 
95
- ar_version = ActiveRecord::VERSION::STRING
126
+ updated_count == 1
127
+ end
128
+
129
+ private
96
130
 
97
- # @note Override to add sharding scope on destroying
98
- if ActiveRecord::Turntable.rails42_later?
99
- def relation_for_destroy
100
- pk = self.class.primary_key
101
- column = self.class.columns_hash[pk]
102
- substitute = self.class.connection.substitute_at(column, 0)
103
- klass = self.class
131
+ # @note Override to add sharding scope on destroying
132
+ if Util.ar42_or_later?
133
+ def relation_for_destroy
134
+ pk = self.class.primary_key
135
+ column = self.class.columns_hash[pk]
136
+ substitute = self.class.connection.substitute_at(column, 0)
137
+ klass = self.class
104
138
 
105
- relation = self.class.unscoped.where(
106
- self.class.arel_table[pk].eq(substitute))
107
- relation.bind_values = [[column, id]]
139
+ relation = self.class.unscoped.where(
140
+ self.class.arel_table[pk].eq(substitute))
141
+ relation.bind_values = [[column, id]]
108
142
 
109
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
110
- shard_key_column = klass.columns_hash[klass.turntable_shard_key]
111
- shard_key_substitute = klass.connection.substitute_at(shard_key_column)
143
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
144
+ shard_key_column = klass.columns_hash[klass.turntable_shard_key]
145
+ shard_key_substitute = klass.connection.substitute_at(shard_key_column)
112
146
 
113
- relation = relation.where(self.class.arel_table[klass.turntable_shard_key].eq(shard_key_substitute))
114
- relation.bind_values << [shard_key_column, self[klass.turntable_shard_key]]
147
+ relation = relation.where(self.class.arel_table[klass.turntable_shard_key].eq(shard_key_substitute))
148
+ relation.bind_values << [shard_key_column, self[klass.turntable_shard_key]]
149
+ end
150
+ relation
115
151
  end
116
- relation
117
- end
118
- else
119
- def relation_for_destroy
120
- pk = self.class.primary_key
121
- column = self.class.columns_hash[pk]
122
- substitute = self.class.connection.substitute_at(column, 0)
123
- klass = self.class
124
-
125
- relation = self.class.unscoped.where(
126
- self.class.arel_table[pk].eq(substitute))
127
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
128
- relation = relation.where(klass.turntable_shard_key => self.send(turntable_shard_key))
152
+ else
153
+ def relation_for_destroy
154
+ pk = self.class.primary_key
155
+ column = self.class.columns_hash[pk]
156
+ substitute = self.class.connection.substitute_at(column, 0)
157
+ klass = self.class
158
+
159
+ relation = self.class.unscoped.where(
160
+ self.class.arel_table[pk].eq(substitute))
161
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
162
+ relation = relation.where(klass.turntable_shard_key => self.send(turntable_shard_key))
163
+ end
164
+ relation.bind_values = [[column, id]]
165
+ relation
129
166
  end
130
- relation.bind_values = [[column, id]]
131
- relation
132
167
  end
133
- end
134
168
 
135
- # @note Override to add sharding scope on updating
136
- if ar_version < "4.1"
137
- method_name = ar_version =~ /\A4\.0\.[0-5]\z/ ? "update_record" : "_update_record"
138
- class_eval <<-EOD
139
- def #{method_name}(attribute_names = @attributes.keys)
140
- attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
141
- if attributes_with_values.empty?
142
- 0
143
- else
144
- klass = self.class
145
- column_hash = klass.connection.schema_cache.columns_hash klass.table_name
146
- db_columns_with_values = attributes_with_values.map { |attr,value|
147
- real_column = column_hash[attr.name]
148
- [real_column, value]
149
- }
150
- bind_attrs = attributes_with_values.dup
151
- bind_attrs.keys.each_with_index do |column, i|
152
- real_column = db_columns_with_values[i].first
153
- bind_attrs[column] = klass.connection.substitute_at(real_column, i)
154
- end
155
- condition_scope = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id))
156
- if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
157
- condition_scope = condition_scope.where(klass.turntable_shard_key => self.send(turntable_shard_key))
169
+ # @note Override to add sharding scope on updating
170
+ if Util.earlier_than_ar41?
171
+ method_name = Util.ar_version_earlier_than?("4.0.6") ? "update_record" : "_update_record"
172
+ class_eval <<-EOD
173
+ def #{method_name}(attribute_names = @attributes.keys)
174
+ attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
175
+ if attributes_with_values.empty?
176
+ 0
177
+ else
178
+ klass = self.class
179
+ column_hash = klass.connection.schema_cache.columns_hash klass.table_name
180
+ db_columns_with_values = attributes_with_values.map { |attr,value|
181
+ real_column = column_hash[attr.name]
182
+ [real_column, value]
183
+ }
184
+ bind_attrs = attributes_with_values.dup
185
+ bind_attrs.keys.each_with_index do |column, i|
186
+ real_column = db_columns_with_values[i].first
187
+ bind_attrs[column] = klass.connection.substitute_at(real_column, i)
188
+ end
189
+ condition_scope = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id))
190
+ if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
191
+ condition_scope = condition_scope.where(klass.turntable_shard_key => self.send(turntable_shard_key))
192
+ end
193
+ stmt = condition_scope.arel.compile_update(bind_attrs)
194
+ klass.connection.update stmt, 'SQL', db_columns_with_values
158
195
  end
159
- stmt = condition_scope.arel.compile_update(bind_attrs)
160
- klass.connection.update stmt, 'SQL', db_columns_with_values
161
196
  end
162
- end
163
- EOD
164
- else
165
- method_name = ar_version =~ /\A4\.1\.[01]\z/ ? "update_record" : "_update_record"
166
- class_eval <<-EOD
167
- def #{method_name}(attribute_names = @attributes.keys)
168
- klass = self.class
169
- attributes_values = arel_attributes_with_values_for_update(attribute_names)
170
- if attributes_values.empty?
171
- 0
172
- else
173
- scope = if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
174
- klass.unscoped.where(klass.turntable_shard_key => self.send(turntable_shard_key))
197
+ EOD
198
+ else
199
+ method_name = Util.ar_version_earlier_than?("4.1.2") ? "update_record" : "_update_record"
200
+ attributes_method_name = Util.ar42_or_later? ? "self.attribute_names" : "@attributes.keys"
201
+ class_eval <<-EOD
202
+ def #{method_name}(attribute_names = #{attributes_method_name})
203
+ klass = self.class
204
+ attributes_values = arel_attributes_with_values_for_update(attribute_names)
205
+ if attributes_values.empty?
206
+ 0
207
+ else
208
+ scope = if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
209
+ klass.unscoped.where(klass.turntable_shard_key => self.send(turntable_shard_key))
210
+ end
211
+ klass.unscoped.#{method_name} attributes_values, id, id_was, scope
175
212
  end
176
- klass.unscoped.#{method_name} attributes_values, id, id_was, scope
177
213
  end
178
- end
179
- EOD
214
+ EOD
215
+ end
180
216
  end
181
217
  end
182
218
  end
@@ -4,9 +4,8 @@ module ActiveRecord::Turntable
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- version = ActiveRecord::VERSION::STRING
8
- if version >= '4.1'
9
- if version < '4.1.2'
7
+ if Util.ar41_or_later?
8
+ if Util.ar_version_earlier_than?('4.1.2')
10
9
  alias_method :_update_record_without_turntable, :update_record
11
10
  alias_method :update_record, :_update_record_with_turntable
12
11
  else
@@ -16,7 +15,7 @@ module ActiveRecord::Turntable
16
15
  end
17
16
 
18
17
  # @note Override to add sharding scope on updating
19
- if ActiveRecord::Turntable.rails42_later?
18
+ if Util.ar42_or_later?
20
19
  def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
21
20
  substitutes, binds = substitute_values values
22
21
 
@@ -14,7 +14,11 @@ module ActiveRecord::Turntable
14
14
  begin
15
15
  status = yield
16
16
  rescue ActiveRecord::Rollback
17
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
17
+ if Util.ar42_or_later?
18
+ clear_transaction_record_state
19
+ else
20
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
21
+ end
18
22
  status = nil
19
23
  end
20
24
 
@@ -0,0 +1,37 @@
1
+ module ActiveRecord::Turntable
2
+ module Util
3
+ extend self
4
+
5
+ def ar_version_equals_or_later?(version)
6
+ ar_version >= Gem::Version.new(version)
7
+ end
8
+
9
+ def ar_version_earlier_than?(version)
10
+ ar_version < Gem::Version.new(version)
11
+ end
12
+
13
+ def ar4?
14
+ ActiveRecord::VERSION::MAJOR == 4
15
+ end
16
+
17
+ def ar41_or_later?
18
+ ar_version_equals_or_later?("4.1")
19
+ end
20
+
21
+ def earlier_than_ar41?
22
+ ar_version_earlier_than?("4.1")
23
+ end
24
+
25
+ def ar42_or_later?
26
+ ar_version_equals_or_later?("4.2")
27
+ end
28
+
29
+ def earlier_than_ar42?
30
+ ar_version_earlier_than?("4.2")
31
+ end
32
+
33
+ def ar_version
34
+ ActiveRecord::gem_version
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Turntable
3
- VERSION = "2.1.0.beta1"
3
+ VERSION = "2.1.0.beta2"
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: 2.1.0.beta1
4
+ version: 2.1.0.beta2
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: 2015-01-07 00:00:00.000000000 Z
12
+ date: 2015-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -398,6 +398,7 @@ files:
398
398
  - lib/active_record/turntable/sequencer/mysql.rb
399
399
  - lib/active_record/turntable/shard.rb
400
400
  - lib/active_record/turntable/sql_tree_patch.rb
401
+ - lib/active_record/turntable/util.rb
401
402
  - lib/active_record/turntable/version.rb
402
403
  - lib/activerecord-turntable.rb
403
404
  - lib/generators/active_record/turntable/install_generator.rb
@@ -465,7 +466,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
465
466
  version: 1.3.1
466
467
  requirements: []
467
468
  rubyforge_project: activerecord-turntable
468
- rubygems_version: 2.4.4
469
+ rubygems_version: 2.4.5
469
470
  signing_key:
470
471
  specification_version: 4
471
472
  summary: ActiveRecord sharding extension