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
@@ -5,13 +5,14 @@ module ActiveRecord
|
|
5
5
|
class Relation
|
6
6
|
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
|
-
:extending, :unscope, :optimizer_hints, :annotate
|
8
|
+
:extending, :unscope, :optimizer_hints, :annotate,
|
9
|
+
:with]
|
9
10
|
|
10
11
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
12
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
13
|
|
13
14
|
CLAUSE_METHODS = [:where, :having, :from]
|
14
|
-
INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :
|
15
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with]
|
15
16
|
|
16
17
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
17
18
|
|
@@ -31,6 +32,10 @@ module ActiveRecord
|
|
31
32
|
@loaded = false
|
32
33
|
@predicate_builder = predicate_builder
|
33
34
|
@delegate_to_klass = false
|
35
|
+
@future_result = nil
|
36
|
+
@records = nil
|
37
|
+
@async = false
|
38
|
+
@none = false
|
34
39
|
end
|
35
40
|
|
36
41
|
def initialize_copy(other)
|
@@ -38,15 +43,10 @@ module ActiveRecord
|
|
38
43
|
reset
|
39
44
|
end
|
40
45
|
|
41
|
-
def arel_attribute(name) # :nodoc:
|
42
|
-
table[name]
|
43
|
-
end
|
44
|
-
deprecate :arel_attribute
|
45
|
-
|
46
46
|
def bind_attribute(name, value) # :nodoc:
|
47
47
|
if reflection = klass._reflect_on_association(name)
|
48
48
|
name = reflection.foreign_key
|
49
|
-
value = value.read_attribute(reflection.
|
49
|
+
value = value.read_attribute(reflection.association_primary_key) unless value.nil?
|
50
50
|
end
|
51
51
|
|
52
52
|
attr = table[name]
|
@@ -67,8 +67,12 @@ module ActiveRecord
|
|
67
67
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
68
|
# user.name # => Oscar
|
69
69
|
def new(attributes = nil, &block)
|
70
|
-
|
71
|
-
|
70
|
+
if attributes.is_a?(Array)
|
71
|
+
attributes.collect { |attr| new(attr, &block) }
|
72
|
+
else
|
73
|
+
block = current_scope_restoring_block(&block)
|
74
|
+
scoping { _new(attributes, &block) }
|
75
|
+
end
|
72
76
|
end
|
73
77
|
alias build new
|
74
78
|
|
@@ -148,7 +152,7 @@ module ActiveRecord
|
|
148
152
|
# above can be alternatively written this way:
|
149
153
|
#
|
150
154
|
# # Find the first user named "Scarlett" or create a new one with a
|
151
|
-
# #
|
155
|
+
# # particular last name.
|
152
156
|
# User.find_or_create_by(first_name: 'Scarlett') do |user|
|
153
157
|
# user.last_name = 'Johansson'
|
154
158
|
# end
|
@@ -158,38 +162,41 @@ module ActiveRecord
|
|
158
162
|
# failed due to validation errors it won't be persisted, you get what
|
159
163
|
# #create returns in such situation.
|
160
164
|
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
+
# If creation failed because of a unique constraint, this method will
|
166
|
+
# assume it encountered a race condition and will try finding the record
|
167
|
+
# once more. If somehow the second find still does not find a record
|
168
|
+
# because a concurrent DELETE happened, it will then raise an
|
169
|
+
# ActiveRecord::RecordNotFound exception.
|
165
170
|
#
|
166
|
-
#
|
171
|
+
# Please note <b>this method is not atomic</b>, it runs first a SELECT,
|
172
|
+
# and if there are no results an INSERT is attempted. So if the table
|
173
|
+
# doesn't have a relevant unique constraint it could be the case that
|
174
|
+
# you end up with two or more similar records.
|
167
175
|
def find_or_create_by(attributes, &block)
|
168
|
-
find_by(attributes) ||
|
176
|
+
find_by(attributes) || create_or_find_by(attributes, &block)
|
169
177
|
end
|
170
178
|
|
171
179
|
# Like #find_or_create_by, but calls
|
172
180
|
# {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
|
173
181
|
# is raised if the created record is invalid.
|
174
182
|
def find_or_create_by!(attributes, &block)
|
175
|
-
find_by(attributes) ||
|
183
|
+
find_by(attributes) || create_or_find_by!(attributes, &block)
|
176
184
|
end
|
177
185
|
|
178
|
-
# Attempts to create a record with the given attributes in a table that has a unique constraint
|
186
|
+
# Attempts to create a record with the given attributes in a table that has a unique database constraint
|
179
187
|
# on one or several of its columns. If a row already exists with one or several of these
|
180
188
|
# unique constraints, the exception such an insertion would normally raise is caught,
|
181
189
|
# and the existing record with those attributes is found using #find_by!.
|
182
190
|
#
|
183
|
-
# This is similar to #find_or_create_by, but
|
184
|
-
#
|
185
|
-
# if none is found.
|
191
|
+
# This is similar to #find_or_create_by, but tries to create the record first. As such it is
|
192
|
+
# better suited for cases where the record is most likely not to exist yet.
|
186
193
|
#
|
187
194
|
# There are several drawbacks to #create_or_find_by, though:
|
188
195
|
#
|
189
|
-
# * The underlying table must have the relevant columns defined with unique constraints.
|
196
|
+
# * The underlying table must have the relevant columns defined with unique database constraints.
|
190
197
|
# * A unique constraint violation may be triggered by only one, or at least less than all,
|
191
198
|
# of the given attributes. This means that the subsequent #find_by! may fail to find a
|
192
|
-
# matching record, which will then raise an
|
199
|
+
# matching record, which will then raise an ActiveRecord::RecordNotFound exception,
|
193
200
|
# rather than a record with the given attributes.
|
194
201
|
# * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
|
195
202
|
# we actually have another race condition between INSERT -> SELECT, which can be triggered
|
@@ -198,7 +205,7 @@ module ActiveRecord
|
|
198
205
|
# * It relies on exception handling to handle control flow, which may be marginally slower.
|
199
206
|
# * The primary key may auto-increment on each create, even if it fails. This can accelerate
|
200
207
|
# the problem of running out of integers, if the underlying table is still stuck on a primary
|
201
|
-
# key of type int (note: All Rails apps since 5.1+ have defaulted to bigint, which is not liable
|
208
|
+
# key of type int (note: All \Rails apps since 5.1+ have defaulted to bigint, which is not liable
|
202
209
|
# to this problem).
|
203
210
|
#
|
204
211
|
# This method will return a record if all given attributes are covered by unique constraints
|
@@ -208,7 +215,11 @@ module ActiveRecord
|
|
208
215
|
def create_or_find_by(attributes, &block)
|
209
216
|
transaction(requires_new: true) { create(attributes, &block) }
|
210
217
|
rescue ActiveRecord::RecordNotUnique
|
211
|
-
|
218
|
+
if connection.transaction_open?
|
219
|
+
where(attributes).lock.find_by!(attributes)
|
220
|
+
else
|
221
|
+
find_by!(attributes)
|
222
|
+
end
|
212
223
|
end
|
213
224
|
|
214
225
|
# Like #create_or_find_by, but calls
|
@@ -217,7 +228,11 @@ module ActiveRecord
|
|
217
228
|
def create_or_find_by!(attributes, &block)
|
218
229
|
transaction(requires_new: true) { create!(attributes, &block) }
|
219
230
|
rescue ActiveRecord::RecordNotUnique
|
220
|
-
|
231
|
+
if connection.transaction_open?
|
232
|
+
where(attributes).lock.find_by!(attributes)
|
233
|
+
else
|
234
|
+
find_by!(attributes)
|
235
|
+
end
|
221
236
|
end
|
222
237
|
|
223
238
|
# Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
|
@@ -235,8 +250,8 @@ module ActiveRecord
|
|
235
250
|
#
|
236
251
|
# Please see further details in the
|
237
252
|
# {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
|
238
|
-
def explain
|
239
|
-
exec_explain(collecting_queries_for_explain { exec_queries })
|
253
|
+
def explain(*options)
|
254
|
+
exec_explain(collecting_queries_for_explain { exec_queries }, options)
|
240
255
|
end
|
241
256
|
|
242
257
|
# Converts relation objects to Array.
|
@@ -257,37 +272,71 @@ module ActiveRecord
|
|
257
272
|
|
258
273
|
# Returns size of the records.
|
259
274
|
def size
|
260
|
-
loaded?
|
275
|
+
if loaded?
|
276
|
+
records.length
|
277
|
+
else
|
278
|
+
count(:all)
|
279
|
+
end
|
261
280
|
end
|
262
281
|
|
263
282
|
# Returns true if there are no records.
|
264
283
|
def empty?
|
265
|
-
return
|
266
|
-
|
284
|
+
return true if @none
|
285
|
+
|
286
|
+
if loaded?
|
287
|
+
records.empty?
|
288
|
+
else
|
289
|
+
!exists?
|
290
|
+
end
|
267
291
|
end
|
268
292
|
|
269
293
|
# Returns true if there are no records.
|
270
|
-
|
271
|
-
|
294
|
+
#
|
295
|
+
# When a pattern argument is given, this method checks whether elements in
|
296
|
+
# the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
|
297
|
+
#
|
298
|
+
# posts.none?(Comment) # => true or false
|
299
|
+
def none?(*args)
|
300
|
+
return true if @none
|
301
|
+
|
302
|
+
return super if args.present? || block_given?
|
272
303
|
empty?
|
273
304
|
end
|
274
305
|
|
275
306
|
# Returns true if there are any records.
|
276
|
-
|
277
|
-
|
307
|
+
#
|
308
|
+
# When a pattern argument is given, this method checks whether elements in
|
309
|
+
# the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
|
310
|
+
#
|
311
|
+
# posts.any?(Post) # => true or false
|
312
|
+
def any?(*args)
|
313
|
+
return false if @none
|
314
|
+
|
315
|
+
return super if args.present? || block_given?
|
278
316
|
!empty?
|
279
317
|
end
|
280
318
|
|
281
319
|
# Returns true if there is exactly one record.
|
282
|
-
|
283
|
-
|
284
|
-
|
320
|
+
#
|
321
|
+
# When a pattern argument is given, this method checks whether elements in
|
322
|
+
# the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
|
323
|
+
#
|
324
|
+
# posts.one?(Post) # => true or false
|
325
|
+
def one?(*args)
|
326
|
+
return false if @none
|
327
|
+
|
328
|
+
return super if args.present? || block_given?
|
329
|
+
return records.one? if loaded?
|
330
|
+
limited_count == 1
|
285
331
|
end
|
286
332
|
|
287
333
|
# Returns true if there is more than one record.
|
288
334
|
def many?
|
335
|
+
return false if @none
|
336
|
+
|
289
337
|
return super if block_given?
|
290
|
-
|
338
|
+
return records.many? if loaded?
|
339
|
+
limited_count > 1
|
291
340
|
end
|
292
341
|
|
293
342
|
# Returns a stable cache key that can be used to identify this query.
|
@@ -297,7 +346,7 @@ module ActiveRecord
|
|
297
346
|
# # => "products/query-1850ab3d302391b85b8693e941286659"
|
298
347
|
#
|
299
348
|
# If ActiveRecord::Base.collection_cache_versioning is turned off, as it was
|
300
|
-
# in Rails 6.0 and earlier, the cache key will also include a version.
|
349
|
+
# in \Rails 6.0 and earlier, the cache key will also include a version.
|
301
350
|
#
|
302
351
|
# ActiveRecord::Base.collection_cache_versioning = false
|
303
352
|
# Product.where("name like ?", "%Cosmic Encounter%").cache_key
|
@@ -344,7 +393,7 @@ module ActiveRecord
|
|
344
393
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
394
|
timestamp_column = timestamp_column.to_s
|
346
395
|
|
347
|
-
if loaded?
|
396
|
+
if loaded?
|
348
397
|
size = records.size
|
349
398
|
if size > 0
|
350
399
|
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
@@ -357,6 +406,7 @@ module ActiveRecord
|
|
357
406
|
|
358
407
|
if collection.has_limit_or_offset?
|
359
408
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
409
|
+
query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
|
360
410
|
subquery_alias = "subquery_for_cache_key"
|
361
411
|
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
362
412
|
arel = query.build_subquery(subquery_alias, select_values % subquery_column)
|
@@ -377,7 +427,7 @@ module ActiveRecord
|
|
377
427
|
end
|
378
428
|
|
379
429
|
if timestamp
|
380
|
-
"#{size}-#{timestamp.utc.
|
430
|
+
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
381
431
|
else
|
382
432
|
"#{size}"
|
383
433
|
end
|
@@ -398,17 +448,30 @@ module ActiveRecord
|
|
398
448
|
# Comment.where(post_id: 1).scoping do
|
399
449
|
# Comment.first
|
400
450
|
# end
|
401
|
-
# #
|
451
|
+
# # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
452
|
+
#
|
453
|
+
# If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
|
454
|
+
# for the relation including +update+ and +delete+ on instances.
|
455
|
+
# Once +all_queries+ is set to true it cannot be set to false in a
|
456
|
+
# nested block.
|
402
457
|
#
|
403
458
|
# Please check unscoped if you want to remove all previous scopes (including
|
404
459
|
# the default_scope) during the execution of a block.
|
405
|
-
def scoping
|
406
|
-
|
460
|
+
def scoping(all_queries: nil, &block)
|
461
|
+
registry = klass.scope_registry
|
462
|
+
if global_scope?(registry) && all_queries == false
|
463
|
+
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
464
|
+
elsif already_in_scope?(registry)
|
465
|
+
yield
|
466
|
+
else
|
467
|
+
_scoping(self, registry, all_queries, &block)
|
468
|
+
end
|
407
469
|
end
|
408
470
|
|
409
|
-
def _exec_scope(
|
471
|
+
def _exec_scope(...) # :nodoc:
|
410
472
|
@delegate_to_klass = true
|
411
|
-
|
473
|
+
registry = klass.scope_registry
|
474
|
+
_scoping(nil, registry) { instance_exec(...) || self }
|
412
475
|
ensure
|
413
476
|
@delegate_to_klass = false
|
414
477
|
end
|
@@ -422,7 +485,8 @@ module ActiveRecord
|
|
422
485
|
#
|
423
486
|
# ==== Parameters
|
424
487
|
#
|
425
|
-
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
|
488
|
+
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement. Any strings provided will
|
489
|
+
# be type cast, unless you use +Arel.sql+. (Don't pass user-provided values to +Arel.sql+.)
|
426
490
|
#
|
427
491
|
# ==== Examples
|
428
492
|
#
|
@@ -437,19 +501,13 @@ module ActiveRecord
|
|
437
501
|
#
|
438
502
|
# # Update all invoices and set the number column to its id value.
|
439
503
|
# Invoice.update_all('number = id')
|
504
|
+
#
|
505
|
+
# # Update all books with 'Rails' in their title
|
506
|
+
# Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
|
440
507
|
def update_all(updates)
|
441
508
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
442
509
|
|
443
|
-
|
444
|
-
arel.source.left = table
|
445
|
-
|
446
|
-
stmt = Arel::UpdateManager.new
|
447
|
-
stmt.table(arel.source)
|
448
|
-
stmt.key = table[primary_key]
|
449
|
-
stmt.take(arel.limit)
|
450
|
-
stmt.offset(arel.offset)
|
451
|
-
stmt.order(*arel.orders)
|
452
|
-
stmt.wheres = arel.constraints
|
510
|
+
return 0 if @none
|
453
511
|
|
454
512
|
if updates.is_a?(Hash)
|
455
513
|
if klass.locking_enabled? &&
|
@@ -458,11 +516,22 @@ module ActiveRecord
|
|
458
516
|
attr = table[klass.locking_column]
|
459
517
|
updates[attr.name] = _increment_attribute(attr)
|
460
518
|
end
|
461
|
-
|
519
|
+
values = _substitute_values(updates)
|
462
520
|
else
|
463
|
-
|
521
|
+
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
464
522
|
end
|
465
523
|
|
524
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
525
|
+
arel.source.left = table
|
526
|
+
|
527
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
528
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
529
|
+
key = if klass.composite_primary_key?
|
530
|
+
primary_key.map { |pk| table[pk] }
|
531
|
+
else
|
532
|
+
table[primary_key]
|
533
|
+
end
|
534
|
+
stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
|
466
535
|
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
467
536
|
end
|
468
537
|
|
@@ -474,6 +543,14 @@ module ActiveRecord
|
|
474
543
|
end
|
475
544
|
end
|
476
545
|
|
546
|
+
def update!(id = :all, attributes) # :nodoc:
|
547
|
+
if id == :all
|
548
|
+
each { |record| record.update!(attributes) }
|
549
|
+
else
|
550
|
+
klass.update!(id, attributes)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
477
554
|
# Updates the counters of the records in the current relation.
|
478
555
|
#
|
479
556
|
# ==== Parameters
|
@@ -572,6 +649,8 @@ module ActiveRecord
|
|
572
649
|
# Post.distinct.delete_all
|
573
650
|
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
|
574
651
|
def delete_all
|
652
|
+
return 0 if @none
|
653
|
+
|
575
654
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
|
576
655
|
value = @values[method]
|
577
656
|
method == :distinct ? value : value&.any?
|
@@ -583,15 +662,16 @@ module ActiveRecord
|
|
583
662
|
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
584
663
|
arel.source.left = table
|
585
664
|
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
665
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
666
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
667
|
+
key = if klass.composite_primary_key?
|
668
|
+
primary_key.map { |pk| table[pk] }
|
669
|
+
else
|
670
|
+
table[primary_key]
|
671
|
+
end
|
672
|
+
stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
|
593
673
|
|
594
|
-
klass.connection.delete(stmt, "#{klass}
|
674
|
+
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
|
595
675
|
end
|
596
676
|
|
597
677
|
# Finds and destroys all records matching the specified conditions.
|
@@ -620,6 +700,47 @@ module ActiveRecord
|
|
620
700
|
where(*args).delete_all
|
621
701
|
end
|
622
702
|
|
703
|
+
# Schedule the query to be performed from a background thread pool.
|
704
|
+
#
|
705
|
+
# Post.where(published: true).load_async # => #<ActiveRecord::Relation>
|
706
|
+
#
|
707
|
+
# When the +Relation+ is iterated, if the background query wasn't executed yet,
|
708
|
+
# it will be performed by the foreground thread.
|
709
|
+
#
|
710
|
+
# Note that {config.active_record.async_query_executor}[https://guides.rubyonrails.org/configuring.html#config-active-record-async-query-executor] must be configured
|
711
|
+
# for queries to actually be executed concurrently. Otherwise it defaults to
|
712
|
+
# executing them in the foreground.
|
713
|
+
#
|
714
|
+
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
715
|
+
# fixtures are enabled.
|
716
|
+
#
|
717
|
+
# If the query was actually executed in the background, the Active Record logs will show
|
718
|
+
# it by prefixing the log line with <tt>ASYNC</tt>:
|
719
|
+
#
|
720
|
+
# ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
|
721
|
+
def load_async
|
722
|
+
return load if !connection.async_enabled?
|
723
|
+
|
724
|
+
unless loaded?
|
725
|
+
result = exec_main_query(async: connection.current_transaction.closed?)
|
726
|
+
|
727
|
+
if result.is_a?(Array)
|
728
|
+
@records = result
|
729
|
+
else
|
730
|
+
@future_result = result
|
731
|
+
end
|
732
|
+
@loaded = true
|
733
|
+
end
|
734
|
+
|
735
|
+
self
|
736
|
+
end
|
737
|
+
|
738
|
+
# Returns <tt>true</tt> if the relation was scheduled on the background
|
739
|
+
# thread pool.
|
740
|
+
def scheduled?
|
741
|
+
!!@future_result
|
742
|
+
end
|
743
|
+
|
623
744
|
# Causes the records to be loaded from the database if they have not
|
624
745
|
# been loaded already. You can use this if for some reason you need
|
625
746
|
# to explicitly load some records before actually using them. The
|
@@ -627,7 +748,7 @@ module ActiveRecord
|
|
627
748
|
#
|
628
749
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
629
750
|
def load(&block)
|
630
|
-
|
751
|
+
if !loaded? || scheduled?
|
631
752
|
@records = exec_queries(&block)
|
632
753
|
@loaded = true
|
633
754
|
end
|
@@ -642,29 +763,30 @@ module ActiveRecord
|
|
642
763
|
end
|
643
764
|
|
644
765
|
def reset
|
766
|
+
@future_result&.cancel
|
767
|
+
@future_result = nil
|
645
768
|
@delegate_to_klass = false
|
646
769
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
647
770
|
@offsets = @take = nil
|
648
771
|
@cache_keys = nil
|
649
|
-
@
|
772
|
+
@cache_versions = nil
|
773
|
+
@records = nil
|
650
774
|
self
|
651
775
|
end
|
652
776
|
|
653
777
|
# Returns sql statement for the relation.
|
654
778
|
#
|
655
779
|
# User.where(name: 'Oscar').to_sql
|
656
|
-
# #
|
780
|
+
# # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
657
781
|
def to_sql
|
658
|
-
@to_sql ||=
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
relation.to_sql
|
663
|
-
end
|
664
|
-
else
|
665
|
-
conn = klass.connection
|
666
|
-
conn.unprepared_statement { conn.to_sql(arel) }
|
782
|
+
@to_sql ||= if eager_loading?
|
783
|
+
apply_join_dependency do |relation, join_dependency|
|
784
|
+
relation = join_dependency.apply_column_aliases(relation)
|
785
|
+
relation.to_sql
|
667
786
|
end
|
787
|
+
else
|
788
|
+
conn = klass.connection
|
789
|
+
conn.unprepared_statement { conn.to_sql(arel) }
|
668
790
|
end
|
669
791
|
end
|
670
792
|
|
@@ -672,7 +794,7 @@ module ActiveRecord
|
|
672
794
|
#
|
673
795
|
# User.where(name: 'Oscar').where_values_hash
|
674
796
|
# # => {name: "Oscar"}
|
675
|
-
def where_values_hash(relation_table_name = klass.table_name)
|
797
|
+
def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
|
676
798
|
where_clause.to_h(relation_table_name)
|
677
799
|
end
|
678
800
|
|
@@ -692,7 +814,7 @@ module ActiveRecord
|
|
692
814
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
693
815
|
# Note that this is a naive implementation because we could have strings and symbols which
|
694
816
|
# represent the same association, but that aren't matched by this. Also, we could have
|
695
|
-
# nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
|
817
|
+
# nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
|
696
818
|
def joined_includes_values
|
697
819
|
includes_values & joins_values
|
698
820
|
end
|
@@ -709,8 +831,13 @@ module ActiveRecord
|
|
709
831
|
end
|
710
832
|
end
|
711
833
|
|
712
|
-
def pretty_print(
|
713
|
-
|
834
|
+
def pretty_print(pp)
|
835
|
+
subject = loaded? ? records : annotate("loading for pp")
|
836
|
+
entries = subject.take([limit_value, 11].compact.min)
|
837
|
+
|
838
|
+
entries[10] = "..." if entries.size == 11
|
839
|
+
|
840
|
+
pp.pp(entries)
|
714
841
|
end
|
715
842
|
|
716
843
|
# Returns true if relation is blank.
|
@@ -722,6 +849,10 @@ module ActiveRecord
|
|
722
849
|
@values.dup
|
723
850
|
end
|
724
851
|
|
852
|
+
def values_for_queries # :nodoc:
|
853
|
+
@values.except(:extending, :skip_query_cache, :strict_loading)
|
854
|
+
end
|
855
|
+
|
725
856
|
def inspect
|
726
857
|
subject = loaded? ? records : annotate("loading for inspect")
|
727
858
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
@@ -756,11 +887,9 @@ module ActiveRecord
|
|
756
887
|
def preload_associations(records) # :nodoc:
|
757
888
|
preload = preload_values
|
758
889
|
preload += includes_values unless eager_loading?
|
759
|
-
preloader = nil
|
760
890
|
scope = strict_loading_value ? StrictLoadingScope : nil
|
761
891
|
preload.each do |associations|
|
762
|
-
|
763
|
-
preloader.preload records, associations, scope
|
892
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
|
764
893
|
end
|
765
894
|
end
|
766
895
|
|
@@ -770,13 +899,13 @@ module ActiveRecord
|
|
770
899
|
@loaded = true
|
771
900
|
end
|
772
901
|
|
773
|
-
|
774
|
-
|
902
|
+
private
|
903
|
+
def already_in_scope?(registry)
|
904
|
+
@delegate_to_klass && registry.current_scope(klass, true)
|
775
905
|
end
|
776
906
|
|
777
|
-
|
778
|
-
|
779
|
-
@delegate_to_klass && klass.current_scope(true)
|
907
|
+
def global_scope?(registry)
|
908
|
+
registry.global_current_scope(klass, true)
|
780
909
|
end
|
781
910
|
|
782
911
|
def current_scope_restoring_block(&block)
|
@@ -799,11 +928,20 @@ module ActiveRecord
|
|
799
928
|
klass.create!(attributes, &block)
|
800
929
|
end
|
801
930
|
|
802
|
-
def _scoping(scope)
|
803
|
-
previous
|
931
|
+
def _scoping(scope, registry, all_queries = false)
|
932
|
+
previous = registry.current_scope(klass, true)
|
933
|
+
registry.set_current_scope(klass, scope)
|
934
|
+
|
935
|
+
if all_queries
|
936
|
+
previous_global = registry.global_current_scope(klass, true)
|
937
|
+
registry.set_global_current_scope(klass, scope)
|
938
|
+
end
|
804
939
|
yield
|
805
940
|
ensure
|
806
|
-
klass
|
941
|
+
registry.set_current_scope(klass, previous)
|
942
|
+
if all_queries
|
943
|
+
registry.set_global_current_scope(klass, previous_global)
|
944
|
+
end
|
807
945
|
end
|
808
946
|
|
809
947
|
def _substitute_values(values)
|
@@ -826,44 +964,69 @@ module ActiveRecord
|
|
826
964
|
|
827
965
|
def exec_queries(&block)
|
828
966
|
skip_query_cache_if_necessary do
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
else
|
837
|
-
relation = join_dependency.apply_column_aliases(relation)
|
838
|
-
rows = connection.select_all(relation.arel, "SQL")
|
839
|
-
join_dependency.instantiate(rows, strict_loading_value, &block)
|
840
|
-
end.freeze
|
841
|
-
end
|
842
|
-
else
|
843
|
-
klass.find_by_sql(arel, &block).freeze
|
844
|
-
end
|
967
|
+
rows = if scheduled?
|
968
|
+
future = @future_result
|
969
|
+
@future_result = nil
|
970
|
+
future.result
|
971
|
+
else
|
972
|
+
exec_main_query
|
973
|
+
end
|
845
974
|
|
975
|
+
records = instantiate_records(rows, &block)
|
846
976
|
preload_associations(records) unless skip_preloading_value
|
847
977
|
|
848
978
|
records.each(&:readonly!) if readonly_value
|
849
|
-
records.each
|
979
|
+
records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
|
850
980
|
|
851
981
|
records
|
852
982
|
end
|
853
983
|
end
|
854
984
|
|
855
|
-
def
|
856
|
-
if
|
857
|
-
|
858
|
-
|
985
|
+
def exec_main_query(async: false)
|
986
|
+
if @none
|
987
|
+
if async
|
988
|
+
return FutureResult.wrap([])
|
989
|
+
else
|
990
|
+
return []
|
859
991
|
end
|
992
|
+
end
|
993
|
+
|
994
|
+
skip_query_cache_if_necessary do
|
995
|
+
if where_clause.contradiction?
|
996
|
+
[].freeze
|
997
|
+
elsif eager_loading?
|
998
|
+
apply_join_dependency do |relation, join_dependency|
|
999
|
+
if relation.null_relation?
|
1000
|
+
[].freeze
|
1001
|
+
else
|
1002
|
+
relation = join_dependency.apply_column_aliases(relation)
|
1003
|
+
@_join_dependency = join_dependency
|
1004
|
+
connection.select_all(relation.arel, "SQL", async: async)
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
else
|
1008
|
+
klass._query_by_sql(arel, async: async)
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def instantiate_records(rows, &block)
|
1014
|
+
return [].freeze if rows.empty?
|
1015
|
+
if eager_loading?
|
1016
|
+
records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
|
1017
|
+
@_join_dependency = nil
|
1018
|
+
records
|
860
1019
|
else
|
861
|
-
|
1020
|
+
klass._load_from_sql(rows, &block).freeze
|
862
1021
|
end
|
863
1022
|
end
|
864
1023
|
|
865
|
-
def
|
866
|
-
|
1024
|
+
def skip_query_cache_if_necessary(&block)
|
1025
|
+
if skip_query_cache_value
|
1026
|
+
uncached(&block)
|
1027
|
+
else
|
1028
|
+
yield
|
1029
|
+
end
|
867
1030
|
end
|
868
1031
|
|
869
1032
|
def references_eager_loaded_tables?
|
@@ -889,5 +1052,9 @@ module ActiveRecord
|
|
889
1052
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
890
1053
|
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
891
1054
|
end
|
1055
|
+
|
1056
|
+
def limited_count
|
1057
|
+
limit_value ? count : limit(2).count
|
1058
|
+
end
|
892
1059
|
end
|
893
1060
|
end
|