switchman 1.10.4 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- 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