activerecord 6.0.6.1 → 6.1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1146 -788
- 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 +24 -25
- 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
|