activerecord 5.2.4.2 → 6.0.2.2
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 +715 -566
- 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/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- 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 +3 -13
- 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 +12 -23
- 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 +14 -14
- 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 +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- 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 +2 -2
- 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 +104 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
- 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 +187 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -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 +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -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/money.rb +2 -2
- 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 +164 -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 +120 -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 +129 -141
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +103 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -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 +37 -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 +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -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 +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- 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 +33 -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 +199 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +23 -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 +213 -64
- 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 +4 -5
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +30 -3
- 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 +194 -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 +23 -0
- data/lib/active_record/test_fixtures.rb +225 -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.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -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 -24
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -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,88 @@
|
|
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, prevent_writes: true) do
|
50
|
+
instrumenter.instrument("database_selector.active_record.read_from_primary") do
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def read_from_replica(&blk)
|
57
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role) do
|
58
|
+
instrumenter.instrument("database_selector.active_record.read_from_replica") do
|
59
|
+
yield
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def write_to_primary(&blk)
|
65
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do
|
66
|
+
instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
|
67
|
+
yield
|
68
|
+
ensure
|
69
|
+
context.update_last_write_timestamp
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def read_from_primary?
|
75
|
+
!time_since_last_write_ok?
|
76
|
+
end
|
77
|
+
|
78
|
+
def send_to_replica_delay
|
79
|
+
delay
|
80
|
+
end
|
81
|
+
|
82
|
+
def time_since_last_write_ok?
|
83
|
+
Time.now - context.last_write_timestamp >= send_to_replica_delay
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
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
|
|
@@ -580,27 +588,35 @@ module ActiveRecord
|
|
580
588
|
end
|
581
589
|
|
582
590
|
def load_schema_if_pending!
|
583
|
-
|
591
|
+
current_config = Base.connection_config
|
592
|
+
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
|
593
|
+
|
594
|
+
needs_update = !all_configs.all? do |db_config|
|
595
|
+
Tasks::DatabaseTasks.schema_up_to_date?(db_config.config, ActiveRecord::Base.schema_format, nil, Rails.env, db_config.spec_name)
|
596
|
+
end
|
597
|
+
|
598
|
+
if needs_update
|
584
599
|
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
585
600
|
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
586
601
|
FileUtils.cd(root) do
|
587
|
-
current_config = Base.connection_config
|
588
602
|
Base.clear_all_connections!
|
589
603
|
system("bin/rails db:test:prepare")
|
590
|
-
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
591
|
-
Base.establish_connection(current_config)
|
592
604
|
end
|
593
|
-
check_pending!
|
594
605
|
end
|
606
|
+
|
607
|
+
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
608
|
+
Base.establish_connection(current_config)
|
609
|
+
|
610
|
+
check_pending!
|
595
611
|
end
|
596
612
|
|
597
|
-
def maintain_test_schema!
|
613
|
+
def maintain_test_schema! #:nodoc:
|
598
614
|
if ActiveRecord::Base.maintain_test_schema
|
599
615
|
suppress_messages { load_schema_if_pending! }
|
600
616
|
end
|
601
617
|
end
|
602
618
|
|
603
|
-
def method_missing(name, *args, &block)
|
619
|
+
def method_missing(name, *args, &block) #:nodoc:
|
604
620
|
nearest_delegate.send(name, *args, &block)
|
605
621
|
end
|
606
622
|
|
@@ -617,7 +633,7 @@ module ActiveRecord
|
|
617
633
|
end
|
618
634
|
end
|
619
635
|
|
620
|
-
def disable_ddl_transaction
|
636
|
+
def disable_ddl_transaction #:nodoc:
|
621
637
|
self.class.disable_ddl_transaction
|
622
638
|
end
|
623
639
|
|
@@ -677,15 +693,13 @@ module ActiveRecord
|
|
677
693
|
if connection.respond_to? :revert
|
678
694
|
connection.revert { yield }
|
679
695
|
else
|
680
|
-
recorder =
|
696
|
+
recorder = command_recorder
|
681
697
|
@connection = recorder
|
682
698
|
suppress_messages do
|
683
699
|
connection.revert { yield }
|
684
700
|
end
|
685
701
|
@connection = recorder.delegate
|
686
|
-
recorder.
|
687
|
-
send(cmd, *args, &block)
|
688
|
-
end
|
702
|
+
recorder.replay(self)
|
689
703
|
end
|
690
704
|
end
|
691
705
|
end
|
@@ -694,7 +708,7 @@ module ActiveRecord
|
|
694
708
|
connection.respond_to?(:reverting) && connection.reverting
|
695
709
|
end
|
696
710
|
|
697
|
-
ReversibleBlockHelper = Struct.new(:reverting) do
|
711
|
+
ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
|
698
712
|
def up
|
699
713
|
yield unless reverting
|
700
714
|
end
|
@@ -830,10 +844,14 @@ module ActiveRecord
|
|
830
844
|
write "== %s %s" % [text, "=" * length]
|
831
845
|
end
|
832
846
|
|
847
|
+
# Takes a message argument and outputs it as is.
|
848
|
+
# A second boolean argument can be passed to specify whether to indent or not.
|
833
849
|
def say(message, subitem = false)
|
834
850
|
write "#{subitem ? " ->" : "--"} #{message}"
|
835
851
|
end
|
836
852
|
|
853
|
+
# Outputs text along with how long it took to run its block.
|
854
|
+
# If the block returns an integer it assumes it is the number of rows affected.
|
837
855
|
def say_with_time(message)
|
838
856
|
say(message)
|
839
857
|
result = nil
|
@@ -843,6 +861,7 @@ module ActiveRecord
|
|
843
861
|
result
|
844
862
|
end
|
845
863
|
|
864
|
+
# Takes a block as an argument and suppresses any output generated by the block.
|
846
865
|
def suppress_messages
|
847
866
|
save, self.verbose = verbose, false
|
848
867
|
yield
|
@@ -874,18 +893,19 @@ module ActiveRecord
|
|
874
893
|
|
875
894
|
def copy(destination, sources, options = {})
|
876
895
|
copied = []
|
896
|
+
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
877
897
|
|
878
898
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
879
899
|
|
880
|
-
destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
|
900
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
881
901
|
last = destination_migrations.last
|
882
902
|
sources.each do |scope, path|
|
883
|
-
source_migrations = ActiveRecord::MigrationContext.new(path).migrations
|
903
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
884
904
|
|
885
905
|
source_migrations.each do |migration|
|
886
906
|
source = File.binread(migration.filename)
|
887
907
|
inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
|
888
|
-
magic_comments = ""
|
908
|
+
magic_comments = +""
|
889
909
|
loop do
|
890
910
|
# If we have a magic comment in the original migration,
|
891
911
|
# insert our comment after the first newline(end of the magic comment line)
|
@@ -956,6 +976,10 @@ module ActiveRecord
|
|
956
976
|
yield
|
957
977
|
end
|
958
978
|
end
|
979
|
+
|
980
|
+
def command_recorder
|
981
|
+
CommandRecorder.new(connection)
|
982
|
+
end
|
959
983
|
end
|
960
984
|
|
961
985
|
# MigrationProxy is used to defer loading of the actual migration classes
|
@@ -998,11 +1022,12 @@ module ActiveRecord
|
|
998
1022
|
end
|
999
1023
|
end
|
1000
1024
|
|
1001
|
-
class MigrationContext
|
1002
|
-
attr_reader :migrations_paths
|
1025
|
+
class MigrationContext #:nodoc:
|
1026
|
+
attr_reader :migrations_paths, :schema_migration
|
1003
1027
|
|
1004
|
-
def initialize(migrations_paths)
|
1028
|
+
def initialize(migrations_paths, schema_migration)
|
1005
1029
|
@migrations_paths = migrations_paths
|
1030
|
+
@schema_migration = schema_migration
|
1006
1031
|
end
|
1007
1032
|
|
1008
1033
|
def migrate(target_version = nil, &block)
|
@@ -1033,7 +1058,7 @@ module ActiveRecord
|
|
1033
1058
|
migrations
|
1034
1059
|
end
|
1035
1060
|
|
1036
|
-
Migrator.new(:up, selected_migrations, target_version).migrate
|
1061
|
+
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1037
1062
|
end
|
1038
1063
|
|
1039
1064
|
def down(target_version = nil)
|
@@ -1043,20 +1068,20 @@ module ActiveRecord
|
|
1043
1068
|
migrations
|
1044
1069
|
end
|
1045
1070
|
|
1046
|
-
Migrator.new(:down, selected_migrations, target_version).migrate
|
1071
|
+
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1047
1072
|
end
|
1048
1073
|
|
1049
1074
|
def run(direction, target_version)
|
1050
|
-
Migrator.new(direction, migrations, target_version).run
|
1075
|
+
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1051
1076
|
end
|
1052
1077
|
|
1053
1078
|
def open
|
1054
|
-
Migrator.new(:up, migrations,
|
1079
|
+
Migrator.new(:up, migrations, schema_migration)
|
1055
1080
|
end
|
1056
1081
|
|
1057
1082
|
def get_all_versions
|
1058
|
-
if
|
1059
|
-
|
1083
|
+
if schema_migration.table_exists?
|
1084
|
+
schema_migration.all_versions.map(&:to_i)
|
1060
1085
|
else
|
1061
1086
|
[]
|
1062
1087
|
end
|
@@ -1079,10 +1104,6 @@ module ActiveRecord
|
|
1079
1104
|
migrations.last || NullMigration.new
|
1080
1105
|
end
|
1081
1106
|
|
1082
|
-
def parse_migration_filename(filename) # :nodoc:
|
1083
|
-
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1084
|
-
end
|
1085
|
-
|
1086
1107
|
def migrations
|
1087
1108
|
migrations = migration_files.map do |file|
|
1088
1109
|
version, name, scope = parse_migration_filename(file)
|
@@ -1097,12 +1118,12 @@ module ActiveRecord
|
|
1097
1118
|
end
|
1098
1119
|
|
1099
1120
|
def migrations_status
|
1100
|
-
db_list =
|
1121
|
+
db_list = schema_migration.normalized_versions
|
1101
1122
|
|
1102
1123
|
file_list = migration_files.map do |file|
|
1103
1124
|
version, name, scope = parse_migration_filename(file)
|
1104
1125
|
raise IllegalMigrationNameError.new(file) unless version
|
1105
|
-
version =
|
1126
|
+
version = schema_migration.normalize_migration_number(version)
|
1106
1127
|
status = db_list.delete(version) ? "up" : "down"
|
1107
1128
|
[status, version, (name + scope).humanize]
|
1108
1129
|
end.compact
|
@@ -1114,11 +1135,6 @@ module ActiveRecord
|
|
1114
1135
|
(db_list + file_list).sort_by { |_, version, _| version }
|
1115
1136
|
end
|
1116
1137
|
|
1117
|
-
def migration_files
|
1118
|
-
paths = Array(migrations_paths)
|
1119
|
-
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1120
|
-
end
|
1121
|
-
|
1122
1138
|
def current_environment
|
1123
1139
|
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1124
1140
|
end
|
@@ -1137,8 +1153,17 @@ module ActiveRecord
|
|
1137
1153
|
end
|
1138
1154
|
|
1139
1155
|
private
|
1156
|
+
def migration_files
|
1157
|
+
paths = Array(migrations_paths)
|
1158
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
def parse_migration_filename(filename)
|
1162
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1163
|
+
end
|
1164
|
+
|
1140
1165
|
def move(direction, steps)
|
1141
|
-
migrator = Migrator.new(direction, migrations)
|
1166
|
+
migrator = Migrator.new(direction, migrations, schema_migration)
|
1142
1167
|
|
1143
1168
|
if current_version != 0 && !migrator.current_migration
|
1144
1169
|
raise UnknownMigrationVersionError.new(current_version)
|
@@ -1161,30 +1186,24 @@ module ActiveRecord
|
|
1161
1186
|
class << self
|
1162
1187
|
attr_accessor :migrations_paths
|
1163
1188
|
|
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
1189
|
# For cases where a table doesn't exist like loading from schema cache
|
1172
1190
|
def current_version
|
1173
|
-
MigrationContext.new(migrations_paths).current_version
|
1191
|
+
MigrationContext.new(migrations_paths, SchemaMigration).current_version
|
1174
1192
|
end
|
1175
1193
|
end
|
1176
1194
|
|
1177
1195
|
self.migrations_paths = ["db/migrate"]
|
1178
1196
|
|
1179
|
-
def initialize(direction, migrations, target_version = nil)
|
1197
|
+
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1180
1198
|
@direction = direction
|
1181
1199
|
@target_version = target_version
|
1182
1200
|
@migrated_versions = nil
|
1183
1201
|
@migrations = migrations
|
1202
|
+
@schema_migration = schema_migration
|
1184
1203
|
|
1185
1204
|
validate(@migrations)
|
1186
1205
|
|
1187
|
-
|
1206
|
+
@schema_migration.create_table
|
1188
1207
|
ActiveRecord::InternalMetadata.create_table
|
1189
1208
|
end
|
1190
1209
|
|
@@ -1238,7 +1257,7 @@ module ActiveRecord
|
|
1238
1257
|
end
|
1239
1258
|
|
1240
1259
|
def load_migrated
|
1241
|
-
@migrated_versions = Set.new(
|
1260
|
+
@migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
|
1242
1261
|
end
|
1243
1262
|
|
1244
1263
|
private
|
@@ -1293,7 +1312,7 @@ module ActiveRecord
|
|
1293
1312
|
record_version_state_after_migrating(migration.version)
|
1294
1313
|
end
|
1295
1314
|
rescue => e
|
1296
|
-
msg = "An error has occurred, "
|
1315
|
+
msg = +"An error has occurred, "
|
1297
1316
|
msg << "this and " if use_transaction?(migration)
|
1298
1317
|
msg << "all later migrations canceled:\n\n#{e}"
|
1299
1318
|
raise StandardError, msg, e.backtrace
|
@@ -1322,10 +1341,10 @@ module ActiveRecord
|
|
1322
1341
|
def record_version_state_after_migrating(version)
|
1323
1342
|
if down?
|
1324
1343
|
migrated.delete(version)
|
1325
|
-
|
1344
|
+
@schema_migration.delete_by(version: version.to_s)
|
1326
1345
|
else
|
1327
1346
|
migrated << version
|
1328
|
-
|
1347
|
+
@schema_migration.create!(version: version.to_s)
|
1329
1348
|
end
|
1330
1349
|
end
|
1331
1350
|
|
@@ -1351,7 +1370,7 @@ module ActiveRecord
|
|
1351
1370
|
end
|
1352
1371
|
|
1353
1372
|
def use_advisory_lock?
|
1354
|
-
Base.connection.
|
1373
|
+
Base.connection.advisory_locks_enabled?
|
1355
1374
|
end
|
1356
1375
|
|
1357
1376
|
def with_advisory_lock
|