switchman 1.10.4 → 1.11.1

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
- SHA256:
3
- metadata.gz: ec38b2f9f4514dd6e8a395c91d56ec88e110df9f65901b09e9990de84d7b5144
4
- data.tar.gz: 8b1941a4f918b184917a0f4293b67a0f10a3317187eb98fa6736693201801a9b
2
+ SHA1:
3
+ metadata.gz: 67d816fd26624b395d3ff11e802340dedeac19af
4
+ data.tar.gz: 4775afc373abd08b450b2af8ac3c150e4c786676
5
5
  SHA512:
6
- metadata.gz: 54771d8a12ce199e67802b8be9c195b00ed8203a602027b6d0ab8776042341ad6ccf40f33c0cf0ac644c1339bcde9fe6668f442e0a864763f28be0ab8d5ba62d
7
- data.tar.gz: 53e9832319bd99cdbe0032a6c66c0749f57e9c08e09df5bd7239b872d1a4a29b868603a43d13e7d6f23c6157a14fb7a75650b90c13b7f18e424c3e5e98ad54ac
6
+ metadata.gz: ce07a665d16609b09ac3c4bd7f8e12d7ade79b1bebf4b12cfb98c4da70f7851b3229e9f65fb12b716b917e9ac24ecab48dd4e289ca69beacd723ddb39e21e81a
7
+ data.tar.gz: 25ed4aafe75a02fdcc9db632ececb598a73778219ac957c255c21ee5aa0e1606a69c7e04f1528a3e67acdee89046b99123ce17e13a6cf5735b003352e21a4209
File without changes
@@ -69,27 +69,17 @@ module Switchman
69
69
  end
70
70
  end
71
71
 
72
- if ::Rails.version >= '5'
73
- module Extension
74
- def self.build(_model, _reflection)
75
- end
76
-
77
- def self.valid_options
78
- [:multishard]
79
- end
72
+ module Extension
73
+ def self.build(_model, _reflection)
80
74
  end
81
75
 
82
- ::ActiveRecord::Associations::Builder::Association.extensions << Extension
83
- else
84
- module Builder
85
- module CollectionAssociation
86
- def valid_options
87
- super + [:multishard]
88
- end
89
- end
76
+ def self.valid_options
77
+ [:multishard]
90
78
  end
91
79
  end
92
80
 
81
+ ::ActiveRecord::Associations::Builder::Association.extensions << Extension
82
+
93
83
  module Preloader
94
84
  module Association
95
85
  def associated_records_by_owner(preloader = nil)
@@ -4,14 +4,8 @@ module Switchman
4
4
  module ClassMethods
5
5
  delegate :shard, to: :all
6
6
 
7
- if ::Rails.version < '5'
8
- def shard_category
9
- @shard_category || (self.superclass < ::ActiveRecord::Base && self.superclass.shard_category) || :primary
10
- end
11
- else
12
- def shard_category
13
- connection_specification_name.to_sym
14
- end
7
+ def shard_category
8
+ connection_specification_name.to_sym
15
9
  end
16
10
 
17
11
  def shard_category=(category)
@@ -22,13 +16,7 @@ module Switchman
22
16
  end
23
17
  categories[category] ||= []
24
18
  categories[category] << self
25
- if ::Rails.version < '5'
26
- connection_handler.uninitialize_ar(self)
27
- @shard_category = category
28
- connection_handler.initialize_categories(superclass)
29
- else
30
- self.connection_specification_name = category.to_s
31
- end
19
+ self.connection_specification_name = category.to_s
32
20
  end
33
21
 
34
22
  def integral_id?
@@ -104,22 +92,18 @@ module Switchman
104
92
  end
105
93
  end
106
94
 
107
- def scope_class
108
- ::Rails.version >= '5' ? self.class : self.class.base_class
109
- end
110
-
111
95
  def save(*args)
112
96
  @shard_set_in_stone = true
113
- scope_class.shard(shard, :implicit).scoping { super }
97
+ self.class.shard(shard, :implicit).scoping { super }
114
98
  end
115
99
 
116
100
  def save!(*args)
117
101
  @shard_set_in_stone = true
118
- scope_class.shard(shard, :implicit).scoping { super }
102
+ self.class.shard(shard, :implicit).scoping { super }
119
103
  end
120
104
 
121
105
  def destroy
122
- scope_class.shard(shard, :implicit).scoping { super }
106
+ self.class.shard(shard, :implicit).scoping { super }
123
107
  end
124
108
 
125
109
  def clone
@@ -152,12 +136,10 @@ module Switchman
152
136
  copy
153
137
  end
154
138
 
155
- if ::Rails.version >= '5'
156
- def quoted_id
157
- return super unless self.class.sharded_primary_key?
158
- # do this the Rails 4.2 way, so that if Shard.current != self.shard, the id gets transposed
159
- self.class.connection.quote(id)
160
- end
139
+ def quoted_id
140
+ return super unless self.class.sharded_primary_key?
141
+ # do this the Rails 4.2 way, so that if Shard.current != self.shard, the id gets transposed
142
+ self.class.connection.quote(id)
161
143
  end
162
144
  end
163
145
  end
@@ -159,7 +159,7 @@ module Switchman
159
159
  'count', opts[:distinct]).as('count')
160
160
  end
161
161
 
162
- haves = ::Rails.version >= "5" ? having_clause.send(:predicates) : having_values
162
+ haves = having_clause.send(:predicates)
163
163
  select_values += select_values unless haves.empty?
164
164
  select_values.concat opts[:group_fields].zip(opts[:group_aliases]).map { |field,aliaz|
165
165
  if field.respond_to?(:as)
@@ -22,9 +22,8 @@ module Switchman
22
22
  end
23
23
  end
24
24
 
25
- def establish_connection(*args)
25
+ def establish_connection(spec)
26
26
  pool = super
27
- owner, spec = ::Rails.version < '5' ? args : [nil, args.first]
28
27
 
29
28
  # this is the first place that the adapter would have been required; but now we
30
29
  # need this addition ASAP since it will be called when loading the default shard below
@@ -53,16 +52,11 @@ module Switchman
53
52
 
54
53
  @shard_connection_pools ||= { [:master, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
55
54
 
56
- category = ::Rails.version < '5' ? owner.shard_category : pool.spec.name.to_sym
55
+ category = pool.spec.name.to_sym
57
56
  proxy = ConnectionPoolProxy.new(category,
58
57
  pool,
59
58
  @shard_connection_pools)
60
- if ::Rails.version < '5'
61
- owner_to_pool[owner.name] = proxy
62
- class_to_pool.clear
63
- else
64
- owner_to_pool[pool.spec.name] = proxy
65
- end
59
+ owner_to_pool[pool.spec.name] = proxy
66
60
 
67
61
  if first_time
68
62
  if Shard.default.database_server.config[:prefer_slave]
@@ -107,96 +101,46 @@ module Switchman
107
101
  proxy
108
102
  end
109
103
 
110
- if ::Rails.version < '5'
111
- def remove_connection(model)
112
- uninitialize_ar(model) if owner_to_pool[model.name].is_a?(ConnectionPoolProxy)
113
- result = super
114
- initialize_categories
115
- result
116
- end
104
+ def remove_connection(spec_name)
105
+ pool = owner_to_pool[spec_name]
106
+ owner_to_pool[spec_name] = pool.default_pool if pool.is_a?(ConnectionPoolProxy)
107
+ super
108
+ end
117
109
 
118
- def pool_for(owner)
119
- # copypasted from AR#ConnectionHandler other than proxy handling
120
-
121
- owner_to_pool.fetch(owner.name) {
122
- if ancestor_pool = pool_from_any_process_for(owner)
123
- # A connection was established in an ancestor process that must have
124
- # subsequently forked. We can't reuse the connection, but we can copy
125
- # the specification and establish a new connection with it.
126
- if ancestor_pool.is_a?(ConnectionPoolProxy)
127
- establish_connection owner, ancestor_pool.default_pool.spec
128
- else
129
- establish_connection owner, ancestor_pool.spec
130
- end
110
+ def retrieve_connection_pool(spec_name)
111
+ owner_to_pool.fetch(spec_name) do
112
+ if ancestor_pool = pool_from_any_process_for(spec_name)
113
+ # A connection was established in an ancestor process that must have
114
+ # subsequently forked. We can't reuse the connection, but we can copy
115
+ # the specification and establish a new connection with it.
116
+ spec = if ancestor_pool.is_a?(ConnectionPoolProxy)
117
+ ancestor_pool.default_pool.spec
131
118
  else
132
- owner_to_pool[owner.name] = nil
133
- end
134
- }
135
- end
136
-
137
- def retrieve_connection_pool(klass)
138
- class_to_pool[klass.name] ||= begin
139
- original_klass = klass
140
- until pool = pool_for(klass)
141
- klass = klass.superclass
142
- break unless klass <= Base
143
- end
144
-
145
- if pool.is_a?(ConnectionPoolProxy) && pool.category != original_klass.shard_category
146
- default_pool = pool.default_pool
147
- pool = nil
148
- class_to_pool.each_value { |p| pool = p if p.is_a?(ConnectionPoolProxy) &&
149
- p.category == original_klass.shard_category &&
150
- p.default_pool == default_pool }
151
- pool ||= ConnectionPoolProxy.new(original_klass.shard_category, default_pool, @shard_connection_pools)
119
+ ancestor_pool.spec
152
120
  end
153
-
154
- class_to_pool[original_klass.name] = pool
155
- end
156
- end
157
- else
158
- def remove_connection(spec_name)
159
- pool = owner_to_pool[spec_name]
160
- owner_to_pool[spec_name] = pool.default_pool if pool.is_a?(ConnectionPoolProxy)
161
- super
162
- end
163
-
164
- def retrieve_connection_pool(spec_name)
165
- owner_to_pool.fetch(spec_name) do
166
- if ancestor_pool = pool_from_any_process_for(spec_name)
167
- # A connection was established in an ancestor process that must have
168
- # subsequently forked. We can't reuse the connection, but we can copy
169
- # the specification and establish a new connection with it.
170
- spec = if ancestor_pool.is_a?(ConnectionPoolProxy)
171
- ancestor_pool.default_pool.spec
172
- else
173
- ancestor_pool.spec
174
- end
175
- spec = spec.to_hash if ::Rails.version >= '5.1'
176
- pool = establish_connection spec
177
- pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
178
- pool
179
- elsif spec_name != "primary"
180
- primary_pool = retrieve_connection_pool("primary")
181
- if primary_pool.is_a?(ConnectionPoolProxy)
182
- ConnectionPoolProxy.new(spec_name.to_sym, primary_pool.default_pool, @shard_connection_pools)
183
- else
184
- primary_pool
185
- end
121
+ spec = spec.to_hash if ::Rails.version >= '5.1'
122
+ pool = establish_connection spec
123
+ pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
124
+ pool
125
+ elsif spec_name != "primary"
126
+ primary_pool = retrieve_connection_pool("primary")
127
+ if primary_pool.is_a?(ConnectionPoolProxy)
128
+ ConnectionPoolProxy.new(spec_name.to_sym, primary_pool.default_pool, @shard_connection_pools)
186
129
  else
187
- owner_to_pool[spec_name] = nil
130
+ primary_pool
188
131
  end
132
+ else
133
+ owner_to_pool[spec_name] = nil
189
134
  end
190
135
  end
191
136
  end
192
137
 
193
138
  def clear_idle_connections!(since_when)
194
- # TODO in rails 4.2+ s/connection_pools.values/connection_pool_list/
195
- connection_pools.values.each{ |pool| pool.clear_idle_connections!(since_when) }
139
+ connection_pool_list.each{ |pool| pool.clear_idle_connections!(since_when) }
196
140
  end
197
141
 
198
142
  def switchman_connection_pool_proxies
199
- (::Rails.version < '5' ? class_to_pool : owner_to_pool).values.uniq.select{|p| p.is_a?(ConnectionPoolProxy)}
143
+ owner_to_pool.values.uniq.select{|p| p.is_a?(ConnectionPoolProxy)}
200
144
  end
201
145
 
202
146
  private
@@ -39,12 +39,7 @@ module Switchman
39
39
  conn
40
40
  end
41
41
 
42
- def release_connection(with_id = nil)
43
- with_id ||= if ::Rails.version >= '5'
44
- Thread.current
45
- else
46
- current_connection_id
47
- end
42
+ def release_connection(with_id = Thread.current)
48
43
  super(with_id)
49
44
 
50
45
  if spec.config[:idle_timeout]
@@ -58,7 +58,7 @@ module Switchman
58
58
  end
59
59
 
60
60
  relation.activate do |shard_rel|
61
- return true if connection.select_value(shard_rel, "#{name} Exists", shard_rel.bind_values)
61
+ return true if connection.select_value(shard_rel, "#{name} Exists", shard_rel.bound_attributes)
62
62
  end
63
63
  false
64
64
  end
@@ -17,11 +17,7 @@ module Switchman
17
17
  shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
18
18
 
19
19
  unless (payload[:binds] || []).empty?
20
- if ::Rails.version < '5'
21
- binds = " " + payload[:binds].map { |col,v|
22
- render_bind(col, v)
23
- }.inspect
24
- elsif ::Rails.version < '5.0.3'
20
+ if ::Rails.version < '5.0.3'
25
21
  binds = " " + payload[:binds].map { |attr| render_bind(attr) }.inspect
26
22
  else
27
23
  casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
@@ -31,17 +27,8 @@ module Switchman
31
27
  end
32
28
  end
33
29
 
34
- if ::Rails.version >= '5'
35
- name = colorize_payload_name(name, payload[:name])
36
- sql = color(sql, sql_color(sql), true)
37
- else
38
- if odd?
39
- name = color(name, self.class::CYAN, true)
40
- sql = color(sql, nil, true)
41
- else
42
- name = color(name, self.class::MAGENTA, true)
43
- end
44
- end
30
+ name = colorize_payload_name(name, payload[:name])
31
+ sql = color(sql, sql_color(sql), true)
45
32
 
46
33
  debug " #{name} #{sql}#{binds}#{shard}"
47
34
  end
@@ -1,12 +1,6 @@
1
1
  module Switchman
2
2
  module ActiveRecord
3
3
  module PostgreSQLAdapter
4
- if ::Rails.version < '5'
5
- def self.prepended(klass)
6
- klass::NATIVE_DATABASE_TYPES[:primary_key] = "bigserial primary key".freeze
7
- end
8
- end
9
-
10
4
  # copy/paste; use quote_local_table_name
11
5
  def create_database(name, options = {})
12
6
  options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
@@ -58,9 +52,16 @@ module Switchman
58
52
  SQL
59
53
  end
60
54
 
61
- method_name = ::Rails.version >= '5' ? :data_source_exists? : :table_exists?
62
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
63
- def #{method_name}(name)
55
+ if ::Rails.version >= '5.1'
56
+ def extract_schema_qualified_name(string)
57
+ name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(string.to_s)
58
+ if string && !name.schema && use_qualified_names?
59
+ name.instance_variable_set(:@schema, shard.name)
60
+ end
61
+ [name.schema, name.identifier]
62
+ end
63
+ else
64
+ def data_source_exists?(name)
64
65
  name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
65
66
  return false unless name.identifier
66
67
  if !name.schema && use_qualified_names?
@@ -72,11 +73,11 @@ module Switchman
72
73
  FROM pg_class c
73
74
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
74
75
  WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
75
- AND c.relname = '\#{name.identifier}'
76
- AND n.nspname = \#{name.schema ? "'\#{name.schema}'" : 'ANY (current_schemas(false))'}
76
+ AND c.relname = '#{name.identifier}'
77
+ AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
77
78
  SQL
78
79
  end
79
- RUBY
80
+ end
80
81
 
81
82
  def view_exists?(name)
82
83
  name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
@@ -213,28 +214,6 @@ module Switchman
213
214
  algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
214
215
  [index_name, index_type, index_columns, index_options, algorithm, using]
215
216
  end
216
-
217
- def rename_table(table_name, new_name)
218
- clear_cache!
219
- execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_local_table_name(new_name)}"
220
- pk, seq = pk_and_sequence_for(new_name)
221
- if pk
222
- idx = "#{table_name}_pkey"
223
- new_idx = "#{new_name}_pkey"
224
- execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_local_table_name(new_idx)}"
225
- if seq && seq.identifier == "#{table_name}_#{pk}_seq"
226
- new_seq = "#{new_name}_#{pk}_seq"
227
- execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_local_table_name(new_seq)}"
228
- end
229
- end
230
- rename_table_indexes(table_name, new_name)
231
- end
232
-
233
- def rename_index(table_name, old_name, new_name)
234
- validate_index_length!(table_name, new_name)
235
-
236
- execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_local_table_name(new_name)}"
237
- end
238
217
  end
239
218
  end
240
219
  end
@@ -52,17 +52,9 @@ module Switchman
52
52
  if self.query_cache_enabled && !locked?(arel)
53
53
  arel, binds = binds_from_relation(arel, binds)
54
54
  sql = to_sql(arel, binds)
55
- if ::Rails.version >= '5'
56
- cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
57
- else
58
- cache_sql(sql, binds) { super(sql, name, binds) }
59
- end
55
+ cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
60
56
  else
61
- if ::Rails.version >= '5'
62
- super
63
- else
64
- super(arel, name, binds)
65
- end
57
+ super
66
58
  end
67
59
  end
68
60
 
@@ -42,33 +42,6 @@ module Switchman
42
42
  self
43
43
  end
44
44
 
45
- if ::Rails.version < '5'
46
- # moved to WhereClauseFactory#build in Rails 5
47
- def build_where(opts, other = [])
48
- case opts
49
- when String, Array
50
- values = Hash === other.first ? other.first.values : other
51
-
52
- values.grep(ActiveRecord::Relation) do |rel|
53
- # serialize subqueries against the same shard as the outer query is currently
54
- # targeted to run against
55
- if rel.shard_source_value == :implicit && rel.primary_shard != primary_shard
56
- rel.shard!(primary_shard)
57
- end
58
- end
59
-
60
- [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
61
- when Hash, ::Arel::Nodes::Node
62
- predicates = super
63
- infer_shards_from_primary_key(predicates) if shard_source_value == :implicit && shard_value.is_a?(Shard)
64
- predicates = transpose_predicates(predicates, nil, primary_shard)
65
- predicates
66
- else
67
- super
68
- end
69
- end
70
- end
71
-
72
45
  # the shard that where_values are relative to. if it's multiple shards, they're stored
73
46
  # relative to the first shard
74
47
  def primary_shard
@@ -103,49 +76,26 @@ module Switchman
103
76
  end
104
77
  end
105
78
 
106
- if ::Rails.version < '5'
107
- # fixes an issue in Rails 4.2 with `reverse_sql_order` and qualified names
108
- # where quoted_table_name is called before shard(s) have been activated
109
- # if there's no ordering
110
- def reverse_order!
111
- orders = order_values.uniq
112
- orders.reject!(&:blank?)
113
- if orders.empty?
114
- self.order_values = [arel_table[primary_key].desc]
115
- else
116
- self.order_values = reverse_sql_order(orders)
117
- end
118
- self
119
- end
120
- end
121
-
122
79
  private
123
80
 
124
81
  [:where, :having].each do |type|
125
82
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
126
- def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
127
- if ::Rails.version >= '5'
128
- unless (predicates = #{type}_clause.send(:predicates)).empty?
129
- new_predicates, new_binds = transpose_predicates(predicates, source_shard,
130
- target_shard, remove_nonlocal_primary_keys,
131
- binds: #{type}_clause.binds,
132
- dup_binds_on_mutation: true)
133
- if new_predicates != predicates || !new_binds.equal?(#{type}_clause.binds)
134
- self.#{type}_clause = #{type}_clause.dup
135
- if new_predicates != predicates
136
- #{type}_clause.instance_variable_set(:@predicates, new_predicates)
137
- end
138
- if !new_binds.equal?(#{type}_clause.binds)
139
- #{type}_clause.instance_variable_set(:@binds, new_binds)
140
- end
83
+ def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
84
+ unless (predicates = #{type}_clause.send(:predicates)).empty?
85
+ new_predicates, new_binds = transpose_predicates(predicates, source_shard,
86
+ target_shard, remove_nonlocal_primary_keys,
87
+ binds: #{type}_clause.binds,
88
+ dup_binds_on_mutation: true)
89
+ if new_predicates != predicates || !new_binds.equal?(#{type}_clause.binds)
90
+ self.#{type}_clause = #{type}_clause.dup
91
+ if new_predicates != predicates
92
+ #{type}_clause.instance_variable_set(:@predicates, new_predicates)
93
+ end
94
+ if !new_binds.equal?(#{type}_clause.binds)
95
+ #{type}_clause.instance_variable_set(:@binds, new_binds)
141
96
  end
142
97
  end
143
- else
144
- unless #{type}_values.empty?
145
- self.#{type}_values = transpose_predicates(#{type}_values,
146
- source_shard, target_shard, remove_nonlocal_primary_keys)
147
- end
148
- end
98
+ end
149
99
  end
150
100
  RUBY
151
101
  end
@@ -189,20 +139,10 @@ module Switchman
189
139
  end
190
140
  when ::Arel::Nodes::BindParam
191
141
  # look for a bind param with a matching column name
192
- if ::Rails.version >= "5"
193
- if binds && bind = binds.detect{|b| b&.name.to_s == klass.primary_key.to_s}
194
- unless bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
195
- local_id, id_shard = Shard.local_id_for(bind.value)
196
- id_shard ||= Shard.current(klass.shard_category) if local_id
197
- end
198
- end
199
- else
200
- if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first&.name.to_s == klass.primary_key.to_s}
201
- column, value = bind_values[idx]
202
- unless value.is_a?(::ActiveRecord::StatementCache::Substitute)
203
- local_id, id_shard = Shard.local_id_for(value)
204
- id_shard ||= Shard.current(klass.shard_category) if local_id
205
- end
142
+ if binds && bind = binds.detect{|b| b&.name.to_s == klass.primary_key.to_s}
143
+ unless bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
144
+ local_id, id_shard = Shard.local_id_for(bind.value)
145
+ id_shard ||= Shard.current(klass.shard_category) if local_id
206
146
  end
207
147
  end
208
148
  else
@@ -260,9 +200,9 @@ module Switchman
260
200
 
261
201
  def arel_columns(columns)
262
202
  columns.map do |field|
263
- if (Symbol === field || String === field) && ::Rails.version >= '5' && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
203
+ if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
264
204
  klass.arel_attribute(field, table)
265
- elsif (Symbol === field || String === field) && ::Rails.version < '5' && columns_hash.key?(field.to_s) && !from_value
205
+ elsif (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_value
266
206
  arel_table[field]
267
207
  elsif Symbol === field
268
208
  # the rest of this is pulled from AR - the only change is from quote_table_name to quote_column_name here
@@ -324,35 +264,21 @@ module Switchman
324
264
  local_ids
325
265
  when ::Arel::Nodes::BindParam
326
266
  # look for a bind param with a matching column name
327
- if ::Rails.version >= "5"
328
- if binds && bind = binds.detect{|b| b&.name.to_s == predicate.left.name.to_s}
329
- # before we mutate, dup
330
- if dup_binds_on_mutation
331
- binds = binds.map(&:dup)
332
- dup_binds_on_mutation = false
333
- bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
334
- end
335
- if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
336
- bind.value.sharded = true # mark for transposition later
337
- bind.value.primary = true if type == :primary
338
- else
339
- local_id = Shard.relative_id_for(bind.value, current_source_shard, target_shard)
340
- local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
341
- bind.instance_variable_set(:@value, local_id)
342
- bind.instance_variable_set(:@value_for_database, nil)
343
- end
267
+ if binds && bind = binds.detect{|b| b&.name.to_s == predicate.left.name.to_s}
268
+ # before we mutate, dup
269
+ if dup_binds_on_mutation
270
+ binds = binds.map(&:dup)
271
+ dup_binds_on_mutation = false
272
+ bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
344
273
  end
345
- else
346
- if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first&.name.to_s == predicate.left.name.to_s}
347
- column, value = bind_values[idx]
348
- if value.is_a?(::ActiveRecord::StatementCache::Substitute)
349
- value.sharded = true # mark for transposition later
350
- value.primary = true if type == :primary
351
- else
352
- local_id = Shard.relative_id_for(value, current_source_shard, target_shard)
353
- local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
354
- bind_values[idx] = [column, local_id]
355
- end
274
+ if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
275
+ bind.value.sharded = true # mark for transposition later
276
+ bind.value.primary = true if type == :primary
277
+ else
278
+ local_id = Shard.relative_id_for(bind.value, current_source_shard, target_shard)
279
+ local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
280
+ bind.instance_variable_set(:@value, local_id)
281
+ bind.instance_variable_set(:@value_for_database, nil)
356
282
  end
357
283
  end
358
284
  predicate.right
@@ -374,7 +300,7 @@ module Switchman
374
300
  predicate.class.new(predicate.left, new_right_value)
375
301
  end
376
302
  end
377
- result = [result, binds] if ::Rails.version >= '5'
303
+ result = [result, binds]
378
304
  result
379
305
  end
380
306
  end
@@ -12,31 +12,29 @@ module Switchman
12
12
  end
13
13
  end
14
14
 
15
- if ::Rails.version >= '4.2'
16
- module AssociationScopeCache
17
- def initialize(*args)
18
- super
19
- # on ThroughReflection, these won't be initialized (cause it doesn't
20
- # inherit from AssociationReflection), so make sure they're
21
- # initialized here
22
- @association_scope_cache ||= {}
23
- @scope_lock ||= Mutex.new
24
- end
15
+ module AssociationScopeCache
16
+ def initialize(*args)
17
+ super
18
+ # on ThroughReflection, these won't be initialized (cause it doesn't
19
+ # inherit from AssociationReflection), so make sure they're
20
+ # initialized here
21
+ @association_scope_cache ||= {}
22
+ @scope_lock ||= Mutex.new
23
+ end
25
24
 
26
- # cache association scopes by shard.
27
- # this technically belongs on AssociationReflection, but we put it on
28
- # ThroughReflection as well, instead of delegating to its internal
29
- # HasManyAssociation, losing its proper `klass`
30
- def association_scope_cache(conn, owner)
31
- key = conn.prepared_statements
32
- if polymorphic?
33
- key = [key, owner._read_attribute(@foreign_type)]
34
- end
35
- key = [key, shard(owner).id].flatten
36
- @association_scope_cache[key] ||= @scope_lock.synchronize {
37
- @association_scope_cache[key] ||= yield
38
- }
25
+ # cache association scopes by shard.
26
+ # this technically belongs on AssociationReflection, but we put it on
27
+ # ThroughReflection as well, instead of delegating to its internal
28
+ # HasManyAssociation, losing its proper `klass`
29
+ def association_scope_cache(conn, owner)
30
+ key = conn.prepared_statements
31
+ if polymorphic?
32
+ key = [key, owner._read_attribute(@foreign_type)]
39
33
  end
34
+ key = [key, shard(owner).id].flatten
35
+ @association_scope_cache[key] ||= @scope_lock.synchronize {
36
+ @association_scope_cache[key] ||= yield
37
+ }
40
38
  end
41
39
  end
42
40
 
@@ -46,19 +46,16 @@ module Switchman
46
46
  self.activate { |relation| relation.call_super(:explain, Relation) }
47
47
  end
48
48
 
49
- to_a_method = ::Rails.version >= '5' ? :records : :to_a
50
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
51
- def #{to_a_method}
52
- return @records if loaded?
53
- results = self.activate { |relation| relation.call_super(#{to_a_method.inspect}, Relation) }
54
- case shard_value
55
- when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base
56
- @records = results
57
- @loaded = true
58
- end
59
- results
49
+ def records
50
+ return @records if loaded?
51
+ results = self.activate { |relation| relation.call_super(:records, Relation) }
52
+ case shard_value
53
+ when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base
54
+ @records = results
55
+ @loaded = true
60
56
  end
61
- RUBY
57
+ results
58
+ end
62
59
 
63
60
  %I{update_all delete_all}.each do |method|
64
61
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -5,8 +5,7 @@ module Switchman
5
5
  def create(connection, block = Proc.new)
6
6
  relation = block.call ::ActiveRecord::StatementCache::Params.new
7
7
 
8
- binds = ::Rails.version >= '5' ? relation.bound_attributes : relation.bind_values
9
- bind_map = ::ActiveRecord::StatementCache::BindMap.new(binds)
8
+ bind_map = ::ActiveRecord::StatementCache::BindMap.new(relation.bound_attributes )
10
9
  new relation.arel, bind_map
11
10
  end
12
11
  end
@@ -65,44 +64,25 @@ module Switchman
65
64
  module BindMap
66
65
  # performs id transposition here instead of query_methods.rb
67
66
  def bind(values, current_shard, target_shard)
68
- if ::Rails.version >= '5'
69
- bas = @bound_attributes.dup
70
- @indexes.each_with_index do |offset,i|
71
- ba = bas[offset]
72
- if ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.sharded
73
- new_value = Shard.relative_id_for(values[i], current_shard, target_shard || current_shard)
74
- else
75
- new_value = values[i]
76
- end
77
- bas[offset] = ba.with_cast_value(new_value)
67
+ bas = @bound_attributes.dup
68
+ @indexes.each_with_index do |offset,i|
69
+ ba = bas[offset]
70
+ if ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.sharded
71
+ new_value = Shard.relative_id_for(values[i], current_shard, target_shard || current_shard)
72
+ else
73
+ new_value = values[i]
78
74
  end
79
- bas
80
- else
81
- bvs = @bind_values.map { |pair| pair.dup }
82
- @indexes.each_with_index do |offset,i|
83
- bv = bvs[offset]
84
- if bv[1].sharded
85
- bv[1] = Shard.relative_id_for(values[i], current_shard, target_shard || current_shard)
86
- else
87
- bv[1] = values[i]
88
- end
89
- end
90
- bvs
75
+ bas[offset] = ba.with_cast_value(new_value)
91
76
  end
77
+ bas
92
78
  end
93
79
 
94
80
  def primary_value_index
95
- if ::Rails.version >= '5'
96
- primary_ba_index = @bound_attributes.index do |ba|
97
- ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.primary
98
- end
99
- if primary_ba_index
100
- @indexes.index(primary_ba_index)
101
- end
102
- else
103
- if primary_bv_index = @bind_values.index{|col, sub| sub.primary}
104
- @indexes.index(primary_bv_index)
105
- end
81
+ primary_ba_index = @bound_attributes.index do |ba|
82
+ ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.primary
83
+ end
84
+ if primary_ba_index
85
+ @indexes.index(primary_ba_index)
106
86
  end
107
87
  end
108
88
  end
@@ -2,11 +2,7 @@ module Switchman
2
2
  module Arel
3
3
  module Table
4
4
  def model
5
- if ::Rails.version >= '5'
6
- type_caster.model
7
- else
8
- engine
9
- end
5
+ type_caster.model
10
6
  end
11
7
  end
12
8
  module Visitors
@@ -123,7 +123,7 @@ module Switchman
123
123
  end
124
124
  end
125
125
  args = [config, "#{config[:adapter]}_connection"]
126
- args.unshift(pool_key.join("/")) if ::Rails.version >= '5' # seems as good a name as any
126
+ args.unshift(pool_key.join("/"))
127
127
  spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(*args)
128
128
  # unfortunately the AR code that does this require logic can't really be
129
129
  # called in isolation
@@ -1,5 +1,3 @@
1
- require "securerandom"
2
-
3
1
  module Switchman
4
2
  class DatabaseServer
5
3
  attr_accessor :id
@@ -138,14 +136,27 @@ module Switchman
138
136
  create_schema = options[:schema]
139
137
  # look for another shard associated with this db
140
138
  other_shard = self.shards.where("name<>':memory:' OR name IS NULL").order(:id).first
139
+ temp_name = other_shard&.name unless id == ::Rails.env
140
+ temp_name = Shard.default.name if id == ::Rails.env
141
141
 
142
142
  case config[:adapter]
143
143
  when 'postgresql'
144
+ temp_name ||= 'public'
144
145
  create_statement = lambda { "CREATE SCHEMA #{name}" }
145
146
  password = " PASSWORD #{::ActiveRecord::Base.connection.quote(config[:password])}" if config[:password]
146
147
  when 'sqlite3'
147
- # no create_statement
148
+ if name
149
+ # Try to create a db on-disk even if the only shards for sqlite are in-memory
150
+ temp_name = nil if temp_name == ':memory:'
151
+ # Put it in the db directory if there are no other sqlite shards
152
+ temp_name ||= 'db/dummy'
153
+ temp_name = File.join(File.dirname(temp_name), "#{name}.sqlite3")
154
+ # If they really asked for :memory:, give them :memory:
155
+ temp_name = name if name == ':memory:'
156
+ name = temp_name
157
+ end
148
158
  else
159
+ temp_name ||= self.config[:database] % self.config
149
160
  create_statement = lambda { "CREATE DATABASE #{name}" }
150
161
  end
151
162
  sharding_config = Switchman.config
@@ -159,35 +170,27 @@ module Switchman
159
170
  end
160
171
 
161
172
  create_shard = lambda do
162
- shard_id = options.fetch(:id) do
163
- case config[:adapter]
164
- when 'postgresql'
165
- id_seq = Shard.connection.quote(Shard.connection.quote_table_name('switchman_shards_id_seq'))
166
- next_id = Shard.connection.select_value("SELECT nextval(#{id_seq})")
167
- next_id.to_i
168
- else
169
- nil
170
- end
171
- end
172
-
173
- if name.nil?
174
- base_name = self.config[:database].to_s % self.config
175
- base_name = $1 if base_name =~ /(?:.*\/)(.+)_shard_\d+(?:\.sqlite3)?$/
176
- base_name = nil if base_name == ':memory:'
177
- base_name << '_' if base_name
178
- base_id = shard_id || SecureRandom.uuid
179
- name = "#{base_name}shard_#{base_id}"
180
- if config[:adapter] == 'sqlite3'
181
- name = File.join('db', "#{name}.sqlite3")
182
- end
173
+ shard = Shard.create!(:name => temp_name,
174
+ :database_server => self) do |shard|
175
+ shard.id = options[:id] if options[:id]
183
176
  end
184
-
185
- shard = Shard.create!(:id => shard_id,
186
- :name => name,
187
- :database_server => self)
188
-
189
177
  begin
190
178
  self.class.creating_new_shard = true
179
+ if name.nil?
180
+ base_name = self.config[:database] % self.config
181
+ base_name = $1 if base_name =~ /(?:.*\/)(.+)_shard_\d+(?:\.sqlite3)?$/
182
+ base_name = nil if base_name == ':memory:'
183
+ base_name << '_' if base_name
184
+ name = "#{base_name}shard_#{shard.id}"
185
+ if config[:adapter] == 'sqlite3'
186
+ # Try to create a db on-disk even if the only shards for sqlite are in-memory
187
+ temp_name = nil if temp_name == ':memory:'
188
+ # Put it in the db directory if there are no other sqlite shards
189
+ temp_name ||= 'db/dummy'
190
+ name = File.join(File.dirname(temp_name), "#{name}.sqlite3")
191
+ shard.name = name
192
+ end
193
+ end
191
194
  shard.activate(*Shard.categories) do
192
195
  ::Shackles.activate(:deploy) do
193
196
  begin
@@ -196,11 +199,14 @@ module Switchman
196
199
  ::ActiveRecord::Base.connection.execute(stmt)
197
200
  end
198
201
  # have to disconnect and reconnect to the correct db
202
+ shard.name = name
199
203
  if self.shareable? && other_shard
200
204
  other_shard.activate { ::ActiveRecord::Base.connection }
201
205
  else
202
206
  ::ActiveRecord::Base.connection_pool.current_pool.disconnect!
203
207
  end
208
+ else
209
+ shard.name = name
204
210
  end
205
211
  old_proc = ::ActiveRecord::Base.connection.raw_connection.set_notice_processor {} if config[:adapter] == 'postgresql'
206
212
  old_verbose = ::ActiveRecord::Migration.verbose
@@ -223,10 +229,11 @@ module Switchman
223
229
  end
224
230
  end
225
231
  end
232
+ shard.save!
226
233
  shard
227
234
  rescue
228
235
  shard.destroy
229
- shard.drop_database rescue nil
236
+ shard.drop_database if shard.name == name rescue nil
230
237
  reset_column_information unless create_schema == false rescue nil
231
238
  raise
232
239
  ensure
@@ -112,9 +112,6 @@ module Switchman
112
112
  ::ActiveRecord::Associations::Association.prepend(ActiveRecord::Association)
113
113
  ::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::BelongsToAssociation)
114
114
  ::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::CollectionProxy)
115
- if ::Rails.version < '5'
116
- ::ActiveRecord::Associations::Builder::CollectionAssociation.include(ActiveRecord::Builder::CollectionAssociation)
117
- end
118
115
 
119
116
  ::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Preloader::Association)
120
117
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
@@ -129,9 +126,7 @@ module Switchman
129
126
 
130
127
  ::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
131
128
  ::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
132
- if ::Rails.version >= '5'
133
- ::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
134
- end
129
+ ::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
135
130
  ::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
136
131
 
137
132
  ::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
@@ -147,12 +142,10 @@ module Switchman
147
142
  ::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
148
143
  ::ActiveRecord::Relation.include(CallSuper)
149
144
 
150
- if ::Rails.version >= '5'
151
- ::ActiveRecord::Relation::WhereClauseFactory.prepend(ActiveRecord::WhereClauseFactory)
152
- ::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
153
- ::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
154
- ::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
155
- end
145
+ ::ActiveRecord::Relation::WhereClauseFactory.prepend(ActiveRecord::WhereClauseFactory)
146
+ ::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
147
+ ::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
148
+ ::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
156
149
 
157
150
  ::Rails.singleton_class.prepend(Rails::ClassMethods)
158
151
 
@@ -118,8 +118,7 @@ module Switchman
118
118
  klass.before do
119
119
  raise "Sharding did not set up correctly" if @@sharding_failed
120
120
  Shard.clear_cache
121
- if ::Rails.version >= '5.1' ? use_transactional_tests :
122
- (::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
121
+ if ::Rails.version >= '5.1' ? use_transactional_tests : (use_transactional_tests || use_transactional_fixtures)
123
122
  Shard.default(true)
124
123
  @shard1 = Shard.find(@shard1.id)
125
124
  @shard2 = Shard.find(@shard2.id)
@@ -135,8 +134,7 @@ module Switchman
135
134
 
136
135
  klass.after do
137
136
  next if @@sharding_failed
138
- if ::Rails.version >= '5.1' ? use_transactional_tests :
139
- (::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
137
+ if ::Rails.version >= '5.1' ? use_transactional_tests : (use_transactional_tests || use_transactional_fixtures)
140
138
  shards = [@shard2]
141
139
  shards << @shard1 unless @shard1.database_server == Shard.default.database_server
142
140
  shards.each do |shard|
@@ -1,3 +1,3 @@
1
1
  module Switchman
2
- VERSION = "1.10.4"
2
+ VERSION = "1.11.1"
3
3
  end
@@ -219,20 +219,6 @@ module Switchman
219
219
  run_cmd('pg_dump', args, 'dumping')
220
220
  File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
221
221
  end
222
-
223
- if ::Rails.version < '4.2.5'
224
- # These methods are backported from rails 4.2.5 to work with the above
225
- def run_cmd(cmd, args, action)
226
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
227
- end
228
-
229
- def run_cmd_error(cmd, args, action)
230
- msg = "failed to execute:\n"
231
- msg << "#{cmd} #{args.join(' ')}\n\n"
232
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
233
- msg
234
- end
235
- end
236
222
  end
237
223
  end
238
224
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.4
4
+ version: 1.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-05-07 00:00:00.000000000 Z
13
+ date: 2017-07-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: '4.2'
21
+ version: '5.0'
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
24
  version: '5.2'
@@ -28,7 +28,7 @@ dependencies:
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: '4.2'
31
+ version: '5.0'
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '5.2'
@@ -38,7 +38,7 @@ dependencies:
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '4.2'
41
+ version: '5.0'
42
42
  - - "<"
43
43
  - !ruby/object:Gem::Version
44
44
  version: '5.2'
@@ -48,7 +48,7 @@ dependencies:
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: '4.2'
51
+ version: '5.0'
52
52
  - - "<"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.2'
@@ -177,6 +177,7 @@ files:
177
177
  - db/migrate/20130328212039_create_switchman_shards.rb
178
178
  - db/migrate/20130328224244_create_default_shard.rb
179
179
  - db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
180
+ - db/shard_1708.sqlite3
180
181
  - lib/switchman.rb
181
182
  - lib/switchman/action_controller/caching.rb
182
183
  - lib/switchman/active_record/abstract_adapter.rb
@@ -243,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
244
  version: '0'
244
245
  requirements: []
245
246
  rubyforge_project:
246
- rubygems_version: 2.7.6
247
+ rubygems_version: 2.6.10
247
248
  signing_key:
248
249
  specification_version: 4
249
250
  summary: Rails 4 sharding magic