activerecord 5.2.3 → 6.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +605 -554
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +18 -25
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +24 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +15 -5
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +111 -19
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +20 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +172 -41
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -143
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +204 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +28 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +180 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +90 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +87 -76
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +193 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +58 -49
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +14 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +182 -68
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +159 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -65
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +109 -27
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -4,6 +4,8 @@ module ActiveRecord
|
|
4
4
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
5
|
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
|
6
6
|
|
7
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
8
|
+
|
7
9
|
def self.runtime=(value)
|
8
10
|
ActiveRecord::RuntimeRegistry.sql_runtime = value
|
9
11
|
end
|
@@ -100,36 +102,15 @@ module ActiveRecord
|
|
100
102
|
end
|
101
103
|
|
102
104
|
def log_query_source
|
103
|
-
|
104
|
-
|
105
|
-
if source_line
|
106
|
-
if defined?(::Rails.root)
|
107
|
-
app_root = "#{::Rails.root.to_s}/".freeze
|
108
|
-
source_line = source_line.sub(app_root, "")
|
109
|
-
end
|
110
|
-
|
111
|
-
logger.debug(" ↳ #{ source_line }:#{ line_number }")
|
112
|
-
end
|
113
|
-
end
|
105
|
+
source = extract_query_source_location(caller)
|
114
106
|
|
115
|
-
|
116
|
-
|
117
|
-
frame.absolute_path && !ignored_callstack(frame.absolute_path)
|
107
|
+
if source
|
108
|
+
logger.debug(" ↳ #{source}")
|
118
109
|
end
|
119
|
-
|
120
|
-
offending_line = line || callstack.first
|
121
|
-
|
122
|
-
[
|
123
|
-
offending_line.path,
|
124
|
-
offending_line.lineno
|
125
|
-
]
|
126
110
|
end
|
127
111
|
|
128
|
-
|
129
|
-
|
130
|
-
def ignored_callstack(path)
|
131
|
-
path.start_with?(RAILS_GEM_ROOT) ||
|
132
|
-
path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
112
|
+
def extract_query_source_location(locations)
|
113
|
+
backtrace_cleaner.clean(locations.lazy).first
|
133
114
|
end
|
134
115
|
end
|
135
116
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/middleware/database_selector/resolver"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Middleware
|
7
|
+
# The DatabaseSelector Middleware provides a framework for automatically
|
8
|
+
# swapping from the primary to the replica database connection. Rails
|
9
|
+
# provides a basic framework to determine when to swap and allows for
|
10
|
+
# applications to write custom strategy classes to override the default
|
11
|
+
# behavior.
|
12
|
+
#
|
13
|
+
# The resolver class defines when the application should switch (i.e. read
|
14
|
+
# from the primary if a write occurred less than 2 seconds ago) and a
|
15
|
+
# resolver context class that sets a value that helps the resolver class
|
16
|
+
# decide when to switch.
|
17
|
+
#
|
18
|
+
# Rails default middleware uses the request's session to set a timestamp
|
19
|
+
# that informs the application when to read from a primary or read from a
|
20
|
+
# replica.
|
21
|
+
#
|
22
|
+
# To use the DatabaseSelector in your application with default settings add
|
23
|
+
# the following options to your environment config:
|
24
|
+
#
|
25
|
+
# config.active_record.database_selector = { delay: 2.seconds }
|
26
|
+
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
|
27
|
+
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
|
28
|
+
#
|
29
|
+
# New applications will include these lines commented out in the production.rb.
|
30
|
+
#
|
31
|
+
# The default behavior can be changed by setting the config options to a
|
32
|
+
# custom class:
|
33
|
+
#
|
34
|
+
# config.active_record.database_selector = { delay: 2.seconds }
|
35
|
+
# config.active_record.database_resolver = MyResolver
|
36
|
+
# config.active_record.database_resolver_context = MyResolver::MySession
|
37
|
+
class DatabaseSelector
|
38
|
+
def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
|
39
|
+
@app = app
|
40
|
+
@resolver_klass = resolver_klass || Resolver
|
41
|
+
@context_klass = context_klass || Resolver::Session
|
42
|
+
@options = options
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :resolver_klass, :context_klass, :options
|
46
|
+
|
47
|
+
# Middleware that determines which database connection to use in a multiple
|
48
|
+
# database application.
|
49
|
+
def call(env)
|
50
|
+
request = ActionDispatch::Request.new(env)
|
51
|
+
|
52
|
+
select_database(request) do
|
53
|
+
@app.call(env)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def select_database(request, &blk)
|
60
|
+
context = context_klass.call(request)
|
61
|
+
resolver = resolver_klass.call(context, options)
|
62
|
+
|
63
|
+
if reading_request?(request)
|
64
|
+
resolver.read(&blk)
|
65
|
+
else
|
66
|
+
resolver.write(&blk)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def reading_request?(request)
|
71
|
+
request.get? || request.head?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/middleware/database_selector/resolver/session"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Middleware
|
7
|
+
class DatabaseSelector
|
8
|
+
# The Resolver class is used by the DatabaseSelector middleware to
|
9
|
+
# determine which database the request should use.
|
10
|
+
#
|
11
|
+
# To change the behavior of the Resolver class in your application,
|
12
|
+
# create a custom resolver class that inherits from
|
13
|
+
# DatabaseSelector::Resolver and implements the methods that need to
|
14
|
+
# be changed.
|
15
|
+
#
|
16
|
+
# By default the Resolver class will send read traffic to the replica
|
17
|
+
# if it's been 2 seconds since the last write.
|
18
|
+
class Resolver # :nodoc:
|
19
|
+
SEND_TO_REPLICA_DELAY = 2.seconds
|
20
|
+
|
21
|
+
def self.call(context, options = {})
|
22
|
+
new(context, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(context, options = {})
|
26
|
+
@context = context
|
27
|
+
@options = options
|
28
|
+
@delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY
|
29
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :context, :delay, :instrumenter
|
33
|
+
|
34
|
+
def read(&blk)
|
35
|
+
if read_from_primary?
|
36
|
+
read_from_primary(&blk)
|
37
|
+
else
|
38
|
+
read_from_replica(&blk)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(&blk)
|
43
|
+
write_to_primary(&blk)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def read_from_primary(&blk)
|
49
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
50
|
+
ActiveRecord::Base.connection_handler.while_preventing_writes do
|
51
|
+
instrumenter.instrument("database_selector.active_record.read_from_primary") do
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_from_replica(&blk)
|
59
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role) do
|
60
|
+
instrumenter.instrument("database_selector.active_record.read_from_replica") do
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def write_to_primary(&blk)
|
67
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
68
|
+
instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
|
69
|
+
yield
|
70
|
+
ensure
|
71
|
+
context.update_last_write_timestamp
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def read_from_primary?
|
77
|
+
!time_since_last_write_ok?
|
78
|
+
end
|
79
|
+
|
80
|
+
def send_to_replica_delay
|
81
|
+
delay
|
82
|
+
end
|
83
|
+
|
84
|
+
def time_since_last_write_ok?
|
85
|
+
Time.now - context.last_write_timestamp >= send_to_replica_delay
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Middleware
|
5
|
+
class DatabaseSelector
|
6
|
+
class Resolver
|
7
|
+
# The session class is used by the DatabaseSelector::Resolver to save
|
8
|
+
# timestamps of the last write in the session.
|
9
|
+
#
|
10
|
+
# The last_write is used to determine whether it's safe to read
|
11
|
+
# from the replica or the request needs to be sent to the primary.
|
12
|
+
class Session # :nodoc:
|
13
|
+
def self.call(request)
|
14
|
+
new(request.session)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Converts time to a timestamp that represents milliseconds since
|
18
|
+
# epoch.
|
19
|
+
def self.convert_time_to_timestamp(time)
|
20
|
+
time.to_i * 1000 + time.usec / 1000
|
21
|
+
end
|
22
|
+
|
23
|
+
# Converts milliseconds since epoch timestamp into a time object.
|
24
|
+
def self.convert_timestamp_to_time(timestamp)
|
25
|
+
timestamp ? Time.at(timestamp / 1000, (timestamp % 1000) * 1000) : Time.at(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(session)
|
29
|
+
@session = session
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :session
|
33
|
+
|
34
|
+
def last_write_timestamp
|
35
|
+
self.class.convert_timestamp_to_time(session[:last_write])
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_last_write_timestamp
|
39
|
+
session[:last_write] = self.class.convert_time_to_timestamp(Time.now)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "benchmark"
|
3
4
|
require "set"
|
4
5
|
require "zlib"
|
5
6
|
require "active_support/core_ext/module/attribute_accessors"
|
7
|
+
require "active_support/actionable_error"
|
6
8
|
|
7
9
|
module ActiveRecord
|
8
|
-
class MigrationError < ActiveRecordError#:nodoc:
|
10
|
+
class MigrationError < ActiveRecordError #:nodoc:
|
9
11
|
def initialize(message = nil)
|
10
12
|
message = "\n\n#{message}\n\n" if message
|
11
13
|
super
|
@@ -22,7 +24,7 @@ module ActiveRecord
|
|
22
24
|
# t.string :zipcode
|
23
25
|
# end
|
24
26
|
#
|
25
|
-
# execute
|
27
|
+
# execute <<~SQL
|
26
28
|
# ALTER TABLE distributors
|
27
29
|
# ADD CONSTRAINT zipchk
|
28
30
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -40,7 +42,7 @@ module ActiveRecord
|
|
40
42
|
# t.string :zipcode
|
41
43
|
# end
|
42
44
|
#
|
43
|
-
# execute
|
45
|
+
# execute <<~SQL
|
44
46
|
# ALTER TABLE distributors
|
45
47
|
# ADD CONSTRAINT zipchk
|
46
48
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -48,7 +50,7 @@ module ActiveRecord
|
|
48
50
|
# end
|
49
51
|
#
|
50
52
|
# def down
|
51
|
-
# execute
|
53
|
+
# execute <<~SQL
|
52
54
|
# ALTER TABLE distributors
|
53
55
|
# DROP CONSTRAINT zipchk
|
54
56
|
# SQL
|
@@ -67,7 +69,7 @@ module ActiveRecord
|
|
67
69
|
#
|
68
70
|
# reversible do |dir|
|
69
71
|
# dir.up do
|
70
|
-
# execute
|
72
|
+
# execute <<~SQL
|
71
73
|
# ALTER TABLE distributors
|
72
74
|
# ADD CONSTRAINT zipchk
|
73
75
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -75,7 +77,7 @@ module ActiveRecord
|
|
75
77
|
# end
|
76
78
|
#
|
77
79
|
# dir.down do
|
78
|
-
# execute
|
80
|
+
# execute <<~SQL
|
79
81
|
# ALTER TABLE distributors
|
80
82
|
# DROP CONSTRAINT zipchk
|
81
83
|
# SQL
|
@@ -86,7 +88,7 @@ module ActiveRecord
|
|
86
88
|
class IrreversibleMigration < MigrationError
|
87
89
|
end
|
88
90
|
|
89
|
-
class DuplicateMigrationVersionError < MigrationError#:nodoc:
|
91
|
+
class DuplicateMigrationVersionError < MigrationError #:nodoc:
|
90
92
|
def initialize(version = nil)
|
91
93
|
if version
|
92
94
|
super("Multiple migrations have the version number #{version}.")
|
@@ -96,7 +98,7 @@ module ActiveRecord
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
|
-
class DuplicateMigrationNameError < MigrationError#:nodoc:
|
101
|
+
class DuplicateMigrationNameError < MigrationError #:nodoc:
|
100
102
|
def initialize(name = nil)
|
101
103
|
if name
|
102
104
|
super("Multiple migrations have the name #{name}.")
|
@@ -116,7 +118,7 @@ module ActiveRecord
|
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
119
|
-
class IllegalMigrationNameError < MigrationError#:nodoc:
|
121
|
+
class IllegalMigrationNameError < MigrationError #:nodoc:
|
120
122
|
def initialize(name = nil)
|
121
123
|
if name
|
122
124
|
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
@@ -126,12 +128,18 @@ module ActiveRecord
|
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
129
|
-
class PendingMigrationError < MigrationError#:nodoc:
|
131
|
+
class PendingMigrationError < MigrationError #:nodoc:
|
132
|
+
include ActiveSupport::ActionableError
|
133
|
+
|
134
|
+
action "Run pending migrations" do
|
135
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
136
|
+
end
|
137
|
+
|
130
138
|
def initialize(message = nil)
|
131
139
|
if !message && defined?(Rails.env)
|
132
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
140
|
+
super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
|
133
141
|
elsif !message
|
134
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
142
|
+
super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
|
135
143
|
else
|
136
144
|
super
|
137
145
|
end
|
@@ -139,8 +147,8 @@ module ActiveRecord
|
|
139
147
|
end
|
140
148
|
|
141
149
|
class ConcurrentMigrationError < MigrationError #:nodoc:
|
142
|
-
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
|
143
|
-
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
|
150
|
+
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
|
151
|
+
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
|
144
152
|
|
145
153
|
def initialize(message = DEFAULT_MESSAGE)
|
146
154
|
super
|
@@ -149,7 +157,7 @@ module ActiveRecord
|
|
149
157
|
|
150
158
|
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
151
159
|
def initialize
|
152
|
-
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n
|
160
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
|
153
161
|
if defined?(Rails.env)
|
154
162
|
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
155
163
|
else
|
@@ -160,7 +168,7 @@ module ActiveRecord
|
|
160
168
|
|
161
169
|
class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
|
162
170
|
def initialize(env = "production")
|
163
|
-
msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
|
171
|
+
msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
|
164
172
|
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
165
173
|
msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
166
174
|
super(msg)
|
@@ -169,10 +177,10 @@ module ActiveRecord
|
|
169
177
|
|
170
178
|
class EnvironmentMismatchError < ActiveRecordError
|
171
179
|
def initialize(current: nil, stored: nil)
|
172
|
-
msg =
|
180
|
+
msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
|
173
181
|
msg << "You are running in `#{ current }` environment. "
|
174
182
|
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
175
|
-
msg << "
|
183
|
+
msg << " rails db:environment:set"
|
176
184
|
if defined?(Rails.env)
|
177
185
|
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
178
186
|
else
|
@@ -307,7 +315,7 @@ module ActiveRecord
|
|
307
315
|
# named +column_name+ from the table called +table_name+.
|
308
316
|
# * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
|
309
317
|
# columns from the table definition.
|
310
|
-
# * <tt>remove_foreign_key(from_table,
|
318
|
+
# * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
|
311
319
|
# given foreign key from the table called +table_name+.
|
312
320
|
# * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
|
313
321
|
# specified by +column_names+.
|
@@ -351,7 +359,7 @@ module ActiveRecord
|
|
351
359
|
# <tt>rails db:migrate</tt>. This will update the database by running all of the
|
352
360
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
353
361
|
# (see "About the schema_migrations table" section below) if missing. It will also
|
354
|
-
# invoke the db:schema:dump
|
362
|
+
# invoke the db:schema:dump command, which will update your db/schema.rb file
|
355
363
|
# to match the structure of your database.
|
356
364
|
#
|
357
365
|
# To roll the database back to a previous migration version, use
|
@@ -486,9 +494,9 @@ module ActiveRecord
|
|
486
494
|
# This migration will create the horses table for you on the way up, and
|
487
495
|
# automatically figure out how to drop the table on the way down.
|
488
496
|
#
|
489
|
-
# Some commands
|
490
|
-
#
|
491
|
-
#
|
497
|
+
# Some commands cannot be reversed. If you care to define how to move up
|
498
|
+
# and down in these cases, you should define the +up+ and +down+ methods
|
499
|
+
# as before.
|
492
500
|
#
|
493
501
|
# If a command cannot be reversed, an
|
494
502
|
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
|
@@ -519,10 +527,10 @@ module ActiveRecord
|
|
519
527
|
autoload :Compatibility, "active_record/migration/compatibility"
|
520
528
|
|
521
529
|
# This must be defined before the inherited hook, below
|
522
|
-
class Current < Migration
|
530
|
+
class Current < Migration #:nodoc:
|
523
531
|
end
|
524
532
|
|
525
|
-
def self.inherited(subclass)
|
533
|
+
def self.inherited(subclass) #:nodoc:
|
526
534
|
super
|
527
535
|
if subclass.superclass == Migration
|
528
536
|
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
|
@@ -540,7 +548,7 @@ module ActiveRecord
|
|
540
548
|
ActiveRecord::VERSION::STRING.to_f
|
541
549
|
end
|
542
550
|
|
543
|
-
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/
|
551
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
|
544
552
|
|
545
553
|
# This class is used to verify that all migrations have been run before
|
546
554
|
# loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
|
@@ -567,10 +575,10 @@ module ActiveRecord
|
|
567
575
|
end
|
568
576
|
|
569
577
|
class << self
|
570
|
-
attr_accessor :delegate
|
571
|
-
attr_accessor :disable_ddl_transaction
|
578
|
+
attr_accessor :delegate #:nodoc:
|
579
|
+
attr_accessor :disable_ddl_transaction #:nodoc:
|
572
580
|
|
573
|
-
def nearest_delegate
|
581
|
+
def nearest_delegate #:nodoc:
|
574
582
|
delegate || superclass.nearest_delegate
|
575
583
|
end
|
576
584
|
|
@@ -594,13 +602,13 @@ module ActiveRecord
|
|
594
602
|
end
|
595
603
|
end
|
596
604
|
|
597
|
-
def maintain_test_schema!
|
605
|
+
def maintain_test_schema! #:nodoc:
|
598
606
|
if ActiveRecord::Base.maintain_test_schema
|
599
607
|
suppress_messages { load_schema_if_pending! }
|
600
608
|
end
|
601
609
|
end
|
602
610
|
|
603
|
-
def method_missing(name, *args, &block)
|
611
|
+
def method_missing(name, *args, &block) #:nodoc:
|
604
612
|
nearest_delegate.send(name, *args, &block)
|
605
613
|
end
|
606
614
|
|
@@ -617,7 +625,7 @@ module ActiveRecord
|
|
617
625
|
end
|
618
626
|
end
|
619
627
|
|
620
|
-
def disable_ddl_transaction
|
628
|
+
def disable_ddl_transaction #:nodoc:
|
621
629
|
self.class.disable_ddl_transaction
|
622
630
|
end
|
623
631
|
|
@@ -677,15 +685,13 @@ module ActiveRecord
|
|
677
685
|
if connection.respond_to? :revert
|
678
686
|
connection.revert { yield }
|
679
687
|
else
|
680
|
-
recorder =
|
688
|
+
recorder = command_recorder
|
681
689
|
@connection = recorder
|
682
690
|
suppress_messages do
|
683
691
|
connection.revert { yield }
|
684
692
|
end
|
685
693
|
@connection = recorder.delegate
|
686
|
-
recorder.
|
687
|
-
send(cmd, *args, &block)
|
688
|
-
end
|
694
|
+
recorder.replay(self)
|
689
695
|
end
|
690
696
|
end
|
691
697
|
end
|
@@ -694,7 +700,7 @@ module ActiveRecord
|
|
694
700
|
connection.respond_to?(:reverting) && connection.reverting
|
695
701
|
end
|
696
702
|
|
697
|
-
ReversibleBlockHelper = Struct.new(:reverting) do
|
703
|
+
ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
|
698
704
|
def up
|
699
705
|
yield unless reverting
|
700
706
|
end
|
@@ -830,10 +836,14 @@ module ActiveRecord
|
|
830
836
|
write "== %s %s" % [text, "=" * length]
|
831
837
|
end
|
832
838
|
|
839
|
+
# Takes a message argument and outputs it as is.
|
840
|
+
# A second boolean argument can be passed to specify whether to indent or not.
|
833
841
|
def say(message, subitem = false)
|
834
842
|
write "#{subitem ? " ->" : "--"} #{message}"
|
835
843
|
end
|
836
844
|
|
845
|
+
# Outputs text along with how long it took to run its block.
|
846
|
+
# If the block returns an integer it assumes it is the number of rows affected.
|
837
847
|
def say_with_time(message)
|
838
848
|
say(message)
|
839
849
|
result = nil
|
@@ -843,6 +853,7 @@ module ActiveRecord
|
|
843
853
|
result
|
844
854
|
end
|
845
855
|
|
856
|
+
# Takes a block as an argument and suppresses any output generated by the block.
|
846
857
|
def suppress_messages
|
847
858
|
save, self.verbose = verbose, false
|
848
859
|
yield
|
@@ -874,18 +885,19 @@ module ActiveRecord
|
|
874
885
|
|
875
886
|
def copy(destination, sources, options = {})
|
876
887
|
copied = []
|
888
|
+
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
877
889
|
|
878
890
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
879
891
|
|
880
|
-
destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
|
892
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
881
893
|
last = destination_migrations.last
|
882
894
|
sources.each do |scope, path|
|
883
|
-
source_migrations = ActiveRecord::MigrationContext.new(path).migrations
|
895
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
884
896
|
|
885
897
|
source_migrations.each do |migration|
|
886
898
|
source = File.binread(migration.filename)
|
887
899
|
inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
|
888
|
-
magic_comments = ""
|
900
|
+
magic_comments = +""
|
889
901
|
loop do
|
890
902
|
# If we have a magic comment in the original migration,
|
891
903
|
# insert our comment after the first newline(end of the magic comment line)
|
@@ -956,6 +968,10 @@ module ActiveRecord
|
|
956
968
|
yield
|
957
969
|
end
|
958
970
|
end
|
971
|
+
|
972
|
+
def command_recorder
|
973
|
+
CommandRecorder.new(connection)
|
974
|
+
end
|
959
975
|
end
|
960
976
|
|
961
977
|
# MigrationProxy is used to defer loading of the actual migration classes
|
@@ -998,11 +1014,12 @@ module ActiveRecord
|
|
998
1014
|
end
|
999
1015
|
end
|
1000
1016
|
|
1001
|
-
class MigrationContext
|
1002
|
-
attr_reader :migrations_paths
|
1017
|
+
class MigrationContext #:nodoc:
|
1018
|
+
attr_reader :migrations_paths, :schema_migration
|
1003
1019
|
|
1004
|
-
def initialize(migrations_paths)
|
1020
|
+
def initialize(migrations_paths, schema_migration)
|
1005
1021
|
@migrations_paths = migrations_paths
|
1022
|
+
@schema_migration = schema_migration
|
1006
1023
|
end
|
1007
1024
|
|
1008
1025
|
def migrate(target_version = nil, &block)
|
@@ -1033,7 +1050,7 @@ module ActiveRecord
|
|
1033
1050
|
migrations
|
1034
1051
|
end
|
1035
1052
|
|
1036
|
-
Migrator.new(:up, selected_migrations, target_version).migrate
|
1053
|
+
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1037
1054
|
end
|
1038
1055
|
|
1039
1056
|
def down(target_version = nil)
|
@@ -1043,20 +1060,20 @@ module ActiveRecord
|
|
1043
1060
|
migrations
|
1044
1061
|
end
|
1045
1062
|
|
1046
|
-
Migrator.new(:down, selected_migrations, target_version).migrate
|
1063
|
+
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1047
1064
|
end
|
1048
1065
|
|
1049
1066
|
def run(direction, target_version)
|
1050
|
-
Migrator.new(direction, migrations, target_version).run
|
1067
|
+
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1051
1068
|
end
|
1052
1069
|
|
1053
1070
|
def open
|
1054
|
-
Migrator.new(:up, migrations,
|
1071
|
+
Migrator.new(:up, migrations, schema_migration)
|
1055
1072
|
end
|
1056
1073
|
|
1057
1074
|
def get_all_versions
|
1058
|
-
if
|
1059
|
-
|
1075
|
+
if schema_migration.table_exists?
|
1076
|
+
schema_migration.all_versions.map(&:to_i)
|
1060
1077
|
else
|
1061
1078
|
[]
|
1062
1079
|
end
|
@@ -1079,10 +1096,6 @@ module ActiveRecord
|
|
1079
1096
|
migrations.last || NullMigration.new
|
1080
1097
|
end
|
1081
1098
|
|
1082
|
-
def parse_migration_filename(filename) # :nodoc:
|
1083
|
-
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1084
|
-
end
|
1085
|
-
|
1086
1099
|
def migrations
|
1087
1100
|
migrations = migration_files.map do |file|
|
1088
1101
|
version, name, scope = parse_migration_filename(file)
|
@@ -1097,12 +1110,12 @@ module ActiveRecord
|
|
1097
1110
|
end
|
1098
1111
|
|
1099
1112
|
def migrations_status
|
1100
|
-
db_list =
|
1113
|
+
db_list = schema_migration.normalized_versions
|
1101
1114
|
|
1102
1115
|
file_list = migration_files.map do |file|
|
1103
1116
|
version, name, scope = parse_migration_filename(file)
|
1104
1117
|
raise IllegalMigrationNameError.new(file) unless version
|
1105
|
-
version =
|
1118
|
+
version = schema_migration.normalize_migration_number(version)
|
1106
1119
|
status = db_list.delete(version) ? "up" : "down"
|
1107
1120
|
[status, version, (name + scope).humanize]
|
1108
1121
|
end.compact
|
@@ -1114,11 +1127,6 @@ module ActiveRecord
|
|
1114
1127
|
(db_list + file_list).sort_by { |_, version, _| version }
|
1115
1128
|
end
|
1116
1129
|
|
1117
|
-
def migration_files
|
1118
|
-
paths = Array(migrations_paths)
|
1119
|
-
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1120
|
-
end
|
1121
|
-
|
1122
1130
|
def current_environment
|
1123
1131
|
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1124
1132
|
end
|
@@ -1137,8 +1145,17 @@ module ActiveRecord
|
|
1137
1145
|
end
|
1138
1146
|
|
1139
1147
|
private
|
1148
|
+
def migration_files
|
1149
|
+
paths = Array(migrations_paths)
|
1150
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def parse_migration_filename(filename)
|
1154
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1155
|
+
end
|
1156
|
+
|
1140
1157
|
def move(direction, steps)
|
1141
|
-
migrator = Migrator.new(direction, migrations)
|
1158
|
+
migrator = Migrator.new(direction, migrations, schema_migration)
|
1142
1159
|
|
1143
1160
|
if current_version != 0 && !migrator.current_migration
|
1144
1161
|
raise UnknownMigrationVersionError.new(current_version)
|
@@ -1161,30 +1178,24 @@ module ActiveRecord
|
|
1161
1178
|
class << self
|
1162
1179
|
attr_accessor :migrations_paths
|
1163
1180
|
|
1164
|
-
def migrations_path=(path)
|
1165
|
-
ActiveSupport::Deprecation.warn \
|
1166
|
-
"`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
|
1167
|
-
"You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
|
1168
|
-
self.migrations_paths = [path]
|
1169
|
-
end
|
1170
|
-
|
1171
1181
|
# For cases where a table doesn't exist like loading from schema cache
|
1172
1182
|
def current_version
|
1173
|
-
MigrationContext.new(migrations_paths).current_version
|
1183
|
+
MigrationContext.new(migrations_paths, SchemaMigration).current_version
|
1174
1184
|
end
|
1175
1185
|
end
|
1176
1186
|
|
1177
1187
|
self.migrations_paths = ["db/migrate"]
|
1178
1188
|
|
1179
|
-
def initialize(direction, migrations, target_version = nil)
|
1189
|
+
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1180
1190
|
@direction = direction
|
1181
1191
|
@target_version = target_version
|
1182
1192
|
@migrated_versions = nil
|
1183
1193
|
@migrations = migrations
|
1194
|
+
@schema_migration = schema_migration
|
1184
1195
|
|
1185
1196
|
validate(@migrations)
|
1186
1197
|
|
1187
|
-
|
1198
|
+
@schema_migration.create_table
|
1188
1199
|
ActiveRecord::InternalMetadata.create_table
|
1189
1200
|
end
|
1190
1201
|
|
@@ -1238,7 +1249,7 @@ module ActiveRecord
|
|
1238
1249
|
end
|
1239
1250
|
|
1240
1251
|
def load_migrated
|
1241
|
-
@migrated_versions = Set.new(
|
1252
|
+
@migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
|
1242
1253
|
end
|
1243
1254
|
|
1244
1255
|
private
|
@@ -1293,7 +1304,7 @@ module ActiveRecord
|
|
1293
1304
|
record_version_state_after_migrating(migration.version)
|
1294
1305
|
end
|
1295
1306
|
rescue => e
|
1296
|
-
msg = "An error has occurred, "
|
1307
|
+
msg = +"An error has occurred, "
|
1297
1308
|
msg << "this and " if use_transaction?(migration)
|
1298
1309
|
msg << "all later migrations canceled:\n\n#{e}"
|
1299
1310
|
raise StandardError, msg, e.backtrace
|
@@ -1322,10 +1333,10 @@ module ActiveRecord
|
|
1322
1333
|
def record_version_state_after_migrating(version)
|
1323
1334
|
if down?
|
1324
1335
|
migrated.delete(version)
|
1325
|
-
|
1336
|
+
@schema_migration.delete_by(version: version.to_s)
|
1326
1337
|
else
|
1327
1338
|
migrated << version
|
1328
|
-
|
1339
|
+
@schema_migration.create!(version: version.to_s)
|
1329
1340
|
end
|
1330
1341
|
end
|
1331
1342
|
|
@@ -1351,7 +1362,7 @@ module ActiveRecord
|
|
1351
1362
|
end
|
1352
1363
|
|
1353
1364
|
def use_advisory_lock?
|
1354
|
-
Base.connection.
|
1365
|
+
Base.connection.advisory_locks_enabled?
|
1355
1366
|
end
|
1356
1367
|
|
1357
1368
|
def with_advisory_lock
|