activerecord-turntable 2.1.0.beta1 → 2.1.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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