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 +4 -4
- data/lib/active_record/turntable.rb +10 -12
- data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +1 -1
- data/lib/active_record/turntable/active_record_ext/association.rb +5 -5
- data/lib/active_record/turntable/active_record_ext/clever_load.rb +40 -38
- data/lib/active_record/turntable/active_record_ext/fixtures.rb +14 -31
- data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +135 -133
- data/lib/active_record/turntable/active_record_ext/persistence.rb +181 -145
- data/lib/active_record/turntable/active_record_ext/relation.rb +3 -4
- data/lib/active_record/turntable/active_record_ext/transactions.rb +5 -1
- data/lib/active_record/turntable/util.rb +37 -0
- data/lib/active_record/turntable/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2673c7fcde5190f1b2da9ac7d398ebf0e3faf1a
|
4
|
+
data.tar.gz: 40fa47723f339d79d3846aaa90aabccdc0232337
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
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
|
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
|
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
|
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
|
2
|
-
module
|
3
|
-
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ActiveRecordExt
|
3
|
+
module CleverLoad
|
4
|
+
extend ActiveSupport::Concern
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
included do
|
7
|
+
class << ActiveRecord::Base
|
8
|
+
delegate :clever_load!, :to => :all
|
9
|
+
end
|
8
10
|
end
|
9
|
-
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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,
|
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
|
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
|
-
|
26
|
+
conn,
|
25
27
|
fs_name,
|
26
|
-
|
28
|
+
klass,
|
27
29
|
::File.join(fixtures_directory, fs_name))
|
28
30
|
end
|
29
31
|
|
30
|
-
|
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.
|
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
|
111
|
+
if ar41_or_later?
|
124
112
|
load_fixtures(config)
|
125
|
-
elsif ActiveRecord::Turntable.rails4?
|
126
|
-
load_fixtures
|
127
113
|
else
|
128
|
-
|
114
|
+
load_fixtures
|
129
115
|
end
|
130
116
|
end
|
131
117
|
|
132
118
|
def turntable_instantiate_fixtures(config)
|
133
|
-
if
|
119
|
+
if ar41_or_later?
|
134
120
|
instantiate_fixtures(config)
|
135
|
-
elsif ActiveRecord::Turntable.rails4?
|
136
|
-
instantiate_fixtures
|
137
121
|
else
|
138
|
-
|
122
|
+
instantiate_fixtures
|
139
123
|
end
|
140
124
|
end
|
141
|
-
|
142
125
|
end
|
143
126
|
end
|
@@ -1,158 +1,160 @@
|
|
1
|
-
module ActiveRecord::Turntable
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
relation.
|
28
|
-
relation.table[
|
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
|
-
|
38
|
-
|
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
|
-
|
41
|
+
affected_rows = self.class.connection.update stmt
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
unless affected_rows == 1
|
44
|
+
raise ActiveRecord::StaleObjectError.new(self, "update")
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
+
affected_rows
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
self.class.
|
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
|
-
|
92
|
+
affected_rows = self.class.connection.update stmt
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
unless affected_rows == 1
|
95
|
+
raise ActiveRecord::StaleObjectError.new(self, "update")
|
96
|
+
end
|
96
97
|
|
97
|
-
|
98
|
+
affected_rows
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
142
|
+
affected_rows = self.class.connection.update stmt
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
|
144
|
+
unless affected_rows == 1
|
145
|
+
raise ActiveRecord::StaleObjectError.new(self, "update")
|
146
|
+
end
|
146
147
|
|
147
|
-
|
148
|
+
affected_rows
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
155
|
-
|
156
|
+
EOD
|
157
|
+
end
|
156
158
|
end
|
157
159
|
end
|
158
160
|
end
|
@@ -1,182 +1,218 @@
|
|
1
|
-
module ActiveRecord::Turntable
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
57
|
+
clear_attribute_changes(changes.keys)
|
58
|
+
primary_key = self.class.primary_key
|
43
59
|
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
75
|
+
attributes = timestamp_attributes_for_update_in_model
|
76
|
+
attributes << name if name
|
54
77
|
|
55
|
-
|
56
|
-
|
78
|
+
unless attributes.empty?
|
79
|
+
current_time = current_time_from_proper_timezone
|
80
|
+
changes = {}
|
57
81
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
110
|
+
attributes.each_key do |key|
|
111
|
+
verify_readonly_attribute(key.to_s)
|
112
|
+
end
|
85
113
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
91
|
-
end
|
120
|
+
updated_count = update_scope.where(self.class.primary_key => id).update_all(attributes)
|
92
121
|
|
93
|
-
|
122
|
+
attributes.each do |k, v|
|
123
|
+
raw_write_attribute(k, v)
|
124
|
+
end
|
94
125
|
|
95
|
-
|
126
|
+
updated_count == 1
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
96
130
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
139
|
+
relation = self.class.unscoped.where(
|
140
|
+
self.class.arel_table[pk].eq(substitute))
|
141
|
+
relation.bind_values = [[column, id]]
|
108
142
|
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
114
|
-
|
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
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
relation =
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
179
|
-
|
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
|
-
|
8
|
-
|
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
|
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
|
-
|
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
|
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.
|
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-
|
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.
|
469
|
+
rubygems_version: 2.4.5
|
469
470
|
signing_key:
|
470
471
|
specification_version: 4
|
471
472
|
summary: ActiveRecord sharding extension
|