online_migrations 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +34 -31
- data/docs/background_migrations.md +36 -4
- data/docs/configuring.md +3 -2
- data/lib/generators/online_migrations/install_generator.rb +3 -7
- data/lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt +18 -0
- data/lib/generators/online_migrations/templates/initializer.rb.tt +5 -3
- data/lib/generators/online_migrations/templates/migration.rb.tt +8 -3
- data/lib/generators/online_migrations/upgrade_generator.rb +33 -0
- data/lib/online_migrations/background_migrations/application_record.rb +13 -0
- data/lib/online_migrations/background_migrations/backfill_column.rb +1 -1
- data/lib/online_migrations/background_migrations/copy_column.rb +6 -20
- data/lib/online_migrations/background_migrations/delete_orphaned_records.rb +2 -20
- data/lib/online_migrations/background_migrations/migration.rb +123 -34
- data/lib/online_migrations/background_migrations/migration_helpers.rb +0 -4
- data/lib/online_migrations/background_migrations/migration_job.rb +15 -12
- data/lib/online_migrations/background_migrations/migration_job_runner.rb +2 -2
- data/lib/online_migrations/background_migrations/migration_runner.rb +56 -11
- data/lib/online_migrations/background_migrations/reset_counters.rb +3 -9
- data/lib/online_migrations/background_migrations/scheduler.rb +5 -15
- data/lib/online_migrations/change_column_type_helpers.rb +68 -83
- data/lib/online_migrations/command_checker.rb +11 -29
- data/lib/online_migrations/config.rb +7 -15
- data/lib/online_migrations/copy_trigger.rb +15 -10
- data/lib/online_migrations/error_messages.rb +13 -25
- data/lib/online_migrations/foreign_keys_collector.rb +2 -2
- data/lib/online_migrations/indexes_collector.rb +3 -3
- data/lib/online_migrations/lock_retrier.rb +4 -9
- data/lib/online_migrations/schema_cache.rb +0 -6
- data/lib/online_migrations/schema_dumper.rb +1 -1
- data/lib/online_migrations/schema_statements.rb +64 -256
- data/lib/online_migrations/utils.rb +18 -56
- data/lib/online_migrations/verbose_sql_logs.rb +3 -2
- data/lib/online_migrations/version.rb +1 -1
- data/lib/online_migrations.rb +7 -6
- metadata +8 -7
- data/lib/online_migrations/background_migrations/advisory_lock.rb +0 -62
- data/lib/online_migrations/foreign_key_definition.rb +0 -17
@@ -27,51 +27,15 @@ module OnlineMigrations
|
|
27
27
|
Kernel.warn("[online_migrations] #{message}")
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
# Technically, Active Record 6.0+ supports multiple databases,
|
32
|
-
# but we can not get the database spec name for this version.
|
33
|
-
ar_version >= 6.1
|
34
|
-
end
|
35
|
-
|
36
|
-
def migration_parent
|
37
|
-
if ar_version <= 4.2
|
38
|
-
ActiveRecord::Migration
|
39
|
-
else
|
40
|
-
ActiveRecord::Migration[ar_version]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def migration_parent_string
|
45
|
-
if ar_version <= 4.2
|
46
|
-
"ActiveRecord::Migration"
|
47
|
-
else
|
48
|
-
"ActiveRecord::Migration[#{ar_version}]"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def model_parent_string
|
53
|
-
if ar_version >= 5.0
|
54
|
-
"ApplicationRecord"
|
55
|
-
else
|
56
|
-
"ActiveRecord::Base"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def define_model(table_name, connection = ActiveRecord::Base.connection)
|
30
|
+
def define_model(table_name)
|
61
31
|
Class.new(ActiveRecord::Base) do
|
62
32
|
self.table_name = table_name
|
63
33
|
self.inheritance_column = :_type_disabled
|
64
|
-
|
65
|
-
@online_migrations_connection = connection
|
66
|
-
|
67
|
-
def self.connection
|
68
|
-
@online_migrations_connection
|
69
|
-
end
|
70
34
|
end
|
71
35
|
end
|
72
36
|
|
73
37
|
def to_bool(value)
|
74
|
-
|
38
|
+
value.to_s.match?(/^true|t|yes|y|1|on$/i)
|
75
39
|
end
|
76
40
|
|
77
41
|
def foreign_table_name(ref_name, options)
|
@@ -81,7 +45,7 @@ module OnlineMigrations
|
|
81
45
|
end
|
82
46
|
|
83
47
|
# Implementation is from ActiveRecord.
|
84
|
-
# This is not needed for ActiveRecord
|
48
|
+
# This is not needed for ActiveRecord >= 7.1 (https://github.com/rails/rails/pull/47753).
|
85
49
|
def index_name(table_name, column_name)
|
86
50
|
max_index_name_size = 62
|
87
51
|
name = "index_#{table_name}_on_#{Array(column_name) * '_and_'}"
|
@@ -122,7 +86,7 @@ module OnlineMigrations
|
|
122
86
|
def estimated_count(connection, table_name)
|
123
87
|
quoted_table = connection.quote(table_name)
|
124
88
|
|
125
|
-
count = connection.select_value(
|
89
|
+
count = connection.select_value(<<~SQL)
|
126
90
|
SELECT
|
127
91
|
(reltuples / COALESCE(NULLIF(relpages, 0), 1)) *
|
128
92
|
(pg_relation_size(#{quoted_table}) / (current_setting('block_size')::integer))
|
@@ -135,25 +99,11 @@ module OnlineMigrations
|
|
135
99
|
count = count.to_i
|
136
100
|
# If the table has never yet been vacuumed or analyzed, reltuples contains -1
|
137
101
|
# indicating that the row count is unknown.
|
138
|
-
count = 0 if count
|
102
|
+
count = 0 if count < 0
|
139
103
|
count
|
140
104
|
end
|
141
105
|
end
|
142
106
|
|
143
|
-
def ar_where_not_multiple_conditions(relation, conditions)
|
144
|
-
if Utils.ar_version >= 6.1
|
145
|
-
relation.where.not(conditions)
|
146
|
-
else
|
147
|
-
# In Active Record < 6.1, NOT with multiple conditions behaves as NOR,
|
148
|
-
# which should really behave as NAND.
|
149
|
-
# https://www.bigbinary.com/blog/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1
|
150
|
-
arel_table = relation.arel_table
|
151
|
-
conditions = conditions.map { |column, value| arel_table[column].not_eq(value) }
|
152
|
-
conditions = conditions.inject(:or)
|
153
|
-
relation.where(conditions)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
107
|
FUNCTION_CALL_RE = /(\w+)\s*\(/
|
158
108
|
private_constant :FUNCTION_CALL_RE
|
159
109
|
|
@@ -167,7 +117,7 @@ module OnlineMigrations
|
|
167
117
|
end
|
168
118
|
|
169
119
|
def volatile_function?(connection, function_name)
|
170
|
-
query =
|
120
|
+
query = <<~SQL
|
171
121
|
SELECT provolatile
|
172
122
|
FROM pg_catalog.pg_proc
|
173
123
|
WHERE proname = #{connection.quote(function_name)}
|
@@ -175,6 +125,18 @@ module OnlineMigrations
|
|
175
125
|
|
176
126
|
connection.select_value(query) == "v"
|
177
127
|
end
|
128
|
+
|
129
|
+
def shard_names(model)
|
130
|
+
model.ancestors.each do |ancestor|
|
131
|
+
# There is no official method to get shard names from the model.
|
132
|
+
# This is the way that currently is used in ActiveRecord tests themselves.
|
133
|
+
pool_manager = ActiveRecord::Base.connection_handler.send(:get_pool_manager, ancestor.name)
|
134
|
+
|
135
|
+
# .uniq call is not needed for Active Record 7.1+
|
136
|
+
# See https://github.com/rails/rails/pull/49284.
|
137
|
+
return pool_manager.shard_names.uniq if pool_manager
|
138
|
+
end
|
139
|
+
end
|
178
140
|
end
|
179
141
|
end
|
180
142
|
end
|
@@ -7,6 +7,7 @@ module OnlineMigrations
|
|
7
7
|
def enable
|
8
8
|
@activerecord_logger_was = ActiveRecord::Base.logger
|
9
9
|
@verbose_query_logs_was = verbose_query_logs
|
10
|
+
return if @activerecord_logger_was.nil?
|
10
11
|
|
11
12
|
stdout_logger = ActiveSupport::Logger.new($stdout)
|
12
13
|
stdout_logger.formatter = @activerecord_logger_was.formatter
|
@@ -34,7 +35,7 @@ module OnlineMigrations
|
|
34
35
|
def verbose_query_logs
|
35
36
|
if Utils.ar_version >= 7.0
|
36
37
|
ActiveRecord.verbose_query_logs
|
37
|
-
|
38
|
+
else
|
38
39
|
ActiveRecord::Base.verbose_query_logs
|
39
40
|
end
|
40
41
|
end
|
@@ -42,7 +43,7 @@ module OnlineMigrations
|
|
42
43
|
def set_verbose_query_logs(value) # rubocop:disable Naming/AccessorMethodName
|
43
44
|
if Utils.ar_version >= 7.0
|
44
45
|
ActiveRecord.verbose_query_logs = value
|
45
|
-
|
46
|
+
else
|
46
47
|
ActiveRecord::Base.verbose_query_logs = value
|
47
48
|
end
|
48
49
|
end
|
data/lib/online_migrations.rb
CHANGED
@@ -18,7 +18,6 @@ module OnlineMigrations
|
|
18
18
|
autoload :Migrator
|
19
19
|
autoload :SchemaDumper
|
20
20
|
autoload :DatabaseTasks
|
21
|
-
autoload :ForeignKeyDefinition
|
22
21
|
autoload :ForeignKeysCollector
|
23
22
|
autoload :IndexDefinition
|
24
23
|
autoload :IndexesCollector
|
@@ -55,12 +54,12 @@ module OnlineMigrations
|
|
55
54
|
autoload :DeleteOrphanedRecords
|
56
55
|
autoload :PerformActionOnRelation
|
57
56
|
autoload :ResetCounters
|
57
|
+
autoload :ApplicationRecord
|
58
58
|
autoload :MigrationJob
|
59
59
|
autoload :Migration
|
60
60
|
autoload :MigrationJobRunner
|
61
61
|
autoload :MigrationRunner
|
62
62
|
autoload :MigrationHelpers
|
63
|
-
autoload :AdvisoryLock
|
64
63
|
autoload :Scheduler
|
65
64
|
end
|
66
65
|
|
@@ -76,6 +75,12 @@ module OnlineMigrations
|
|
76
75
|
@config ||= Config.new
|
77
76
|
end
|
78
77
|
|
78
|
+
# Run background migrations
|
79
|
+
def run_background_migrations
|
80
|
+
BackgroundMigrations::Scheduler.run
|
81
|
+
end
|
82
|
+
|
83
|
+
# @private
|
79
84
|
def load
|
80
85
|
require "active_record/connection_adapters/postgresql_adapter"
|
81
86
|
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(OnlineMigrations::SchemaStatements)
|
@@ -92,10 +97,6 @@ module OnlineMigrations
|
|
92
97
|
else
|
93
98
|
ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
|
94
99
|
end
|
95
|
-
|
96
|
-
if OnlineMigrations::Utils.ar_version <= 5.1
|
97
|
-
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.prepend(OnlineMigrations::ForeignKeyDefinition)
|
98
|
-
end
|
99
100
|
end
|
100
101
|
end
|
101
102
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: online_migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fatkodima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '6.1'
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- fatkodima123@gmail.com
|
@@ -38,12 +38,14 @@ files:
|
|
38
38
|
- docs/configuring.md
|
39
39
|
- lib/generators/online_migrations/background_migration_generator.rb
|
40
40
|
- lib/generators/online_migrations/install_generator.rb
|
41
|
+
- lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt
|
41
42
|
- lib/generators/online_migrations/templates/background_migration.rb.tt
|
42
43
|
- lib/generators/online_migrations/templates/initializer.rb.tt
|
43
44
|
- lib/generators/online_migrations/templates/migration.rb.tt
|
45
|
+
- lib/generators/online_migrations/upgrade_generator.rb
|
44
46
|
- lib/online_migrations.rb
|
45
47
|
- lib/online_migrations/background_migration.rb
|
46
|
-
- lib/online_migrations/background_migrations/
|
48
|
+
- lib/online_migrations/background_migrations/application_record.rb
|
47
49
|
- lib/online_migrations/background_migrations/backfill_column.rb
|
48
50
|
- lib/online_migrations/background_migrations/background_migration_class_validator.rb
|
49
51
|
- lib/online_migrations/background_migrations/config.rb
|
@@ -68,7 +70,6 @@ files:
|
|
68
70
|
- lib/online_migrations/copy_trigger.rb
|
69
71
|
- lib/online_migrations/database_tasks.rb
|
70
72
|
- lib/online_migrations/error_messages.rb
|
71
|
-
- lib/online_migrations/foreign_key_definition.rb
|
72
73
|
- lib/online_migrations/foreign_keys_collector.rb
|
73
74
|
- lib/online_migrations/index_definition.rb
|
74
75
|
- lib/online_migrations/indexes_collector.rb
|
@@ -96,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
97
|
requirements:
|
97
98
|
- - ">="
|
98
99
|
- !ruby/object:Gem::Version
|
99
|
-
version: 2.
|
100
|
+
version: '2.7'
|
100
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
102
|
requirements:
|
102
103
|
- - ">="
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "zlib"
|
4
|
-
|
5
|
-
module OnlineMigrations
|
6
|
-
module BackgroundMigrations
|
7
|
-
# @private
|
8
|
-
class AdvisoryLock
|
9
|
-
attr_reader :name, :connection
|
10
|
-
|
11
|
-
def initialize(name:, connection: ActiveRecord::Base.connection)
|
12
|
-
@name = name
|
13
|
-
@connection = connection
|
14
|
-
end
|
15
|
-
|
16
|
-
def try_lock
|
17
|
-
locked = connection.select_value("SELECT pg_try_advisory_lock(#{lock_key})")
|
18
|
-
Utils.to_bool(locked)
|
19
|
-
end
|
20
|
-
|
21
|
-
def unlock
|
22
|
-
connection.select_value("SELECT pg_advisory_unlock(#{lock_key})")
|
23
|
-
end
|
24
|
-
|
25
|
-
# Runs the given block if an advisory lock is able to be acquired.
|
26
|
-
def with_lock
|
27
|
-
if try_lock
|
28
|
-
begin
|
29
|
-
yield
|
30
|
-
ensure
|
31
|
-
unlock
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def active?
|
37
|
-
objid = lock_key & 0xffffffff
|
38
|
-
classid = (lock_key & (0xffffffff << 32)) >> 32
|
39
|
-
|
40
|
-
active = connection.select_value(<<-SQL.strip_heredoc)
|
41
|
-
SELECT granted
|
42
|
-
FROM pg_locks
|
43
|
-
WHERE locktype = 'advisory'
|
44
|
-
AND pid = pg_backend_pid()
|
45
|
-
AND mode = 'ExclusiveLock'
|
46
|
-
AND classid = #{classid}
|
47
|
-
AND objid = #{objid}
|
48
|
-
SQL
|
49
|
-
|
50
|
-
Utils.to_bool(active)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
SALT = 936723412
|
55
|
-
|
56
|
-
def lock_key
|
57
|
-
name_hash = Zlib.crc32(name)
|
58
|
-
SALT * name_hash
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OnlineMigrations
|
4
|
-
# @private
|
5
|
-
module ForeignKeyDefinition
|
6
|
-
if Utils.ar_version <= 4.2
|
7
|
-
def defined_for?(to_table: nil, **options)
|
8
|
-
(to_table.nil? || to_table.to_s == self.to_table) &&
|
9
|
-
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
10
|
-
end
|
11
|
-
elsif Utils.ar_version <= 5.1
|
12
|
-
def defined_for?(*args, **options)
|
13
|
-
super(*args, **options.except(:validate))
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|