activerecord 6.1.7 → 7.1.5
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 +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
# Returns the version of
|
4
|
+
# Returns the currently loaded version of Active Record as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
|
-
MAJOR =
|
10
|
+
MAJOR = 7
|
11
11
|
MINOR = 1
|
12
|
-
TINY =
|
12
|
+
TINY = 5
|
13
13
|
PRE = nil
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/inflector"
|
3
4
|
require "active_support/core_ext/hash/indifferent_access"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
|
-
#
|
7
|
+
# = Single table inheritance
|
7
8
|
#
|
8
9
|
# Active Record allows inheritance by storing the name of the class in a column that by
|
9
10
|
# default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
|
@@ -31,8 +32,9 @@ module ActiveRecord
|
|
31
32
|
# be triggered. In that case, it'll work just like normal subclasses with no special magic
|
32
33
|
# for differentiating between them or reloading the right type with find.
|
33
34
|
#
|
34
|
-
# Note, all the attributes for all the cases are kept in the same table.
|
35
|
-
#
|
35
|
+
# Note, all the attributes for all the cases are kept in the same table.
|
36
|
+
# Read more:
|
37
|
+
# * https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
|
36
38
|
#
|
37
39
|
module Inheritance
|
38
40
|
extend ActiveSupport::Concern
|
@@ -43,6 +45,8 @@ module ActiveRecord
|
|
43
45
|
# Determines whether to store the full constant name including namespace when using STI.
|
44
46
|
# This is true, by default.
|
45
47
|
class_attribute :store_full_sti_class, instance_writer: false, default: true
|
48
|
+
|
49
|
+
set_base_class
|
46
50
|
end
|
47
51
|
|
48
52
|
module ClassMethods
|
@@ -85,30 +89,30 @@ module ActiveRecord
|
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
88
|
-
def finder_needs_type_condition?
|
92
|
+
def finder_needs_type_condition? # :nodoc:
|
89
93
|
# This is like this because benchmarking justifies the strange :false stuff
|
90
94
|
:true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
|
91
95
|
end
|
92
96
|
|
93
|
-
# Returns the class
|
94
|
-
#
|
97
|
+
# Returns the first class in the inheritance hierarchy that descends from either an
|
98
|
+
# abstract class or from <tt>ActiveRecord::Base</tt>.
|
95
99
|
#
|
96
|
-
#
|
97
|
-
# through some arbitrarily deep hierarchy, B.base_class will return A.
|
100
|
+
# Consider the following behaviour:
|
98
101
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
102
|
+
# class ApplicationRecord < ActiveRecord::Base
|
103
|
+
# self.abstract_class = true
|
104
|
+
# end
|
105
|
+
# class Shape < ApplicationRecord
|
106
|
+
# self.abstract_class = true
|
107
|
+
# end
|
108
|
+
# Polygon = Class.new(Shape)
|
109
|
+
# Square = Class.new(Polygon)
|
110
|
+
#
|
111
|
+
# ApplicationRecord.base_class # => ApplicationRecord
|
112
|
+
# Shape.base_class # => Shape
|
113
|
+
# Polygon.base_class # => Polygon
|
114
|
+
# Square.base_class # => Polygon
|
115
|
+
attr_reader :base_class
|
112
116
|
|
113
117
|
# Returns whether the class is a base class.
|
114
118
|
# See #base_class for more information.
|
@@ -123,7 +127,7 @@ module ActiveRecord
|
|
123
127
|
# true.
|
124
128
|
# +ApplicationRecord+, for example, is generated as an abstract class.
|
125
129
|
#
|
126
|
-
# Consider the following default
|
130
|
+
# Consider the following default behavior:
|
127
131
|
#
|
128
132
|
# Shape = Class.new(ActiveRecord::Base)
|
129
133
|
# Polygon = Class.new(Shape)
|
@@ -164,6 +168,21 @@ module ActiveRecord
|
|
164
168
|
defined?(@abstract_class) && @abstract_class == true
|
165
169
|
end
|
166
170
|
|
171
|
+
# Sets the application record class for Active Record
|
172
|
+
#
|
173
|
+
# This is useful if your application uses a different class than
|
174
|
+
# ApplicationRecord for your primary abstract class. This class
|
175
|
+
# will share a database connection with Active Record. It is the class
|
176
|
+
# that connects to your primary database.
|
177
|
+
def primary_abstract_class
|
178
|
+
if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
|
179
|
+
raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
|
180
|
+
end
|
181
|
+
|
182
|
+
self.abstract_class = true
|
183
|
+
ActiveRecord.application_record_class = self
|
184
|
+
end
|
185
|
+
|
167
186
|
# Returns the value to be stored in the inheritance column for STI.
|
168
187
|
def sti_name
|
169
188
|
store_full_sti_class && store_full_class_name ? name : name.demodulize
|
@@ -174,7 +193,7 @@ module ActiveRecord
|
|
174
193
|
# It is used to find the class correspondent to the value stored in the inheritance column.
|
175
194
|
def sti_class_for(type_name)
|
176
195
|
if store_full_sti_class && store_full_class_name
|
177
|
-
|
196
|
+
type_name.constantize
|
178
197
|
else
|
179
198
|
compute_type(type_name)
|
180
199
|
end
|
@@ -196,15 +215,23 @@ module ActiveRecord
|
|
196
215
|
# It is used to find the class correspondent to the value stored in the polymorphic type column.
|
197
216
|
def polymorphic_class_for(name)
|
198
217
|
if store_full_class_name
|
199
|
-
|
218
|
+
name.constantize
|
200
219
|
else
|
201
220
|
compute_type(name)
|
202
221
|
end
|
203
222
|
end
|
204
223
|
|
205
|
-
def
|
206
|
-
|
224
|
+
def dup # :nodoc:
|
225
|
+
# `initialize_dup` / `initialize_copy` don't work when defined
|
226
|
+
# in the `singleton_class`.
|
227
|
+
other = super
|
228
|
+
other.set_base_class
|
229
|
+
other
|
230
|
+
end
|
231
|
+
|
232
|
+
def initialize_clone(other) # :nodoc:
|
207
233
|
super
|
234
|
+
set_base_class
|
208
235
|
end
|
209
236
|
|
210
237
|
protected
|
@@ -214,10 +241,10 @@ module ActiveRecord
|
|
214
241
|
if type_name.start_with?("::")
|
215
242
|
# If the type is prefixed with a scope operator then we assume that
|
216
243
|
# the type_name is an absolute reference.
|
217
|
-
|
244
|
+
type_name.constantize
|
218
245
|
else
|
219
246
|
type_candidate = @_type_candidates_cache[type_name]
|
220
|
-
if type_candidate && type_constant =
|
247
|
+
if type_candidate && type_constant = type_candidate.safe_constantize
|
221
248
|
return type_constant
|
222
249
|
end
|
223
250
|
|
@@ -227,7 +254,7 @@ module ActiveRecord
|
|
227
254
|
candidates << type_name
|
228
255
|
|
229
256
|
candidates.each do |candidate|
|
230
|
-
constant =
|
257
|
+
constant = candidate.safe_constantize
|
231
258
|
if candidate == constant.to_s
|
232
259
|
@_type_candidates_cache[type_name] = candidate
|
233
260
|
return constant
|
@@ -238,7 +265,32 @@ module ActiveRecord
|
|
238
265
|
end
|
239
266
|
end
|
240
267
|
|
268
|
+
def set_base_class # :nodoc:
|
269
|
+
@base_class = if self == Base
|
270
|
+
self
|
271
|
+
else
|
272
|
+
unless self < Base
|
273
|
+
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
|
274
|
+
end
|
275
|
+
|
276
|
+
if superclass == Base || superclass.abstract_class?
|
277
|
+
self
|
278
|
+
else
|
279
|
+
superclass.base_class
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
241
284
|
private
|
285
|
+
def inherited(subclass)
|
286
|
+
super
|
287
|
+
subclass.set_base_class
|
288
|
+
subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
|
289
|
+
subclass.class_eval do
|
290
|
+
@finder_needs_type_condition = nil
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
242
294
|
# Called by +instantiate+ to decide which class to use for a new
|
243
295
|
# record instance. For single-table inheritance, we check the record
|
244
296
|
# for a +type+ column and return the corresponding class.
|
@@ -5,13 +5,23 @@ require "active_support/core_ext/enumerable"
|
|
5
5
|
module ActiveRecord
|
6
6
|
class InsertAll # :nodoc:
|
7
7
|
attr_reader :model, :connection, :inserts, :keys
|
8
|
-
attr_reader :on_duplicate, :returning, :unique_by
|
9
|
-
|
10
|
-
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
|
11
|
-
|
12
|
-
|
13
|
-
@
|
14
|
-
|
8
|
+
attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
|
9
|
+
|
10
|
+
def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
|
11
|
+
@model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
|
12
|
+
@on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
|
13
|
+
@record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
|
14
|
+
|
15
|
+
disallow_raw_sql!(on_duplicate)
|
16
|
+
disallow_raw_sql!(returning)
|
17
|
+
|
18
|
+
if @inserts.empty?
|
19
|
+
@keys = []
|
20
|
+
else
|
21
|
+
resolve_sti
|
22
|
+
resolve_attribute_aliases
|
23
|
+
@keys = @inserts.first.keys
|
24
|
+
end
|
15
25
|
|
16
26
|
if model.scope_attributes?
|
17
27
|
@scope_attributes = model.scope_attributes
|
@@ -22,13 +32,15 @@ module ActiveRecord
|
|
22
32
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
23
33
|
@returning = false if @returning == []
|
24
34
|
|
25
|
-
@unique_by = find_unique_index_for(unique_by)
|
26
|
-
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
35
|
+
@unique_by = find_unique_index_for(@unique_by)
|
27
36
|
|
37
|
+
configure_on_duplicate_update_logic
|
28
38
|
ensure_valid_options_for_connection!
|
29
39
|
end
|
30
40
|
|
31
41
|
def execute
|
42
|
+
return ActiveRecord::Result.empty if inserts.empty?
|
43
|
+
|
32
44
|
message = +"#{model} "
|
33
45
|
message << "Bulk " if inserts.many?
|
34
46
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
@@ -36,7 +48,7 @@ module ActiveRecord
|
|
36
48
|
end
|
37
49
|
|
38
50
|
def updatable_columns
|
39
|
-
keys - readonly_columns - unique_by_columns
|
51
|
+
@updatable_columns ||= keys - readonly_columns - unique_by_columns
|
40
52
|
end
|
41
53
|
|
42
54
|
def primary_keys
|
@@ -56,18 +68,80 @@ module ActiveRecord
|
|
56
68
|
inserts.map do |attributes|
|
57
69
|
attributes = attributes.stringify_keys
|
58
70
|
attributes.merge!(scope_attributes) if scope_attributes
|
71
|
+
attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
|
59
72
|
|
60
73
|
verify_attributes(attributes)
|
61
74
|
|
62
|
-
|
75
|
+
keys_including_timestamps.map do |key|
|
63
76
|
yield key, attributes[key]
|
64
77
|
end
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
81
|
+
def record_timestamps?
|
82
|
+
@record_timestamps
|
83
|
+
end
|
84
|
+
|
85
|
+
# TODO: Consider renaming this method, as it only conditionally extends keys, not always
|
86
|
+
def keys_including_timestamps
|
87
|
+
@keys_including_timestamps ||= if record_timestamps?
|
88
|
+
keys + model.all_timestamp_attributes_in_model
|
89
|
+
else
|
90
|
+
keys
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
68
94
|
private
|
69
95
|
attr_reader :scope_attributes
|
70
96
|
|
97
|
+
def has_attribute_aliases?(attributes)
|
98
|
+
attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def resolve_sti
|
102
|
+
return if model.descends_from_active_record?
|
103
|
+
|
104
|
+
sti_type = model.sti_name
|
105
|
+
@inserts = @inserts.map do |insert|
|
106
|
+
insert.reverse_merge(model.inheritance_column.to_s => sti_type)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def resolve_attribute_aliases
|
111
|
+
return unless has_attribute_aliases?(@inserts.first)
|
112
|
+
|
113
|
+
@inserts = @inserts.map do |insert|
|
114
|
+
insert.transform_keys { |attribute| resolve_attribute_alias(attribute) }
|
115
|
+
end
|
116
|
+
|
117
|
+
@update_only = Array(@update_only).map { |attribute| resolve_attribute_alias(attribute) } if @update_only
|
118
|
+
@unique_by = Array(@unique_by).map { |attribute| resolve_attribute_alias(attribute) } if @unique_by
|
119
|
+
end
|
120
|
+
|
121
|
+
def resolve_attribute_alias(attribute)
|
122
|
+
model.attribute_alias(attribute) || attribute
|
123
|
+
end
|
124
|
+
|
125
|
+
def configure_on_duplicate_update_logic
|
126
|
+
if custom_update_sql_provided? && update_only.present?
|
127
|
+
raise ArgumentError, "You can't set :update_only and provide custom update SQL via :on_duplicate at the same time"
|
128
|
+
end
|
129
|
+
|
130
|
+
if update_only.present?
|
131
|
+
@updatable_columns = Array(update_only)
|
132
|
+
@on_duplicate = :update
|
133
|
+
elsif custom_update_sql_provided?
|
134
|
+
@update_sql = on_duplicate
|
135
|
+
@on_duplicate = :update
|
136
|
+
elsif @on_duplicate == :update && updatable_columns.empty?
|
137
|
+
@on_duplicate = :skip
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def custom_update_sql_provided?
|
142
|
+
@custom_update_sql_provided ||= Arel.arel_node?(on_duplicate)
|
143
|
+
end
|
144
|
+
|
71
145
|
def find_unique_index_for(unique_by)
|
72
146
|
if !connection.supports_insert_conflict_target?
|
73
147
|
return if unique_by.nil?
|
@@ -77,8 +151,9 @@ module ActiveRecord
|
|
77
151
|
|
78
152
|
name_or_columns = unique_by || model.primary_key
|
79
153
|
match = Array(name_or_columns).map(&:to_s)
|
154
|
+
sorted_match = match.sort
|
80
155
|
|
81
|
-
if index = unique_indexes.find { |i| match.include?(i.name) || i.columns ==
|
156
|
+
if index = unique_indexes.find { |i| match.include?(i.name) || Array(i.columns).sort == sorted_match }
|
82
157
|
index
|
83
158
|
elsif match == primary_keys
|
84
159
|
unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
|
@@ -126,15 +201,28 @@ module ActiveRecord
|
|
126
201
|
|
127
202
|
|
128
203
|
def verify_attributes(attributes)
|
129
|
-
if
|
204
|
+
if keys_including_timestamps != attributes.keys.to_set
|
130
205
|
raise ArgumentError, "All objects being inserted must have the same keys"
|
131
206
|
end
|
132
207
|
end
|
133
208
|
|
209
|
+
def disallow_raw_sql!(value)
|
210
|
+
return if !value.is_a?(String) || Arel.arel_node?(value)
|
211
|
+
|
212
|
+
raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
|
213
|
+
"SQL) called: #{value}. " \
|
214
|
+
"Known-safe values can be passed " \
|
215
|
+
"by wrapping them in Arel.sql()."
|
216
|
+
end
|
217
|
+
|
218
|
+
def timestamps_for_create
|
219
|
+
model.all_timestamp_attributes_in_model.index_with(connection.high_precision_current_timestamp)
|
220
|
+
end
|
221
|
+
|
134
222
|
class Builder # :nodoc:
|
135
223
|
attr_reader :model
|
136
224
|
|
137
|
-
delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
|
225
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
|
138
226
|
|
139
227
|
def initialize(insert_all)
|
140
228
|
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
@@ -145,9 +233,10 @@ module ActiveRecord
|
|
145
233
|
end
|
146
234
|
|
147
235
|
def values_list
|
148
|
-
types = extract_types_from_columns_on(model.table_name, keys:
|
236
|
+
types = extract_types_from_columns_on(model.table_name, keys: keys_including_timestamps)
|
149
237
|
|
150
238
|
values_list = insert_all.map_key_with_value do |key, value|
|
239
|
+
next value if Arel::Nodes::SqlLiteral === value
|
151
240
|
connection.with_yaml_fallback(types[key].serialize(value))
|
152
241
|
end
|
153
242
|
|
@@ -155,7 +244,19 @@ module ActiveRecord
|
|
155
244
|
end
|
156
245
|
|
157
246
|
def returning
|
158
|
-
|
247
|
+
return unless insert_all.returning
|
248
|
+
|
249
|
+
if insert_all.returning.is_a?(String)
|
250
|
+
insert_all.returning
|
251
|
+
else
|
252
|
+
Array(insert_all.returning).map do |attribute|
|
253
|
+
if model.attribute_alias?(attribute)
|
254
|
+
"#{quote_column(model.attribute_alias(attribute))} AS #{quote_column(attribute)}"
|
255
|
+
else
|
256
|
+
quote_column(attribute)
|
257
|
+
end
|
258
|
+
end.join(",")
|
259
|
+
end
|
159
260
|
end
|
160
261
|
|
161
262
|
def conflict_target
|
@@ -173,22 +274,30 @@ module ActiveRecord
|
|
173
274
|
end
|
174
275
|
|
175
276
|
def touch_model_timestamps_unless(&block)
|
176
|
-
|
277
|
+
return "" unless update_duplicates? && record_timestamps?
|
278
|
+
|
279
|
+
model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
|
177
280
|
if touch_timestamp_attribute?(column_name)
|
178
|
-
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE
|
281
|
+
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
|
179
282
|
end
|
180
|
-
end.
|
283
|
+
end.join
|
181
284
|
end
|
182
285
|
|
286
|
+
def raw_update_sql
|
287
|
+
insert_all.update_sql
|
288
|
+
end
|
289
|
+
|
290
|
+
alias raw_update_sql? raw_update_sql
|
291
|
+
|
183
292
|
private
|
184
293
|
attr_reader :connection, :insert_all
|
185
294
|
|
186
295
|
def touch_timestamp_attribute?(column_name)
|
187
|
-
|
296
|
+
insert_all.updatable_columns.exclude?(column_name)
|
188
297
|
end
|
189
298
|
|
190
299
|
def columns_list
|
191
|
-
format_columns(insert_all.
|
300
|
+
format_columns(insert_all.keys_including_timestamps)
|
192
301
|
end
|
193
302
|
|
194
303
|
def extract_types_from_columns_on(table_name, keys:)
|
@@ -205,7 +314,11 @@ module ActiveRecord
|
|
205
314
|
end
|
206
315
|
|
207
316
|
def quote_columns(columns)
|
208
|
-
columns.map(
|
317
|
+
columns.map { |column| quote_column(column) }
|
318
|
+
end
|
319
|
+
|
320
|
+
def quote_column(column)
|
321
|
+
connection.quote_column_name(column)
|
209
322
|
end
|
210
323
|
end
|
211
324
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
##
|
11
11
|
# :singleton-method:
|
12
12
|
# Indicates the format used to generate the timestamp in the cache key, if
|
13
|
-
# versioning is off. Accepts any of the symbols in
|
13
|
+
# versioning is off. Accepts any of the symbols in +Time::DATE_FORMATS+.
|
14
14
|
#
|
15
15
|
# This is +:usec+, by default.
|
16
16
|
class_attribute :cache_timestamp_format, instance_writer: false, default: :usec
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
21
21
|
# by a changing version in the #cache_version method.
|
22
22
|
#
|
23
|
-
# This is +true+, by default on Rails 5.2 and above.
|
23
|
+
# This is +true+, by default on \Rails 5.2 and above.
|
24
24
|
class_attribute :cache_versioning, instance_writer: false, default: false
|
25
25
|
|
26
26
|
##
|
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
28
28
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
29
29
|
# by a changing version in the #cache_version method on collections.
|
30
30
|
#
|
31
|
-
# This is +false+, by default until Rails 6.1.
|
31
|
+
# This is +false+, by default until \Rails 6.1.
|
32
32
|
class_attribute :collection_cache_versioning, instance_writer: false, default: false
|
33
33
|
end
|
34
34
|
|
@@ -55,8 +55,8 @@ module ActiveRecord
|
|
55
55
|
# user = User.find_by(name: 'Phusion')
|
56
56
|
# user_path(user) # => "/users/Phusion"
|
57
57
|
def to_param
|
58
|
-
|
59
|
-
id
|
58
|
+
return unless id
|
59
|
+
Array(id).join(self.class.param_delimiter)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Returns a stable cache key that can be used to identify this record.
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
# Product.new.cache_key # => "products/new"
|
65
65
|
# Product.find(5).cache_key # => "products/5"
|
66
66
|
#
|
67
|
-
# If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
|
67
|
+
# If ActiveRecord::Base.cache_versioning is turned off, as it was in \Rails 5.1 and earlier,
|
68
68
|
# the cache key will also include a version.
|
69
69
|
#
|
70
70
|
# Product.cache_versioning = false
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
79
79
|
timestamp = max_updated_column_timestamp
|
80
80
|
|
81
81
|
if timestamp
|
82
|
-
timestamp = timestamp.utc.
|
82
|
+
timestamp = timestamp.utc.to_fs(cache_timestamp_format)
|
83
83
|
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
84
84
|
else
|
85
85
|
"#{model_name.cache_key}/#{id}"
|
@@ -101,11 +101,12 @@ module ActiveRecord
|
|
101
101
|
timestamp = updated_at_before_type_cast
|
102
102
|
if can_use_fast_cache_version?(timestamp)
|
103
103
|
raw_timestamp_to_cache_version(timestamp)
|
104
|
+
|
104
105
|
elsif timestamp = updated_at
|
105
|
-
timestamp.utc.
|
106
|
+
timestamp.utc.to_fs(cache_timestamp_format)
|
106
107
|
end
|
107
108
|
elsif self.class.has_attribute?("updated_at")
|
108
|
-
raise ActiveModel::MissingAttributeError, "missing attribute
|
109
|
+
raise ActiveModel::MissingAttributeError, "missing attribute 'updated_at' for #{self.class}"
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
@@ -177,7 +178,7 @@ module ActiveRecord
|
|
177
178
|
def can_use_fast_cache_version?(timestamp)
|
178
179
|
timestamp.is_a?(String) &&
|
179
180
|
cache_timestamp_format == :usec &&
|
180
|
-
default_timezone == :utc &&
|
181
|
+
self.class.connection.default_timezone == :utc &&
|
181
182
|
!updated_at_came_from_user?
|
182
183
|
end
|
183
184
|
|