activerecord-turntable 2.5.0 → 3.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/.travis.yml +3 -7
  4. data/CHANGELOG.md +4 -14
  5. data/Gemfile +3 -0
  6. data/Guardfile +12 -7
  7. data/README.md +11 -19
  8. data/Rakefile +14 -15
  9. data/activerecord-turntable.gemspec +24 -27
  10. data/gemfiles/rails5_0.gemfile +6 -0
  11. data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +24 -20
  12. data/lib/active_record/turntable/active_record_ext/activerecord_import_ext.rb +6 -16
  13. data/lib/active_record/turntable/active_record_ext/acts_as_archive_extension.rb +25 -16
  14. data/lib/active_record/turntable/active_record_ext/association.rb +33 -14
  15. data/lib/active_record/turntable/active_record_ext/association_preloader.rb +4 -24
  16. data/lib/active_record/turntable/active_record_ext/clever_load.rb +2 -2
  17. data/lib/active_record/turntable/active_record_ext/connection_handler_extension.rb +11 -15
  18. data/lib/active_record/turntable/active_record_ext/database_tasks.rb +9 -9
  19. data/lib/active_record/turntable/active_record_ext/fixtures.rb +11 -41
  20. data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +40 -147
  21. data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +6 -37
  22. data/lib/active_record/turntable/active_record_ext/migration_proxy.rb +1 -1
  23. data/lib/active_record/turntable/active_record_ext/persistence.rb +54 -148
  24. data/lib/active_record/turntable/active_record_ext/relation.rb +17 -45
  25. data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +80 -78
  26. data/lib/active_record/turntable/active_record_ext/sequencer.rb +6 -15
  27. data/lib/active_record/turntable/active_record_ext/transactions.rb +14 -9
  28. data/lib/active_record/turntable/active_record_ext.rb +15 -16
  29. data/lib/active_record/turntable/algorithm/modulo_algorithm.rb +1 -1
  30. data/lib/active_record/turntable/algorithm/range_algorithm.rb +9 -9
  31. data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +12 -12
  32. data/lib/active_record/turntable/base.rb +27 -14
  33. data/lib/active_record/turntable/cluster.rb +10 -13
  34. data/lib/active_record/turntable/cluster_helper_methods.rb +6 -6
  35. data/lib/active_record/turntable/config.rb +3 -3
  36. data/lib/active_record/turntable/connection_proxy/mixable.rb +1 -1
  37. data/lib/active_record/turntable/connection_proxy.rb +23 -22
  38. data/lib/active_record/turntable/helpers/test_helper.rb +4 -4
  39. data/lib/active_record/turntable/master_shard.rb +12 -7
  40. data/lib/active_record/turntable/migration.rb +41 -47
  41. data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +7 -7
  42. data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +12 -12
  43. data/lib/active_record/turntable/mixer.rb +121 -121
  44. data/lib/active_record/turntable/plugin.rb +1 -1
  45. data/lib/active_record/turntable/pool_proxy.rb +7 -19
  46. data/lib/active_record/turntable/query_cache.rb +41 -0
  47. data/lib/active_record/turntable/railtie.rb +7 -5
  48. data/lib/active_record/turntable/railties/databases.rake +19 -20
  49. data/lib/active_record/turntable/seq_shard.rb +15 -15
  50. data/lib/active_record/turntable/sequencer/api.rb +7 -7
  51. data/lib/active_record/turntable/sequencer/barrage.rb +6 -7
  52. data/lib/active_record/turntable/sequencer/mysql.rb +2 -2
  53. data/lib/active_record/turntable/sequencer.rb +15 -15
  54. data/lib/active_record/turntable/shard.rb +23 -20
  55. data/lib/active_record/turntable/sql_tree_patch.rb +59 -57
  56. data/lib/active_record/turntable/util.rb +1 -21
  57. data/lib/active_record/turntable/version.rb +1 -1
  58. data/lib/active_record/turntable.rb +14 -19
  59. data/lib/activerecord-turntable.rb +2 -2
  60. data/script/performance/algorithm +8 -9
  61. data/spec/active_record/turntable/active_record_ext/association_preloader_spec.rb +4 -4
  62. data/spec/active_record/turntable/active_record_ext/association_spec.rb +5 -14
  63. data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +6 -6
  64. data/spec/active_record/turntable/active_record_ext/fixture_set_spec.rb +4 -4
  65. data/spec/active_record/turntable/active_record_ext/locking_optimistic_spec.rb +2 -15
  66. data/spec/active_record/turntable/active_record_ext/migration_spec.rb +4 -4
  67. data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +17 -15
  68. data/spec/active_record/turntable/active_record_ext/sequencer_spec.rb +1 -1
  69. data/spec/active_record/turntable/active_record_ext/test_fixtures_spec.rb +3 -3
  70. data/spec/active_record/turntable/algorithm/modulo_algorithm_spec.rb +2 -3
  71. data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +2 -3
  72. data/spec/active_record/turntable/algorithm/range_bsearch_algorithm_spec.rb +2 -3
  73. data/spec/active_record/turntable/algorithm_spec.rb +5 -5
  74. data/spec/active_record/turntable/base_spec.rb +1 -1
  75. data/spec/active_record/turntable/cluster_spec.rb +1 -1
  76. data/spec/active_record/turntable/config_spec.rb +1 -1
  77. data/spec/active_record/turntable/connection_proxy_spec.rb +16 -17
  78. data/spec/active_record/turntable/finder_spec.rb +1 -1
  79. data/spec/active_record/turntable/mixer/fader_spec.rb +1 -1
  80. data/spec/active_record/turntable/mixer_spec.rb +2 -4
  81. data/spec/active_record/turntable/query_cache_spec.rb +28 -0
  82. data/spec/active_record/turntable/sequencer/api_spec.rb +4 -4
  83. data/spec/active_record/turntable/sequencer/barrage_spec.rb +2 -2
  84. data/spec/active_record/turntable/sequencer/mysql_spec.rb +1 -1
  85. data/spec/active_record/turntable/shard_spec.rb +1 -1
  86. data/spec/active_record/turntable/sql_tree_patch_spec.rb +2 -2
  87. data/spec/active_record/turntable/transaction_spec.rb +2 -2
  88. data/spec/active_record/turntable_spec.rb +3 -3
  89. data/spec/migrations/002_create_user_statuses.rb +4 -4
  90. data/spec/migrations/003_create_cards.rb +3 -3
  91. data/spec/migrations/004_create_cards_users.rb +2 -2
  92. data/spec/models/user_status.rb +0 -1
  93. data/spec/spec_helper.rb +15 -14
  94. data/spec/support/turntable_helper.rb +4 -4
  95. metadata +98 -59
  96. data/gemfiles/rails4_0.gemfile +0 -7
  97. data/gemfiles/rails4_1.gemfile +0 -7
  98. data/gemfiles/rails4_2.gemfile +0 -7
  99. data/lib/active_record/turntable/rack/connection_management.rb +0 -18
  100. data/lib/active_record/turntable/rack/query_cache.rb +0 -40
  101. data/lib/active_record/turntable/rack.rb +0 -8
  102. data/spec/active_record/turntable/rack/query_cache_spec.rb +0 -19
@@ -6,10 +6,9 @@ module ActiveRecord::Turntable
6
6
  ::ActiveRecord::Persistence.class_eval do
7
7
  # @note Override to add sharding scope on reloading
8
8
  def reload(options = nil)
9
- clear_aggregation_cache
10
- clear_association_cache
9
+ self.class.connection.clear_query_cache
11
10
 
12
- finder_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
11
+ finder_scope = if turntable_enabled? && self.class.primary_key != self.class.turntable_shard_key.to_s
13
12
  self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
14
13
  else
15
14
  self.class.unscoped
@@ -17,88 +16,56 @@ module ActiveRecord::Turntable
17
16
 
18
17
  fresh_object =
19
18
  if options && options[:lock]
20
- finder_scope.lock.find(id)
19
+ finder_scope.lock(options[:lock]).find(id)
21
20
  else
22
21
  finder_scope.find(id)
23
22
  end
24
23
 
25
- if Util.ar42_or_later?
26
- @attributes = fresh_object.instance_variable_get('@attributes')
27
- else
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 = {}
33
- end
24
+ @attributes = fresh_object.instance_variable_get("@attributes")
34
25
  @new_record = false
35
26
  self
36
27
  end
37
28
 
38
29
  # @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?
42
-
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 = {}
49
-
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?
30
+ def touch(*names, time: nil)
31
+ raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
56
32
 
57
- clear_attribute_changes(changes.keys)
58
- primary_key = self.class.primary_key
33
+ time ||= current_time_from_proper_timezone
34
+ attributes = timestamp_attributes_for_update_in_model
35
+ attributes.concat(names)
59
36
 
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
37
+ unless attributes.empty?
38
+ changes = {}
65
39
 
66
- finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
67
- else
68
- true
40
+ attributes.each do |column|
41
+ column = column.to_s
42
+ changes[column] = write_attribute(column, time)
69
43
  end
70
- end
71
- else
72
- def touch(name = nil)
73
- raise ActiveRecordError, "can not touch on a new record object" unless persisted?
74
-
75
- attributes = timestamp_attributes_for_update_in_model
76
- attributes << name if name
77
-
78
- unless attributes.empty?
79
- current_time = current_time_from_proper_timezone
80
- changes = {}
81
-
82
- attributes.each do |column|
83
- column = column.to_s
84
- changes[column] = write_attribute(column, current_time)
85
- end
86
-
87
- changes[self.class.locking_column] = increment_lock if locking_enabled?
88
44
 
89
- @changed_attributes.except!(*changes.keys)
90
- primary_key = self.class.primary_key
45
+ clear_attribute_changes(changes.keys)
46
+ primary_key = self.class.primary_key
47
+ scope = if turntable_enabled? && primary_key != self.class.turntable_shard_key.to_s
48
+ self.class.unscoped.where(self.class.turntable_shard_key => _read_attribute(turntable_shard_key))
49
+ else
50
+ self.class.unscoped
51
+ end
52
+ scope = scope.where(primary_key => _read_attribute(primary_key))
53
+
54
+ if locking_enabled?
55
+ locking_column = self.class.locking_column
56
+ scope = scope.where(locking_column => _read_attribute(locking_column))
57
+ changes[locking_column] = increment_lock
58
+ end
91
59
 
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
60
+ result = scope.update_all(changes) == 1
97
61
 
98
- finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
99
- else
100
- true
62
+ if !result && locking_enabled?
63
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
101
64
  end
65
+
66
+ result
67
+ else
68
+ true
102
69
  end
103
70
  end
104
71
 
@@ -111,7 +78,7 @@ module ActiveRecord::Turntable
111
78
  verify_readonly_attribute(key.to_s)
112
79
  end
113
80
 
114
- update_scope = if turntable_enabled? and self.class.primary_key != self.class.turntable_shard_key.to_s
81
+ update_scope = if turntable_enabled? && self.class.primary_key != self.class.turntable_shard_key.to_s
115
82
  self.class.unscoped.where(self.class.turntable_shard_key => self.send(turntable_shard_key))
116
83
  else
117
84
  self.class.unscoped
@@ -129,89 +96,28 @@ module ActiveRecord::Turntable
129
96
  private
130
97
 
131
98
  # @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
138
-
139
- relation = self.class.unscoped.where(
140
- self.class.arel_table[pk].eq(substitute))
141
- relation.bind_values = [[column, id]]
142
-
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)
146
-
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
151
- end
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
99
+ def relation_for_destroy
100
+ klass = self.class
101
+ relation = klass.unscoped.where(klass.primary_key => id)
102
+
103
+ if klass.turntable_enabled? && klass.primary_key != klass.turntable_shard_key.to_s
104
+ relation = relation.where(klass.turntable_shard_key => self[klass.turntable_shard_key])
166
105
  end
106
+ relation
167
107
  end
168
108
 
169
109
  # @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
195
- end
196
- end
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
212
- end
213
- end
214
- EOD
110
+ def _update_record(attribute_names = self.attribute_names)
111
+ klass = self.class
112
+ attributes_values = arel_attributes_with_values_for_update(attribute_names)
113
+ if attributes_values.empty?
114
+ 0
115
+ else
116
+ scope = if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
117
+ klass.unscoped.where(klass.turntable_shard_key => self.send(turntable_shard_key))
118
+ end
119
+ klass.unscoped._update_record attributes_values, id, id_was, scope
120
+ end
215
121
  end
216
122
  end
217
123
  end
@@ -1,56 +1,28 @@
1
1
  module ActiveRecord::Turntable
2
2
  module ActiveRecordExt
3
3
  module Relation
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- if Util.ar41_or_later?
8
- if Util.ar_version_earlier_than?('4.1.2')
9
- alias_method :_update_record_without_turntable, :update_record
10
- alias_method :update_record, :_update_record_with_turntable
11
- else
12
- alias_method_chain :_update_record, :turntable
13
- end
14
- end
15
- end
16
-
17
4
  # @note Override to add sharding scope on updating
18
- if Util.ar42_or_later?
19
- def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
20
- substitutes, binds = substitute_values values
5
+ def _update_record(values, id, id_was, turntable_scope = nil) # :nodoc:
6
+ substitutes, binds = substitute_values values
21
7
 
22
- scope = @klass.unscoped
8
+ scope = @klass.unscoped
23
9
 
24
- if @klass.finder_needs_type_condition?
25
- scope.unscope!(where: @klass.inheritance_column)
26
- end
27
-
28
- relation = scope.where(@klass.primary_key => (id_was || id))
29
- relation = relation.merge(turntable_scope) if turntable_scope
30
-
31
- bvs = binds + relation.bind_values
32
- um = relation
33
- .arel
34
- .compile_update(substitutes, @klass.primary_key)
35
-
36
- @klass.connection.update(
37
- um,
38
- 'SQL',
39
- bvs,
40
- )
10
+ if @klass.finder_needs_type_condition?
11
+ scope.unscope!(where: @klass.inheritance_column)
41
12
  end
42
- else
43
- def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
44
- substitutes, binds = substitute_values values
45
- condition_scope = @klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id))
46
- condition_scope = condition_scope.merge(turntable_scope) if turntable_scope
47
- um = condition_scope.arel.compile_update(substitutes, @klass.primary_key)
48
13
 
49
- @klass.connection.update(
50
- um,
51
- 'SQL',
52
- binds)
53
- end
14
+ relation = scope.where(@klass.primary_key => (id_was || id))
15
+ relation = relation.merge(turntable_scope) if turntable_scope
16
+ bvs = binds + relation.bound_attributes
17
+ um = relation.
18
+ arel.
19
+ compile_update(substitutes, @klass.primary_key)
20
+
21
+ @klass.connection.update(
22
+ um,
23
+ "SQL",
24
+ bvs
25
+ )
54
26
  end
55
27
  end
56
28
  end
@@ -2,103 +2,105 @@
2
2
  module ActiveRecord::Turntable
3
3
  module ActiveRecordExt
4
4
  module SchemaDumper
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- alias_method_chain :table, :turntable
9
- end
10
5
 
11
6
  private
12
7
 
13
- # @note Override to dump database sequencer method
14
- def table_with_turntable(table, stream)
15
- columns = @connection.columns(table)
16
- begin
17
- tbl = StringIO.new
18
-
19
- # first dump primary key column
20
- if @connection.respond_to?(:pk_and_sequence_for)
21
- pk, _ = @connection.pk_and_sequence_for(table)
22
- elsif @connection.respond_to?(:primary_key)
23
- pk = @connection.primary_key(table)
24
- end
8
+ # @note Override to dump database sequencer method
9
+ def table(table, stream)
10
+ columns = @connection.columns(table)
11
+ begin
12
+ tbl = StringIO.new
13
+
14
+ # first dump primary key column
15
+ if @connection.respond_to?(:primary_keys)
16
+ pk = @connection.primary_keys(table)
17
+ pk = pk.first unless pk.size > 1
18
+ else
19
+ pk = @connection.primary_key(table)
20
+ end
25
21
 
26
- if table =~ /\A(.*)_id_seq\z/
27
- tbl.print " create_sequence_for #{remove_prefix_and_suffix($1).inspect}"
28
- else
29
- tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
30
- end
31
- pkcol = columns.detect { |c| c.name == pk }
32
- if pkcol
33
- if pk != 'id'
34
- tbl.print %Q(, primary_key: "#{pk}")
35
- elsif pkcol.sql_type == 'bigint'
36
- tbl.print ", id: :bigserial"
37
- elsif pkcol.sql_type == 'uuid'
38
- tbl.print ", id: :uuid"
39
- tbl.print %Q(, default: "#{pkcol.default_function.inspect}")
22
+ if table =~ /\A(.*)_id_seq\z/
23
+ tbl.print " create_sequence_for #{remove_prefix_and_suffix(Regexp.last_match(1)).inspect}"
24
+ else
25
+ tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
26
+ end
27
+
28
+ case pk
29
+ when String
30
+ tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id'
31
+ pkcol = columns.detect { |c| c.name == pk }
32
+ pkcolspec = @connection.column_spec_for_primary_key(pkcol)
33
+ if pkcolspec.present?
34
+ pkcolspec.each do |key, value|
35
+ tbl.print ", #{key}: #{value}"
36
+ end
37
+ end
38
+ when Array
39
+ tbl.print ", primary_key: #{pk.inspect}"
40
+ else
41
+ tbl.print ", id: false"
40
42
  end
41
- else
42
- tbl.print ", id: false"
43
- end
44
- if Util.earlier_than_ar42?
45
- tbl.print ", force: true"
46
- else
47
43
  tbl.print ", force: :cascade"
48
- end
49
- tbl.puts " do |t|"
50
44
 
51
- # then dump all non-primary key columns
52
- column_specs = columns.map do |column|
53
- raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
54
- next if column.name == pk
55
- @connection.column_spec(column, @types)
56
- end.compact
45
+ table_options = @connection.table_options(table)
46
+ tbl.print ", options: #{table_options.inspect}" unless table_options.blank?
47
+
48
+ if comment = @connection.table_comment(table).presence
49
+ tbl.print ", comment: #{comment.inspect}"
50
+ end
57
51
 
58
- # find all migration keys used in this table
59
- keys = @connection.migration_keys
52
+ tbl.puts " do |t|"
60
53
 
61
- # figure out the lengths for each column based on above keys
62
- lengths = keys.map { |key|
63
- column_specs.map { |spec|
64
- spec[key] ? spec[key].length + 2 : 0
65
- }.max
66
- }
54
+ # then dump all non-primary key columns
55
+ column_specs = columns.map do |column|
56
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
57
+ next if column.name == pk
58
+ @connection.column_spec(column)
59
+ end.compact
67
60
 
68
- # the string we're going to sprintf our values against, with standardized column widths
69
- format_string = lengths.map{ |len| "%-#{len}s" }
61
+ # find all migration keys used in this table
62
+ keys = @connection.migration_keys
70
63
 
71
- # find the max length for the 'type' column, which is special
72
- type_length = column_specs.map{ |column| column[:type].length }.max
64
+ # figure out the lengths for each column based on above keys
65
+ lengths = keys.map { |key|
66
+ column_specs.map { |spec|
67
+ spec[key] ? spec[key].length + 2 : 0
68
+ }.max
69
+ }
73
70
 
74
- # add column type definition to our format string
75
- format_string.unshift " t.%-#{type_length}s "
71
+ # the string we're going to sprintf our values against, with standardized column widths
72
+ format_string = lengths.map{ |len| "%-#{len}s" }
76
73
 
77
- format_string *= ''
74
+ # find the max length for the 'type' column, which is special
75
+ type_length = column_specs.map{ |column| column[:type].length }.max
78
76
 
79
- column_specs.each do |colspec|
80
- values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
81
- values.unshift colspec[:type]
82
- tbl.print((format_string % values).gsub(/,\s*$/, ''))
83
- tbl.puts
84
- end
77
+ # add column type definition to our format string
78
+ format_string.unshift " t.%-#{type_length}s "
85
79
 
86
- tbl.puts " end"
87
- tbl.puts
80
+ format_string *= ''
88
81
 
89
- indexes(table, tbl)
82
+ column_specs.each do |colspec|
83
+ values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
84
+ values.unshift colspec[:type]
85
+ tbl.print((format_string % values).gsub(/,\s*$/, ''))
86
+ tbl.puts
87
+ end
90
88
 
91
- tbl.rewind
92
- stream.print tbl.read
93
- rescue => e
94
- stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
95
- stream.puts "# #{e.message}"
96
- stream.puts
97
- end
89
+ indexes_in_create(table, tbl)
98
90
 
99
- stream
100
- end
91
+ tbl.puts " end"
92
+ tbl.puts
93
+
94
+ tbl.rewind
95
+ stream.print tbl.read
96
+ rescue => e
97
+ stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
98
+ stream.puts "# #{e.message}"
99
+ stream.puts
100
+ end
101
101
 
102
+ stream
103
+ end
102
104
  end
103
105
  end
104
106
  end
@@ -1,23 +1,14 @@
1
1
  module ActiveRecord::Turntable::ActiveRecordExt
2
2
  module Sequencer
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- include DatabaseStatements
7
- alias_method_chain :prefetch_primary_key?, :turntable
8
- end
9
-
10
- module DatabaseStatements
11
- def default_sequence_name(table_name, pk = nil)
12
- if ActiveRecord::Turntable::Sequencer.has_sequencer?(table_name)
13
- ActiveRecord::Turntable::Sequencer.sequence_name(table_name, pk)
14
- else
15
- super
16
- end
3
+ def default_sequence_name(table_name, pk = nil)
4
+ if ActiveRecord::Turntable::Sequencer.has_sequencer?(table_name)
5
+ ActiveRecord::Turntable::Sequencer.sequence_name(table_name, pk)
6
+ else
7
+ super
17
8
  end
18
9
  end
19
10
 
20
- def prefetch_primary_key_with_turntable?(table_name = nil)
11
+ def prefetch_primary_key?(table_name = nil)
21
12
  ActiveRecord::Turntable::Sequencer.has_sequencer?(table_name)
22
13
  end
23
14
 
@@ -5,8 +5,8 @@ module ActiveRecord::Turntable
5
5
  def with_transaction_returning_status
6
6
  if self.class.turntable_enabled?
7
7
  status = nil
8
- if self.new_record? and self.turntable_shard_key.to_s == self.class.primary_key and
9
- self.id.nil? and self.class.connection.prefetch_primary_key?(self.class.table_name)
8
+ if self.new_record? && self.turntable_shard_key.to_s == self.class.primary_key &&
9
+ self.id.nil? && self.class.connection.prefetch_primary_key?(self.class.table_name)
10
10
  self.id = self.class.connection.next_sequence_value(self.class.sequence_name)
11
11
  end
12
12
  self.class.connection.shards_transaction([self.turntable_shard]) do
@@ -14,11 +14,7 @@ module ActiveRecord::Turntable
14
14
  begin
15
15
  status = yield
16
16
  rescue ActiveRecord::Rollback
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
17
+ clear_transaction_record_state
22
18
  status = nil
23
19
  end
24
20
 
@@ -28,13 +24,22 @@ module ActiveRecord::Turntable
28
24
  else
29
25
  super
30
26
  end
27
+
28
+ ensure
29
+ if @transaction_state && @transaction_state.committed?
30
+ clear_transaction_record_state
31
+ end
31
32
  end
32
33
 
33
34
  def add_to_transaction
34
35
  if self.class.turntable_enabled?
35
- if self.turntable_shard.connection.add_transaction_record(self)
36
- remember_transaction_record_state
36
+ if has_transactional_callbacks?
37
+ self.turntable_shard.connection.add_transaction_record(self)
38
+ else
39
+ sync_with_transaction_state
40
+ set_transaction_state(self.turntable_shard.connection.transaction_state)
37
41
  end
42
+ remember_transaction_record_state
38
43
  else
39
44
  super
40
45
  end
@@ -20,22 +20,21 @@ module ActiveRecord::Turntable
20
20
 
21
21
  included do
22
22
  include Transactions
23
- ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, Sequencer)
24
- ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, AbstractAdapter)
25
- ActiveRecord::LogSubscriber.send(:include, LogSubscriber)
26
- ActiveRecord::Persistence.send(:include, Persistence)
27
- ActiveRecord::Locking::Optimistic.send(:include, LockingOptimistic)
28
- ActiveRecord::Relation.send(:include, CleverLoad, Relation)
29
- ActiveRecord::Migration.send(:include, ActiveRecord::Turntable::Migration)
30
- ActiveRecord::ConnectionAdapters::ConnectionHandler.instance_exec do
31
- include ConnectionHandlerExtension
32
- end
33
- ActiveRecord::Associations::Preloader::Association.send(:include, AssociationPreloader)
34
- ActiveRecord::Associations::Association.send(:prepend, Association)
35
- require 'active_record/turntable/active_record_ext/fixtures'
36
- require 'active_record/turntable/active_record_ext/migration_proxy'
37
- require 'active_record/turntable/active_record_ext/activerecord_import_ext'
38
- require 'active_record/turntable/active_record_ext/acts_as_archive_extension'
23
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(Sequencer)
24
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(AbstractAdapter)
25
+ ActiveRecord::LogSubscriber.prepend(LogSubscriber)
26
+ ActiveRecord::Persistence.include(Persistence)
27
+ ActiveRecord::Locking::Optimistic.include(LockingOptimistic)
28
+ ActiveRecord::Relation.include(CleverLoad)
29
+ ActiveRecord::Relation.prepend(Relation)
30
+ ActiveRecord::Migration.include(ActiveRecord::Turntable::Migration)
31
+ ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ConnectionHandlerExtension)
32
+ ActiveRecord::Associations::Preloader::Association.prepend(AssociationPreloader)
33
+ ActiveRecord::Associations::Association.include(Association)
34
+ require "active_record/turntable/active_record_ext/fixtures"
35
+ require "active_record/turntable/active_record_ext/migration_proxy"
36
+ require "active_record/turntable/active_record_ext/activerecord_import_ext"
37
+ require "active_record/turntable/active_record_ext/acts_as_archive_extension"
39
38
  end
40
39
  end
41
40
  end
@@ -6,7 +6,7 @@ module ActiveRecord::Turntable::Algorithm
6
6
  end
7
7
 
8
8
  def calculate(key)
9
- @config["shards"][key % @config["shards"].size]["connection"]
9
+ @config[:shards][key % @config[:shards].size][:connection]
10
10
  rescue
11
11
  raise ActiveRecord::Turntable::CannotSpecifyShardError, "cannot specify shard for key:#{key}"
12
12
  end