switchman 3.4.2 → 3.5.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +15 -14
  3. data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
  4. data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
  5. data/lib/switchman/active_record/associations.rb +16 -5
  6. data/lib/switchman/active_record/attribute_methods.rb +67 -22
  7. data/lib/switchman/active_record/base.rb +32 -12
  8. data/lib/switchman/active_record/calculations.rb +37 -33
  9. data/lib/switchman/active_record/connection_pool.rb +4 -2
  10. data/lib/switchman/active_record/database_configurations.rb +12 -7
  11. data/lib/switchman/active_record/finder_methods.rb +1 -1
  12. data/lib/switchman/active_record/log_subscriber.rb +2 -2
  13. data/lib/switchman/active_record/migration.rb +4 -2
  14. data/lib/switchman/active_record/persistence.rb +18 -0
  15. data/lib/switchman/active_record/postgresql_adapter.rb +11 -10
  16. data/lib/switchman/active_record/query_cache.rb +1 -1
  17. data/lib/switchman/active_record/query_methods.rb +72 -26
  18. data/lib/switchman/active_record/relation.rb +13 -7
  19. data/lib/switchman/active_record/spawn_methods.rb +2 -2
  20. data/lib/switchman/active_record/statement_cache.rb +2 -2
  21. data/lib/switchman/active_record/tasks/database_tasks.rb +1 -1
  22. data/lib/switchman/active_record/test_fixtures.rb +19 -16
  23. data/lib/switchman/active_support/cache.rb +4 -1
  24. data/lib/switchman/arel.rb +6 -6
  25. data/lib/switchman/call_super.rb +1 -1
  26. data/lib/switchman/database_server.rb +20 -16
  27. data/lib/switchman/default_shard.rb +3 -3
  28. data/lib/switchman/engine.rb +33 -18
  29. data/lib/switchman/environment.rb +2 -2
  30. data/lib/switchman/errors.rb +4 -1
  31. data/lib/switchman/guard_rail/relation.rb +1 -1
  32. data/lib/switchman/parallel.rb +1 -1
  33. data/lib/switchman/r_spec_helper.rb +10 -10
  34. data/lib/switchman/shard.rb +30 -23
  35. data/lib/switchman/sharded_instrumenter.rb +5 -1
  36. data/lib/switchman/test_helper.rb +1 -1
  37. data/lib/switchman/version.rb +1 -1
  38. data/lib/switchman.rb +12 -4
  39. data/lib/tasks/switchman.rake +40 -37
  40. metadata +9 -9
@@ -2,8 +2,8 @@
2
2
 
3
3
  # In rails 7.0+ if you have only 1 db in the env it doesn't try to do explicit activation
4
4
  # (and for rails purposes we only have one db per env because each database server is a separate env)
5
- if Rails.version < '7.0'
6
- task_prefix = Rake::Task.task_defined?('app:db:migrate') ? 'app:db' : 'db'
5
+ if Rails.version < "7.0"
6
+ task_prefix = Rake::Task.task_defined?("app:db:migrate") ? "app:db" : "db"
7
7
  Rake::Task["#{task_prefix}:migrate"].clear_actions.enhance do
8
8
  ActiveRecord::Tasks::DatabaseTasks.migrate
9
9
  # Ensure this doesn't blow up when running inside the dummy app
@@ -13,26 +13,27 @@ end
13
13
 
14
14
  module Switchman
15
15
  module Rake
16
- def self.filter_database_servers(&block)
17
- chain = filter_database_servers_chain # use a local variable so that the current chain is closed over in the following lambda
18
- @filter_database_servers_chain = ->(servers) { block.call(servers, chain) }
16
+ def self.filter_database_servers
17
+ # use a local variable so that the current chain is closed over in the following lambda
18
+ chain = filter_database_servers_chain
19
+ @filter_database_servers_chain = ->(servers) { yield(servers, chain) }
19
20
  end
20
21
 
21
22
  def self.scope(base_scope = Shard,
22
- database_server: ENV.fetch('DATABASE_SERVER', nil),
23
- shard: ENV.fetch('SHARD', nil))
23
+ database_server: ENV.fetch("DATABASE_SERVER", nil),
24
+ shard: ENV.fetch("SHARD", nil))
24
25
  servers = DatabaseServer.all
25
26
 
26
27
  if database_server
27
28
  servers = database_server
28
- if servers.first == '-'
29
+ if servers.first == "-"
29
30
  negative = true
30
31
  servers = servers[1..]
31
32
  end
32
- servers = servers.split(',')
33
- open = servers.delete('open')
33
+ servers = servers.split(",")
34
+ open = servers.delete("open")
34
35
 
35
- servers = servers.map { |server| DatabaseServer.find(server) }.compact
36
+ servers = servers.filter_map { |server| DatabaseServer.find(server) }
36
37
  if open
37
38
  open_servers = DatabaseServer.all.select { |server| server.config[:open] }
38
39
  servers.concat(open_servers)
@@ -44,7 +45,7 @@ module Switchman
44
45
 
45
46
  servers = filter_database_servers_chain.call(servers)
46
47
 
47
- scope = base_scope.order(::Arel.sql('database_server_id IS NOT NULL, database_server_id, id'))
48
+ scope = base_scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
48
49
  if servers != DatabaseServer.all
49
50
  database_server_ids = servers.map(&:id)
50
51
  database_server_ids << nil if servers.include?(Shard.default.database_server)
@@ -57,7 +58,7 @@ module Switchman
57
58
  end
58
59
 
59
60
  def self.options
60
- { parallel: ENV['PARALLEL'].to_i }
61
+ { parallel: ENV["PARALLEL"].to_i }
61
62
  end
62
63
 
63
64
  # classes - an array or proc, to activate as the current shard during the
@@ -69,7 +70,7 @@ module Switchman
69
70
 
70
71
  old_task.enhance do |*task_args|
71
72
  if ::Rails.env.test?
72
- require 'switchman/test_helper'
73
+ require "switchman/test_helper"
73
74
  TestHelper.recreate_persistent_test_shards(dont_create: true)
74
75
  end
75
76
 
@@ -86,7 +87,9 @@ module Switchman
86
87
  nil
87
88
  end
88
89
  rescue => e
89
- warn "Exception from #{e.current_shard.id}: #{e.current_shard.description}:\n#{e.full_message}" if options[:parallel] != 0
90
+ if options[:parallel] != 0
91
+ warn "Exception from #{e.current_shard.id}: #{e.current_shard.description}:\n#{e.full_message}"
92
+ end
90
93
  raise
91
94
  end
92
95
  end
@@ -98,7 +101,7 @@ module Switchman
98
101
  end
99
102
 
100
103
  def self.shard_scope(scope, raw_shard_ids)
101
- raw_shard_ids = raw_shard_ids.split(',')
104
+ raw_shard_ids = raw_shard_ids.split(",")
102
105
 
103
106
  shard_ids = []
104
107
  negative_shard_ids = []
@@ -108,13 +111,13 @@ module Switchman
108
111
 
109
112
  raw_shard_ids.each do |id|
110
113
  case id
111
- when 'default'
114
+ when "default"
112
115
  shard_ids << Shard.default.id
113
- when '-default'
116
+ when "-default"
114
117
  negative_shard_ids << Shard.default.id
115
- when 'primary'
118
+ when "primary"
116
119
  shard_ids.concat(Shard.primary.pluck(:id))
117
- when '-primary'
120
+ when "-primary"
118
121
  negative_shard_ids.concat(Shard.primary.pluck(:id))
119
122
  when /^(-?)(\d+)?\.\.(\.)?(\d+)?$/
120
123
  negative, start, open, finish = $1.present?, $2, $3.present?, $4
@@ -122,8 +125,8 @@ module Switchman
122
125
 
123
126
  range = []
124
127
  range << "id>=#{start}" if start
125
- range << "id<#{'=' unless open}#{finish}" if finish
126
- (negative ? negative_ranges : ranges) << "(#{range.join(' AND ')})"
128
+ range << "id<#{"=" unless open}#{finish}" if finish
129
+ (negative ? negative_ranges : ranges) << "(#{range.join(" AND ")})"
127
130
  when /^-(\d+)$/
128
131
  negative_shard_ids << $1.to_i
129
132
  when /^\d+$/
@@ -151,21 +154,21 @@ module Switchman
151
154
  select = []
152
155
  if index != 1
153
156
  subscope = subscope.offset(per_chunk * (index - 1))
154
- select << 'MIN(id) AS min_id'
157
+ select << "MIN(id) AS min_id"
155
158
  end
156
159
  if index != denominator
157
160
  subscope = subscope.limit(per_chunk)
158
- select << 'MAX(id) AS max_id'
161
+ select << "MAX(id) AS max_id"
159
162
  end
160
163
 
161
- result = Shard.from(subscope).select(select.join(', ')).to_a.first
164
+ result = Shard.from(subscope).select(select.join(", ")).to_a.first
162
165
  range = case index
163
166
  when 1
164
- "id<=#{result['max_id']}"
167
+ "id<=#{result["max_id"]}"
165
168
  when denominator
166
- "id>=#{result['min_id']}"
169
+ "id>=#{result["min_id"]}"
167
170
  else
168
- "(id>=#{result['min_id']} AND id<=#{result['max_id']})"
171
+ "(id>=#{result["min_id"]} AND id<=#{result["max_id"]})"
169
172
  end
170
173
 
171
174
  (numerator.negative? ? negative_ranges : ranges) << range
@@ -186,16 +189,16 @@ module Switchman
186
189
 
187
190
  conditions = []
188
191
  positive_queries = []
189
- positive_queries << ranges.join(' OR ') unless ranges.empty?
192
+ positive_queries << ranges.join(" OR ") unless ranges.empty?
190
193
  unless shard_ids.empty?
191
- positive_queries << 'id IN (?)'
194
+ positive_queries << "id IN (?)"
192
195
  conditions << shard_ids
193
196
  end
194
- positive_query = positive_queries.join(' OR ')
197
+ positive_query = positive_queries.join(" OR ")
195
198
  scope = scope.where(positive_query, *conditions) unless positive_queries.empty?
196
199
 
197
- scope = scope.where("NOT (#{negative_ranges.join(' OR')})") unless negative_ranges.empty?
198
- scope = scope.where('id NOT IN (?)', negative_shard_ids) unless negative_shard_ids.empty?
200
+ scope = scope.where("NOT (#{negative_ranges.join(" OR")})") unless negative_ranges.empty?
201
+ scope = scope.where("id NOT IN (?)", negative_shard_ids) unless negative_shard_ids.empty?
199
202
  scope
200
203
  end
201
204
 
@@ -208,19 +211,19 @@ module Switchman
208
211
  module PostgreSQLDatabaseTasks
209
212
  def structure_dump(filename, extra_flags = nil)
210
213
  set_psql_env
211
- args = ['--schema-only', '--no-privileges', '--no-owner', '--file', filename]
214
+ args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
212
215
  args.concat(Array(extra_flags)) if extra_flags
213
216
  shard = Shard.current.name
214
217
  serialized_search_path = shard
215
218
  args << "--schema=#{Shellwords.escape(shard)}"
216
219
 
217
220
  ignore_tables = ::ActiveRecord::SchemaDumper.ignore_tables
218
- args += ignore_tables.flat_map { |table| ['-T', table] } if ignore_tables.any?
221
+ args += ignore_tables.flat_map { |table| ["-T", table] } if ignore_tables.any?
219
222
 
220
223
  args << db_config.database
221
- run_cmd('pg_dump', args, 'dumping')
224
+ run_cmd("pg_dump", args, "dumping")
222
225
  remove_sql_header_comments(filename)
223
- File.open(filename, 'a') { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
226
+ File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
224
227
  end
225
228
  end
226
229
  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: 3.4.2
4
+ version: 3.5.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: 2023-04-17 00:00:00.000000000 Z
13
+ date: 2023-05-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 2.3.0
89
+ version: '2.3'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 2.3.0
96
+ version: '2.3'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: byebug
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: '4.0'
173
+ version: '6.0'
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: '4.0'
180
+ version: '6.0'
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: rubocop
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -193,19 +193,19 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: '1.10'
195
195
  - !ruby/object:Gem::Dependency
196
- name: rubocop-performance
196
+ name: rubocop-inst
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '1.16'
201
+ version: '1'
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '1.16'
208
+ version: '1'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: rubocop-rake
211
211
  requirement: !ruby/object:Gem::Requirement