activerecord 6.0.6.1 → 6.1.7.6
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 +1152 -779
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +49 -26
- data/lib/active_record/associations/association_scope.rb +18 -20
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +32 -18
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +14 -8
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +118 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -8
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +264 -63
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +69 -34
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +38 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +24 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +72 -18
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +89 -14
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +279 -101
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +104 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +61 -38
- data/lib/active_record/relation/query_methods.rb +322 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/relation.rb +100 -81
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -3
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +79 -31
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +25 -26
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -12,26 +12,24 @@ module ActiveRecord
|
|
12
12
|
delegate :connection, :establish_connection, :clear_active_connections!,
|
13
13
|
to: ActiveRecord::Base
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def self.using_database_configurations?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(db_config)
|
20
|
+
@db_config = db_config
|
21
|
+
@configuration_hash = db_config.configuration_hash
|
17
22
|
end
|
18
23
|
|
19
24
|
def create(master_established = false)
|
20
25
|
establish_master_connection unless master_established
|
21
|
-
connection.create_database
|
22
|
-
|
23
|
-
establish_connection configuration
|
24
|
-
rescue ActiveRecord::StatementInvalid => error
|
25
|
-
if error.cause.is_a?(PG::DuplicateDatabase)
|
26
|
-
raise DatabaseAlreadyExists
|
27
|
-
else
|
28
|
-
raise
|
29
|
-
end
|
26
|
+
connection.create_database(db_config.database, configuration_hash.merge(encoding: encoding))
|
27
|
+
establish_connection(db_config)
|
30
28
|
end
|
31
29
|
|
32
30
|
def drop
|
33
31
|
establish_master_connection
|
34
|
-
connection.drop_database
|
32
|
+
connection.drop_database(db_config.database)
|
35
33
|
end
|
36
34
|
|
37
35
|
def charset
|
@@ -54,14 +52,14 @@ module ActiveRecord
|
|
54
52
|
search_path = \
|
55
53
|
case ActiveRecord::Base.dump_schemas
|
56
54
|
when :schema_search_path
|
57
|
-
|
55
|
+
configuration_hash[:schema_search_path]
|
58
56
|
when :all
|
59
57
|
nil
|
60
58
|
when String
|
61
59
|
ActiveRecord::Base.dump_schemas
|
62
60
|
end
|
63
61
|
|
64
|
-
args = ["-
|
62
|
+
args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
|
65
63
|
args.concat(Array(extra_flags)) if extra_flags
|
66
64
|
unless search_path.blank?
|
67
65
|
args += search_path.split(",").map do |part|
|
@@ -74,7 +72,7 @@ module ActiveRecord
|
|
74
72
|
args += ignore_tables.flat_map { |table| ["-T", table] }
|
75
73
|
end
|
76
74
|
|
77
|
-
args <<
|
75
|
+
args << db_config.database
|
78
76
|
run_cmd("pg_dump", args, "dumping")
|
79
77
|
remove_sql_header_comments(filename)
|
80
78
|
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
@@ -82,31 +80,31 @@ module ActiveRecord
|
|
82
80
|
|
83
81
|
def structure_load(filename, extra_flags)
|
84
82
|
set_psql_env
|
85
|
-
args = ["
|
83
|
+
args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
|
86
84
|
args.concat(Array(extra_flags)) if extra_flags
|
87
|
-
args <<
|
85
|
+
args << db_config.database
|
88
86
|
run_cmd("psql", args, "loading")
|
89
87
|
end
|
90
88
|
|
91
89
|
private
|
92
|
-
attr_reader :
|
90
|
+
attr_reader :db_config, :configuration_hash
|
93
91
|
|
94
92
|
def encoding
|
95
|
-
|
93
|
+
configuration_hash[:encoding] || DEFAULT_ENCODING
|
96
94
|
end
|
97
95
|
|
98
96
|
def establish_master_connection
|
99
|
-
establish_connection
|
100
|
-
|
101
|
-
|
97
|
+
establish_connection configuration_hash.merge(
|
98
|
+
database: "postgres",
|
99
|
+
schema_search_path: "public"
|
102
100
|
)
|
103
101
|
end
|
104
102
|
|
105
103
|
def set_psql_env
|
106
|
-
ENV["PGHOST"] =
|
107
|
-
ENV["PGPORT"] =
|
108
|
-
ENV["PGPASSWORD"] =
|
109
|
-
ENV["PGUSER"] =
|
104
|
+
ENV["PGHOST"] = db_config.host if db_config.host
|
105
|
+
ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
|
106
|
+
ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
|
107
|
+
ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
|
110
108
|
end
|
111
109
|
|
112
110
|
def run_cmd(cmd, args, action)
|
@@ -5,20 +5,25 @@ module ActiveRecord
|
|
5
5
|
class SQLiteDatabaseTasks # :nodoc:
|
6
6
|
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def self.using_database_configurations?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(db_config, root = ActiveRecord::Tasks::DatabaseTasks.root)
|
13
|
+
@db_config = db_config
|
14
|
+
@root = root
|
10
15
|
end
|
11
16
|
|
12
17
|
def create
|
13
|
-
raise DatabaseAlreadyExists if File.exist?(
|
18
|
+
raise DatabaseAlreadyExists if File.exist?(db_config.database)
|
14
19
|
|
15
|
-
establish_connection
|
20
|
+
establish_connection(db_config)
|
16
21
|
connection
|
17
22
|
end
|
18
23
|
|
19
24
|
def drop
|
20
25
|
require "pathname"
|
21
|
-
path = Pathname.new
|
26
|
+
path = Pathname.new(db_config.database)
|
22
27
|
file = path.absolute? ? path.to_s : File.join(root, path)
|
23
28
|
|
24
29
|
FileUtils.rm(file)
|
@@ -40,7 +45,7 @@ module ActiveRecord
|
|
40
45
|
def structure_dump(filename, extra_flags)
|
41
46
|
args = []
|
42
47
|
args.concat(Array(extra_flags)) if extra_flags
|
43
|
-
args <<
|
48
|
+
args << db_config.database
|
44
49
|
|
45
50
|
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
46
51
|
if ignore_tables.any?
|
@@ -53,13 +58,12 @@ module ActiveRecord
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def structure_load(filename, extra_flags)
|
56
|
-
dbfile = configuration["database"]
|
57
61
|
flags = extra_flags.join(" ") if extra_flags
|
58
|
-
`sqlite3 #{flags} #{
|
62
|
+
`sqlite3 #{flags} #{db_config.database} < "#{filename}"`
|
59
63
|
end
|
60
64
|
|
61
65
|
private
|
62
|
-
attr_reader :
|
66
|
+
attr_reader :db_config, :root
|
63
67
|
|
64
68
|
def run_cmd(cmd, args, out)
|
65
69
|
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
@@ -5,18 +5,19 @@ require "active_support/testing/parallelization"
|
|
5
5
|
module ActiveRecord
|
6
6
|
module TestDatabases # :nodoc:
|
7
7
|
ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
|
8
|
-
create_and_load_schema(i, env_name:
|
8
|
+
create_and_load_schema(i, env_name: ActiveRecord::ConnectionHandling::DEFAULT_ENV.call)
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.create_and_load_schema(i, env_name:)
|
12
12
|
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
13
13
|
|
14
14
|
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
15
|
-
db_config.
|
16
|
-
|
15
|
+
db_config._database = "#{db_config.database}-#{i}"
|
16
|
+
|
17
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
|
17
18
|
end
|
18
19
|
ensure
|
19
|
-
ActiveRecord::Base.establish_connection
|
20
|
+
ActiveRecord::Base.establish_connection
|
20
21
|
ENV["VERBOSE"] = old
|
21
22
|
end
|
22
23
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module TestFixtures
|
5
7
|
extend ActiveSupport::Concern
|
@@ -21,7 +23,6 @@ module ActiveRecord
|
|
21
23
|
class_attribute :use_transactional_tests, default: true
|
22
24
|
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
23
25
|
class_attribute :pre_loaded_fixtures, default: false
|
24
|
-
class_attribute :config, default: ActiveRecord::Base
|
25
26
|
class_attribute :lock_threads, default: true
|
26
27
|
end
|
27
28
|
|
@@ -41,8 +42,9 @@ module ActiveRecord
|
|
41
42
|
def fixtures(*fixture_set_names)
|
42
43
|
if fixture_set_names.first == :all
|
43
44
|
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
44
|
-
fixture_set_names = Dir["
|
45
|
-
fixture_set_names.
|
45
|
+
fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq
|
46
|
+
fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
|
47
|
+
fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") }
|
46
48
|
else
|
47
49
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
48
50
|
end
|
@@ -97,7 +99,7 @@ module ActiveRecord
|
|
97
99
|
|
98
100
|
def run_in_transaction?
|
99
101
|
use_transactional_tests &&
|
100
|
-
!self.class.uses_transaction?(
|
102
|
+
!self.class.uses_transaction?(name)
|
101
103
|
end
|
102
104
|
|
103
105
|
def setup_fixtures(config = ActiveRecord::Base)
|
@@ -109,11 +111,11 @@ module ActiveRecord
|
|
109
111
|
@fixture_connections = []
|
110
112
|
@@already_loaded_fixtures ||= {}
|
111
113
|
@connection_subscriber = nil
|
114
|
+
@legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
115
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
112
116
|
|
113
117
|
# Load fixtures once and begin transaction.
|
114
118
|
if run_in_transaction?
|
115
|
-
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
116
|
-
|
117
119
|
if @@already_loaded_fixtures[self.class]
|
118
120
|
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
119
121
|
else
|
@@ -131,19 +133,24 @@ module ActiveRecord
|
|
131
133
|
# When connections are established in the future, begin a transaction too
|
132
134
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
133
135
|
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
134
|
-
|
136
|
+
shard = payload[:shard] if payload.key?(:shard)
|
137
|
+
setup_shared_connection_pool if ActiveRecord::Base.legacy_connection_handling
|
135
138
|
|
136
139
|
if spec_name
|
137
140
|
begin
|
138
|
-
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
141
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
|
139
142
|
rescue ConnectionNotEstablished
|
140
143
|
connection = nil
|
141
144
|
end
|
142
145
|
|
143
|
-
if connection
|
144
|
-
|
145
|
-
|
146
|
-
|
146
|
+
if connection
|
147
|
+
setup_shared_connection_pool unless ActiveRecord::Base.legacy_connection_handling
|
148
|
+
|
149
|
+
if !@fixture_connections.include?(connection)
|
150
|
+
connection.begin_transaction joinable: false, _lazy: false
|
151
|
+
connection.pool.lock_thread = true if lock_threads
|
152
|
+
@fixture_connections << connection
|
153
|
+
end
|
147
154
|
end
|
148
155
|
end
|
149
156
|
end
|
@@ -190,38 +197,79 @@ module ActiveRecord
|
|
190
197
|
# need to share a connection pool so that the reading connection
|
191
198
|
# can see data in the open transaction on the writing connection.
|
192
199
|
def setup_shared_connection_pool
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
handler
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
200
|
+
if ActiveRecord::Base.legacy_connection_handling
|
201
|
+
writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
|
202
|
+
|
203
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
204
|
+
if handler != writing_handler
|
205
|
+
handler.connection_pool_names.each do |name|
|
206
|
+
writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
|
207
|
+
return unless writing_pool_manager
|
208
|
+
|
209
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
210
|
+
@legacy_saved_pool_configs[handler][name] ||= {}
|
211
|
+
pool_manager.shard_names.each do |shard_name|
|
212
|
+
writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
|
213
|
+
pool_config = pool_manager.get_pool_config(nil, shard_name)
|
214
|
+
next if pool_config == writing_pool_config
|
215
|
+
|
216
|
+
@legacy_saved_pool_configs[handler][name][shard_name] = pool_config
|
217
|
+
pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
else
|
223
|
+
handler = ActiveRecord::Base.connection_handler
|
224
|
+
|
225
|
+
handler.connection_pool_names.each do |name|
|
226
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
227
|
+
pool_manager.shard_names.each do |shard_name|
|
228
|
+
writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
|
229
|
+
@saved_pool_configs[name][shard_name] ||= {}
|
230
|
+
pool_manager.role_names.each do |role|
|
231
|
+
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
|
232
|
+
next if pool_config == writing_pool_config
|
233
|
+
|
234
|
+
@saved_pool_configs[name][shard_name][role] = pool_config
|
235
|
+
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
236
|
+
end
|
207
237
|
end
|
208
238
|
end
|
209
239
|
end
|
210
240
|
end
|
211
241
|
|
212
242
|
def teardown_shared_connection_pool
|
213
|
-
|
214
|
-
|
215
|
-
|
243
|
+
if ActiveRecord::Base.legacy_connection_handling
|
244
|
+
@legacy_saved_pool_configs.each_pair do |handler, names|
|
245
|
+
names.each_pair do |name, shards|
|
246
|
+
shards.each_pair do |shard_name, pool_config|
|
247
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
248
|
+
pool_manager.set_pool_config(nil, shard_name, pool_config)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
else
|
253
|
+
handler = ActiveRecord::Base.connection_handler
|
254
|
+
|
255
|
+
@saved_pool_configs.each_pair do |name, shards|
|
256
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
257
|
+
shards.each_pair do |shard_name, roles|
|
258
|
+
roles.each_pair do |role, pool_config|
|
259
|
+
next unless pool_manager.get_pool_config(role, shard_name)
|
260
|
+
|
261
|
+
pool_manager.set_pool_config(role, shard_name, pool_config)
|
262
|
+
end
|
263
|
+
end
|
216
264
|
end
|
217
265
|
end
|
218
266
|
|
267
|
+
@legacy_saved_pool_configs.clear
|
219
268
|
@saved_pool_configs.clear
|
220
269
|
end
|
221
270
|
|
222
271
|
def load_fixtures(config)
|
223
|
-
|
224
|
-
Hash[fixtures.map { |f| [f.name, f] }]
|
272
|
+
ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
|
225
273
|
end
|
226
274
|
|
227
275
|
def instantiate_fixtures
|
@@ -80,11 +80,11 @@ module ActiveRecord
|
|
80
80
|
|
81
81
|
private
|
82
82
|
def timestamp_attributes_for_create
|
83
|
-
["created_at", "created_on"]
|
83
|
+
["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
|
84
84
|
end
|
85
85
|
|
86
86
|
def timestamp_attributes_for_update
|
87
|
-
["updated_at", "updated_on"]
|
87
|
+
["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
|
88
88
|
end
|
89
89
|
|
90
90
|
def reload_schema_from_cache
|
@@ -101,9 +101,7 @@ module ActiveRecord
|
|
101
101
|
current_time = current_time_from_proper_timezone
|
102
102
|
|
103
103
|
all_timestamp_attributes_in_model.each do |column|
|
104
|
-
|
105
|
-
_write_attribute(column, current_time)
|
106
|
-
end
|
104
|
+
_write_attribute(column, current_time) unless _read_attribute(column)
|
107
105
|
end
|
108
106
|
end
|
109
107
|
|
@@ -159,7 +157,7 @@ module ActiveRecord
|
|
159
157
|
def clear_timestamp_attributes
|
160
158
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
161
159
|
self[attribute_name] = nil
|
162
|
-
|
160
|
+
clear_attribute_change(attribute_name)
|
163
161
|
end
|
164
162
|
end
|
165
163
|
end
|
@@ -3,22 +3,20 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
# = Active Record Touch Later
|
5
5
|
module TouchLater # :nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
before_commit_without_transaction_enrollment :touch_deferred_attributes
|
6
|
+
def before_committed!
|
7
|
+
touch_deferred_attributes if has_defer_touch_attrs? && persisted?
|
8
|
+
super
|
10
9
|
end
|
11
10
|
|
12
|
-
def touch_later(*names
|
13
|
-
unless persisted?
|
14
|
-
raise ActiveRecordError, <<-MSG.squish
|
15
|
-
cannot touch on a new or destroyed record object. Consider using
|
16
|
-
persisted?, new_record?, or destroyed? before touching
|
17
|
-
MSG
|
18
|
-
end
|
11
|
+
def touch_later(*names) # :nodoc:
|
12
|
+
_raise_record_not_touched_error unless persisted?
|
19
13
|
|
20
14
|
@_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
|
21
|
-
@_defer_touch_attrs |= names
|
15
|
+
@_defer_touch_attrs |= names.map! do |name|
|
16
|
+
name = name.to_s
|
17
|
+
self.class.attribute_aliases[name] || name
|
18
|
+
end unless names.empty?
|
19
|
+
|
22
20
|
@_touch_time = current_time_from_proper_timezone
|
23
21
|
|
24
22
|
surreptitiously_touch @_defer_touch_attrs
|
@@ -36,22 +34,24 @@ module ActiveRecord
|
|
36
34
|
def touch(*names, time: nil) # :nodoc:
|
37
35
|
if has_defer_touch_attrs?
|
38
36
|
names |= @_defer_touch_attrs
|
37
|
+
super(*names, time: time)
|
38
|
+
@_defer_touch_attrs, @_touch_time = nil, nil
|
39
|
+
else
|
40
|
+
super
|
39
41
|
end
|
40
|
-
super(*names, time: time)
|
41
42
|
end
|
42
43
|
|
43
44
|
private
|
44
|
-
def surreptitiously_touch(
|
45
|
-
|
46
|
-
|
45
|
+
def surreptitiously_touch(attr_names)
|
46
|
+
attr_names.each do |attr_name|
|
47
|
+
_write_attribute(attr_name, @_touch_time)
|
48
|
+
clear_attribute_change(attr_name)
|
49
|
+
end
|
47
50
|
end
|
48
51
|
|
49
52
|
def touch_deferred_attributes
|
50
|
-
|
51
|
-
|
52
|
-
touch(*@_defer_touch_attrs, time: @_touch_time)
|
53
|
-
@_defer_touch_attrs, @_touch_time = nil, nil
|
54
|
-
end
|
53
|
+
@_skip_dirty_tracking = true
|
54
|
+
touch(time: @_touch_time)
|
55
55
|
end
|
56
56
|
|
57
57
|
def has_defer_touch_attrs?
|
@@ -10,9 +10,6 @@ module ActiveRecord
|
|
10
10
|
included do
|
11
11
|
define_callbacks :commit, :rollback,
|
12
12
|
:before_commit,
|
13
|
-
:before_commit_without_transaction_enrollment,
|
14
|
-
:commit_without_transaction_enrollment,
|
15
|
-
:rollback_without_transaction_enrollment,
|
16
13
|
scope: [:kind, :name]
|
17
14
|
end
|
18
15
|
|
@@ -164,13 +161,13 @@ module ActiveRecord
|
|
164
161
|
# end
|
165
162
|
# end
|
166
163
|
#
|
167
|
-
# only "Kotori" is created.
|
164
|
+
# only "Kotori" is created.
|
168
165
|
#
|
169
166
|
# Most databases don't support true nested transactions. At the time of
|
170
167
|
# writing, the only database that we're aware of that supports true nested
|
171
168
|
# transactions, is MS-SQL. Because of this, Active Record emulates nested
|
172
|
-
# transactions by using savepoints
|
173
|
-
# https://dev.mysql.com/doc/refman/
|
169
|
+
# transactions by using savepoints. See
|
170
|
+
# https://dev.mysql.com/doc/refman/en/savepoint.html
|
174
171
|
# for more information about savepoints.
|
175
172
|
#
|
176
173
|
# === \Callbacks
|
@@ -266,21 +263,6 @@ module ActiveRecord
|
|
266
263
|
set_callback(:rollback, :after, *args, &block)
|
267
264
|
end
|
268
265
|
|
269
|
-
def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
270
|
-
set_options_for_callbacks!(args)
|
271
|
-
set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
|
272
|
-
end
|
273
|
-
|
274
|
-
def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
275
|
-
set_options_for_callbacks!(args)
|
276
|
-
set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
|
277
|
-
end
|
278
|
-
|
279
|
-
def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
|
280
|
-
set_options_for_callbacks!(args)
|
281
|
-
set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
|
282
|
-
end
|
283
|
-
|
284
266
|
private
|
285
267
|
def set_options_for_callbacks!(args, enforced_options = {})
|
286
268
|
options = args.extract_options!.merge!(enforced_options)
|
@@ -289,8 +271,10 @@ module ActiveRecord
|
|
289
271
|
if options[:on]
|
290
272
|
fire_on = Array(options[:on])
|
291
273
|
assert_valid_transaction_action(fire_on)
|
292
|
-
options[:if] =
|
293
|
-
|
274
|
+
options[:if] = [
|
275
|
+
-> { transaction_include_any_action?(fire_on) },
|
276
|
+
*options[:if]
|
277
|
+
]
|
294
278
|
end
|
295
279
|
end
|
296
280
|
|
@@ -302,7 +286,7 @@ module ActiveRecord
|
|
302
286
|
end
|
303
287
|
|
304
288
|
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
|
305
|
-
def transaction(options
|
289
|
+
def transaction(**options, &block)
|
306
290
|
self.class.transaction(**options, &block)
|
307
291
|
end
|
308
292
|
|
@@ -310,11 +294,11 @@ module ActiveRecord
|
|
310
294
|
with_transaction_returning_status { super }
|
311
295
|
end
|
312
296
|
|
313
|
-
def save(
|
297
|
+
def save(**) #:nodoc:
|
314
298
|
with_transaction_returning_status { super }
|
315
299
|
end
|
316
300
|
|
317
|
-
def save!(
|
301
|
+
def save!(**) #:nodoc:
|
318
302
|
with_transaction_returning_status { super }
|
319
303
|
end
|
320
304
|
|
@@ -323,7 +307,6 @@ module ActiveRecord
|
|
323
307
|
end
|
324
308
|
|
325
309
|
def before_committed! # :nodoc:
|
326
|
-
_run_before_commit_without_transaction_enrollment_callbacks
|
327
310
|
_run_before_commit_callbacks
|
328
311
|
end
|
329
312
|
|
@@ -335,7 +318,6 @@ module ActiveRecord
|
|
335
318
|
force_clear_transaction_record_state
|
336
319
|
if should_run_callbacks
|
337
320
|
@_committed_already_called = true
|
338
|
-
_run_commit_without_transaction_enrollment_callbacks
|
339
321
|
_run_commit_callbacks
|
340
322
|
end
|
341
323
|
ensure
|
@@ -347,7 +329,6 @@ module ActiveRecord
|
|
347
329
|
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
|
348
330
|
if should_run_callbacks
|
349
331
|
_run_rollback_callbacks
|
350
|
-
_run_rollback_without_transaction_enrollment_callbacks
|
351
332
|
end
|
352
333
|
ensure
|
353
334
|
restore_transaction_record_state(force_restore_state)
|
@@ -363,13 +344,11 @@ module ActiveRecord
|
|
363
344
|
# instance.
|
364
345
|
def with_transaction_returning_status
|
365
346
|
status = nil
|
366
|
-
self.class.
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
@transaction_state = self.class.connection.transaction_state
|
372
|
-
end
|
347
|
+
connection = self.class.connection
|
348
|
+
ensure_finalize = !connection.transaction_open?
|
349
|
+
|
350
|
+
connection.transaction do
|
351
|
+
add_to_transaction(ensure_finalize || has_transactional_callbacks?)
|
373
352
|
remember_transaction_record_state
|
374
353
|
|
375
354
|
status = yield
|
@@ -391,6 +370,7 @@ module ActiveRecord
|
|
391
370
|
@_start_transaction_state ||= {
|
392
371
|
id: id,
|
393
372
|
new_record: @new_record,
|
373
|
+
previously_new_record: @previously_new_record,
|
394
374
|
destroyed: @destroyed,
|
395
375
|
attributes: @attributes,
|
396
376
|
frozen?: frozen?,
|
@@ -415,7 +395,6 @@ module ActiveRecord
|
|
415
395
|
# Force to clear the transaction record state.
|
416
396
|
def force_clear_transaction_record_state
|
417
397
|
@_start_transaction_state = nil
|
418
|
-
@transaction_state = nil
|
419
398
|
end
|
420
399
|
|
421
400
|
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
@@ -423,6 +402,7 @@ module ActiveRecord
|
|
423
402
|
if restore_state = @_start_transaction_state
|
424
403
|
if force_restore_state || restore_state[:level] <= 1
|
425
404
|
@new_record = restore_state[:new_record]
|
405
|
+
@previously_new_record = restore_state[:previously_new_record]
|
426
406
|
@destroyed = restore_state[:destroyed]
|
427
407
|
@attributes = restore_state[:attributes].map do |attr|
|
428
408
|
value = @attributes.fetch_value(attr.name)
|
@@ -455,39 +435,12 @@ module ActiveRecord
|
|
455
435
|
|
456
436
|
# Add the record to the current transaction so that the #after_rollback and #after_commit
|
457
437
|
# callbacks can be called.
|
458
|
-
def add_to_transaction
|
459
|
-
self.class.connection.add_transaction_record(self)
|
438
|
+
def add_to_transaction(ensure_finalize = true)
|
439
|
+
self.class.connection.add_transaction_record(self, ensure_finalize)
|
460
440
|
end
|
461
441
|
|
462
442
|
def has_transactional_callbacks?
|
463
443
|
!_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
|
464
444
|
end
|
465
|
-
|
466
|
-
# Updates the attributes on this particular Active Record object so that
|
467
|
-
# if it's associated with a transaction, then the state of the Active Record
|
468
|
-
# object will be updated to reflect the current state of the transaction.
|
469
|
-
#
|
470
|
-
# The <tt>@transaction_state</tt> variable stores the states of the associated
|
471
|
-
# transaction. This relies on the fact that a transaction can only be in
|
472
|
-
# one rollback or commit (otherwise a list of states would be required).
|
473
|
-
# Each Active Record object inside of a transaction carries that transaction's
|
474
|
-
# TransactionState.
|
475
|
-
#
|
476
|
-
# This method checks to see if the ActiveRecord object's state reflects
|
477
|
-
# the TransactionState, and rolls back or commits the Active Record object
|
478
|
-
# as appropriate.
|
479
|
-
def sync_with_transaction_state
|
480
|
-
if transaction_state = @transaction_state
|
481
|
-
if transaction_state.fully_committed?
|
482
|
-
force_clear_transaction_record_state
|
483
|
-
elsif transaction_state.committed?
|
484
|
-
clear_transaction_record_state
|
485
|
-
elsif transaction_state.rolledback?
|
486
|
-
force_restore_state = transaction_state.fully_rolledback?
|
487
|
-
restore_transaction_record_state(force_restore_state)
|
488
|
-
clear_transaction_record_state
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
445
|
end
|
493
446
|
end
|
@@ -61,9 +61,13 @@ module ActiveRecord
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def encoded(value)
|
64
|
-
|
65
|
-
|
64
|
+
return if default_value?(value)
|
65
|
+
payload = coder.dump(value)
|
66
|
+
if payload && binary? && payload.encoding != Encoding::BINARY
|
67
|
+
payload = payload.dup if payload.frozen?
|
68
|
+
payload.force_encoding(Encoding::BINARY)
|
66
69
|
end
|
70
|
+
payload
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|