activerecord 6.1.7 → 7.1.0
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 +1516 -1019
- data/MIT-LICENSE +1 -1
- data/README.rdoc +17 -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 +50 -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 +35 -31
- 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.rb +26 -16
- data/lib/active_record/associations/preloader/association.rb +207 -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 +423 -289
- 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 +61 -14
- 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 +25 -10
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +10 -13
- data/lib/active_record/attribute_methods.rb +121 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +61 -30
- 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 +96 -590
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -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 +360 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
- 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 +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
- 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 +18 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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/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 +381 -69
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
- 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 +65 -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 +294 -102
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +107 -136
- data/lib/active_record/core.rb +194 -224
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +84 -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 +61 -15
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- 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 +224 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -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 +172 -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 +96 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +156 -62
- data/lib/active_record/errors.rb +171 -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 +131 -86
- data/lib/active_record/future_result.rb +164 -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 +133 -20
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +117 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +56 -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 +108 -13
- data/lib/active_record/migration/compatibility.rb +221 -48
- 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.rb +355 -171
- data/lib/active_record/model_schema.rb +116 -97
- data/lib/active_record/nested_attributes.rb +36 -15
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +405 -85
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- 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 +219 -43
- data/lib/active_record/railties/controller_runtime.rb +13 -9
- data/lib/active_record/railties/databases.rake +185 -249
- 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 +229 -80
- 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 +211 -90
- data/lib/active_record/relation/delegation.rb +27 -13
- 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 +4 -6
- 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 +654 -127
- 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 +262 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +18 -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 +225 -136
- 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 +116 -96
- data/lib/active_record/timestamp.rb +28 -17
- 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 +0 -8
- 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 +0 -12
- 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 +139 -19
- 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 +92 -13
- 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 find no record because a
|
168
|
+
# 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,56 @@ 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
|
-
def none?
|
271
|
-
return
|
294
|
+
def none?(*args)
|
295
|
+
return true if @none
|
296
|
+
|
297
|
+
return super if args.present? || block_given?
|
272
298
|
empty?
|
273
299
|
end
|
274
300
|
|
275
301
|
# Returns true if there are any records.
|
276
|
-
def any?
|
277
|
-
return
|
302
|
+
def any?(*args)
|
303
|
+
return false if @none
|
304
|
+
|
305
|
+
return super if args.present? || block_given?
|
278
306
|
!empty?
|
279
307
|
end
|
280
308
|
|
281
309
|
# Returns true if there is exactly one record.
|
282
|
-
def one?
|
283
|
-
return
|
284
|
-
|
310
|
+
def one?(*args)
|
311
|
+
return false if @none
|
312
|
+
|
313
|
+
return super if args.present? || block_given?
|
314
|
+
return records.one? if loaded?
|
315
|
+
limited_count == 1
|
285
316
|
end
|
286
317
|
|
287
318
|
# Returns true if there is more than one record.
|
288
319
|
def many?
|
320
|
+
return false if @none
|
321
|
+
|
289
322
|
return super if block_given?
|
290
|
-
|
323
|
+
return records.many? if loaded?
|
324
|
+
limited_count > 1
|
291
325
|
end
|
292
326
|
|
293
327
|
# Returns a stable cache key that can be used to identify this query.
|
@@ -297,7 +331,7 @@ module ActiveRecord
|
|
297
331
|
# # => "products/query-1850ab3d302391b85b8693e941286659"
|
298
332
|
#
|
299
333
|
# 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.
|
334
|
+
# in \Rails 6.0 and earlier, the cache key will also include a version.
|
301
335
|
#
|
302
336
|
# ActiveRecord::Base.collection_cache_versioning = false
|
303
337
|
# Product.where("name like ?", "%Cosmic Encounter%").cache_key
|
@@ -344,7 +378,7 @@ module ActiveRecord
|
|
344
378
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
379
|
timestamp_column = timestamp_column.to_s
|
346
380
|
|
347
|
-
if loaded?
|
381
|
+
if loaded?
|
348
382
|
size = records.size
|
349
383
|
if size > 0
|
350
384
|
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
@@ -357,6 +391,7 @@ module ActiveRecord
|
|
357
391
|
|
358
392
|
if collection.has_limit_or_offset?
|
359
393
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
394
|
+
query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
|
360
395
|
subquery_alias = "subquery_for_cache_key"
|
361
396
|
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
362
397
|
arel = query.build_subquery(subquery_alias, select_values % subquery_column)
|
@@ -377,7 +412,7 @@ module ActiveRecord
|
|
377
412
|
end
|
378
413
|
|
379
414
|
if timestamp
|
380
|
-
"#{size}-#{timestamp.utc.
|
415
|
+
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
381
416
|
else
|
382
417
|
"#{size}"
|
383
418
|
end
|
@@ -398,17 +433,30 @@ module ActiveRecord
|
|
398
433
|
# Comment.where(post_id: 1).scoping do
|
399
434
|
# Comment.first
|
400
435
|
# end
|
401
|
-
# #
|
436
|
+
# # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
437
|
+
#
|
438
|
+
# If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
|
439
|
+
# for the relation including +update+ and +delete+ on instances.
|
440
|
+
# Once +all_queries+ is set to true it cannot be set to false in a
|
441
|
+
# nested block.
|
402
442
|
#
|
403
443
|
# Please check unscoped if you want to remove all previous scopes (including
|
404
444
|
# the default_scope) during the execution of a block.
|
405
|
-
def scoping
|
406
|
-
|
445
|
+
def scoping(all_queries: nil, &block)
|
446
|
+
registry = klass.scope_registry
|
447
|
+
if global_scope?(registry) && all_queries == false
|
448
|
+
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
449
|
+
elsif already_in_scope?(registry)
|
450
|
+
yield
|
451
|
+
else
|
452
|
+
_scoping(self, registry, all_queries, &block)
|
453
|
+
end
|
407
454
|
end
|
408
455
|
|
409
|
-
def _exec_scope(
|
456
|
+
def _exec_scope(...) # :nodoc:
|
410
457
|
@delegate_to_klass = true
|
411
|
-
|
458
|
+
registry = klass.scope_registry
|
459
|
+
_scoping(nil, registry) { instance_exec(...) || self }
|
412
460
|
ensure
|
413
461
|
@delegate_to_klass = false
|
414
462
|
end
|
@@ -422,7 +470,8 @@ module ActiveRecord
|
|
422
470
|
#
|
423
471
|
# ==== Parameters
|
424
472
|
#
|
425
|
-
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
|
473
|
+
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement. Any strings provided will
|
474
|
+
# be type cast, unless you use +Arel.sql+. (Don't pass user-provided values to +Arel.sql+.)
|
426
475
|
#
|
427
476
|
# ==== Examples
|
428
477
|
#
|
@@ -437,19 +486,13 @@ module ActiveRecord
|
|
437
486
|
#
|
438
487
|
# # Update all invoices and set the number column to its id value.
|
439
488
|
# Invoice.update_all('number = id')
|
489
|
+
#
|
490
|
+
# # Update all books with 'Rails' in their title
|
491
|
+
# Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
|
440
492
|
def update_all(updates)
|
441
493
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
442
494
|
|
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
|
495
|
+
return 0 if @none
|
453
496
|
|
454
497
|
if updates.is_a?(Hash)
|
455
498
|
if klass.locking_enabled? &&
|
@@ -458,11 +501,17 @@ module ActiveRecord
|
|
458
501
|
attr = table[klass.locking_column]
|
459
502
|
updates[attr.name] = _increment_attribute(attr)
|
460
503
|
end
|
461
|
-
|
504
|
+
values = _substitute_values(updates)
|
462
505
|
else
|
463
|
-
|
506
|
+
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
464
507
|
end
|
465
508
|
|
509
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
510
|
+
arel.source.left = table
|
511
|
+
|
512
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
513
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
514
|
+
stmt = arel.compile_update(values, table[primary_key], having_clause_ast, group_values_arel_columns)
|
466
515
|
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
467
516
|
end
|
468
517
|
|
@@ -474,6 +523,14 @@ module ActiveRecord
|
|
474
523
|
end
|
475
524
|
end
|
476
525
|
|
526
|
+
def update!(id = :all, attributes) # :nodoc:
|
527
|
+
if id == :all
|
528
|
+
each { |record| record.update!(attributes) }
|
529
|
+
else
|
530
|
+
klass.update!(id, attributes)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
477
534
|
# Updates the counters of the records in the current relation.
|
478
535
|
#
|
479
536
|
# ==== Parameters
|
@@ -572,6 +629,8 @@ module ActiveRecord
|
|
572
629
|
# Post.distinct.delete_all
|
573
630
|
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
|
574
631
|
def delete_all
|
632
|
+
return 0 if @none
|
633
|
+
|
575
634
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
|
576
635
|
value = @values[method]
|
577
636
|
method == :distinct ? value : value&.any?
|
@@ -583,15 +642,11 @@ module ActiveRecord
|
|
583
642
|
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
584
643
|
arel.source.left = table
|
585
644
|
|
586
|
-
|
587
|
-
|
588
|
-
stmt
|
589
|
-
stmt.take(arel.limit)
|
590
|
-
stmt.offset(arel.offset)
|
591
|
-
stmt.order(*arel.orders)
|
592
|
-
stmt.wheres = arel.constraints
|
645
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
646
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
647
|
+
stmt = arel.compile_delete(table[primary_key], having_clause_ast, group_values_arel_columns)
|
593
648
|
|
594
|
-
klass.connection.delete(stmt, "#{klass}
|
649
|
+
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
|
595
650
|
end
|
596
651
|
|
597
652
|
# Finds and destroys all records matching the specified conditions.
|
@@ -620,6 +675,47 @@ module ActiveRecord
|
|
620
675
|
where(*args).delete_all
|
621
676
|
end
|
622
677
|
|
678
|
+
# Schedule the query to be performed from a background thread pool.
|
679
|
+
#
|
680
|
+
# Post.where(published: true).load_async # => #<ActiveRecord::Relation>
|
681
|
+
#
|
682
|
+
# When the +Relation+ is iterated, if the background query wasn't executed yet,
|
683
|
+
# it will be performed by the foreground thread.
|
684
|
+
#
|
685
|
+
# Note that {config.active_record.async_query_executor}[https://guides.rubyonrails.org/configuring.html#config-active-record-async-query-executor] must be configured
|
686
|
+
# for queries to actually be executed concurrently. Otherwise it defaults to
|
687
|
+
# executing them in the foreground.
|
688
|
+
#
|
689
|
+
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
690
|
+
# fixtures are enabled.
|
691
|
+
#
|
692
|
+
# If the query was actually executed in the background, the Active Record logs will show
|
693
|
+
# it by prefixing the log line with <tt>ASYNC</tt>:
|
694
|
+
#
|
695
|
+
# ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
|
696
|
+
def load_async
|
697
|
+
return load if !connection.async_enabled?
|
698
|
+
|
699
|
+
unless loaded?
|
700
|
+
result = exec_main_query(async: connection.current_transaction.closed?)
|
701
|
+
|
702
|
+
if result.is_a?(Array)
|
703
|
+
@records = result
|
704
|
+
else
|
705
|
+
@future_result = result
|
706
|
+
end
|
707
|
+
@loaded = true
|
708
|
+
end
|
709
|
+
|
710
|
+
self
|
711
|
+
end
|
712
|
+
|
713
|
+
# Returns <tt>true</tt> if the relation was scheduled on the background
|
714
|
+
# thread pool.
|
715
|
+
def scheduled?
|
716
|
+
!!@future_result
|
717
|
+
end
|
718
|
+
|
623
719
|
# Causes the records to be loaded from the database if they have not
|
624
720
|
# been loaded already. You can use this if for some reason you need
|
625
721
|
# to explicitly load some records before actually using them. The
|
@@ -627,7 +723,7 @@ module ActiveRecord
|
|
627
723
|
#
|
628
724
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
629
725
|
def load(&block)
|
630
|
-
|
726
|
+
if !loaded? || scheduled?
|
631
727
|
@records = exec_queries(&block)
|
632
728
|
@loaded = true
|
633
729
|
end
|
@@ -642,29 +738,30 @@ module ActiveRecord
|
|
642
738
|
end
|
643
739
|
|
644
740
|
def reset
|
741
|
+
@future_result&.cancel
|
742
|
+
@future_result = nil
|
645
743
|
@delegate_to_klass = false
|
646
744
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
647
745
|
@offsets = @take = nil
|
648
746
|
@cache_keys = nil
|
649
|
-
@
|
747
|
+
@cache_versions = nil
|
748
|
+
@records = nil
|
650
749
|
self
|
651
750
|
end
|
652
751
|
|
653
752
|
# Returns sql statement for the relation.
|
654
753
|
#
|
655
754
|
# User.where(name: 'Oscar').to_sql
|
656
|
-
# #
|
755
|
+
# # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
657
756
|
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) }
|
757
|
+
@to_sql ||= if eager_loading?
|
758
|
+
apply_join_dependency do |relation, join_dependency|
|
759
|
+
relation = join_dependency.apply_column_aliases(relation)
|
760
|
+
relation.to_sql
|
667
761
|
end
|
762
|
+
else
|
763
|
+
conn = klass.connection
|
764
|
+
conn.unprepared_statement { conn.to_sql(arel) }
|
668
765
|
end
|
669
766
|
end
|
670
767
|
|
@@ -672,7 +769,7 @@ module ActiveRecord
|
|
672
769
|
#
|
673
770
|
# User.where(name: 'Oscar').where_values_hash
|
674
771
|
# # => {name: "Oscar"}
|
675
|
-
def where_values_hash(relation_table_name = klass.table_name)
|
772
|
+
def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
|
676
773
|
where_clause.to_h(relation_table_name)
|
677
774
|
end
|
678
775
|
|
@@ -692,7 +789,7 @@ module ActiveRecord
|
|
692
789
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
693
790
|
# Note that this is a naive implementation because we could have strings and symbols which
|
694
791
|
# 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] }
|
792
|
+
# nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
|
696
793
|
def joined_includes_values
|
697
794
|
includes_values & joins_values
|
698
795
|
end
|
@@ -709,8 +806,13 @@ module ActiveRecord
|
|
709
806
|
end
|
710
807
|
end
|
711
808
|
|
712
|
-
def pretty_print(
|
713
|
-
|
809
|
+
def pretty_print(pp)
|
810
|
+
subject = loaded? ? records : annotate("loading for pp")
|
811
|
+
entries = subject.take([limit_value, 11].compact.min)
|
812
|
+
|
813
|
+
entries[10] = "..." if entries.size == 11
|
814
|
+
|
815
|
+
pp.pp(entries)
|
714
816
|
end
|
715
817
|
|
716
818
|
# Returns true if relation is blank.
|
@@ -722,6 +824,10 @@ module ActiveRecord
|
|
722
824
|
@values.dup
|
723
825
|
end
|
724
826
|
|
827
|
+
def values_for_queries # :nodoc:
|
828
|
+
@values.except(:extending, :skip_query_cache, :strict_loading)
|
829
|
+
end
|
830
|
+
|
725
831
|
def inspect
|
726
832
|
subject = loaded? ? records : annotate("loading for inspect")
|
727
833
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
@@ -756,11 +862,9 @@ module ActiveRecord
|
|
756
862
|
def preload_associations(records) # :nodoc:
|
757
863
|
preload = preload_values
|
758
864
|
preload += includes_values unless eager_loading?
|
759
|
-
preloader = nil
|
760
865
|
scope = strict_loading_value ? StrictLoadingScope : nil
|
761
866
|
preload.each do |associations|
|
762
|
-
|
763
|
-
preloader.preload records, associations, scope
|
867
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
|
764
868
|
end
|
765
869
|
end
|
766
870
|
|
@@ -770,13 +874,13 @@ module ActiveRecord
|
|
770
874
|
@loaded = true
|
771
875
|
end
|
772
876
|
|
773
|
-
|
774
|
-
|
877
|
+
private
|
878
|
+
def already_in_scope?(registry)
|
879
|
+
@delegate_to_klass && registry.current_scope(klass, true)
|
775
880
|
end
|
776
881
|
|
777
|
-
|
778
|
-
|
779
|
-
@delegate_to_klass && klass.current_scope(true)
|
882
|
+
def global_scope?(registry)
|
883
|
+
registry.global_current_scope(klass, true)
|
780
884
|
end
|
781
885
|
|
782
886
|
def current_scope_restoring_block(&block)
|
@@ -799,11 +903,20 @@ module ActiveRecord
|
|
799
903
|
klass.create!(attributes, &block)
|
800
904
|
end
|
801
905
|
|
802
|
-
def _scoping(scope)
|
803
|
-
previous
|
906
|
+
def _scoping(scope, registry, all_queries = false)
|
907
|
+
previous = registry.current_scope(klass, true)
|
908
|
+
registry.set_current_scope(klass, scope)
|
909
|
+
|
910
|
+
if all_queries
|
911
|
+
previous_global = registry.global_current_scope(klass, true)
|
912
|
+
registry.set_global_current_scope(klass, scope)
|
913
|
+
end
|
804
914
|
yield
|
805
915
|
ensure
|
806
|
-
klass
|
916
|
+
registry.set_current_scope(klass, previous)
|
917
|
+
if all_queries
|
918
|
+
registry.set_global_current_scope(klass, previous_global)
|
919
|
+
end
|
807
920
|
end
|
808
921
|
|
809
922
|
def _substitute_values(values)
|
@@ -826,44 +939,69 @@ module ActiveRecord
|
|
826
939
|
|
827
940
|
def exec_queries(&block)
|
828
941
|
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
|
942
|
+
rows = if scheduled?
|
943
|
+
future = @future_result
|
944
|
+
@future_result = nil
|
945
|
+
future.result
|
946
|
+
else
|
947
|
+
exec_main_query
|
948
|
+
end
|
845
949
|
|
950
|
+
records = instantiate_records(rows, &block)
|
846
951
|
preload_associations(records) unless skip_preloading_value
|
847
952
|
|
848
953
|
records.each(&:readonly!) if readonly_value
|
849
|
-
records.each
|
954
|
+
records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
|
850
955
|
|
851
956
|
records
|
852
957
|
end
|
853
958
|
end
|
854
959
|
|
855
|
-
def
|
856
|
-
if
|
857
|
-
|
858
|
-
|
960
|
+
def exec_main_query(async: false)
|
961
|
+
if @none
|
962
|
+
if async
|
963
|
+
return Promise::Complete.new([])
|
964
|
+
else
|
965
|
+
return []
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
skip_query_cache_if_necessary do
|
970
|
+
if where_clause.contradiction?
|
971
|
+
[].freeze
|
972
|
+
elsif eager_loading?
|
973
|
+
apply_join_dependency do |relation, join_dependency|
|
974
|
+
if relation.null_relation?
|
975
|
+
[].freeze
|
976
|
+
else
|
977
|
+
relation = join_dependency.apply_column_aliases(relation)
|
978
|
+
@_join_dependency = join_dependency
|
979
|
+
connection.select_all(relation.arel, "SQL", async: async)
|
980
|
+
end
|
981
|
+
end
|
982
|
+
else
|
983
|
+
klass._query_by_sql(arel, async: async)
|
859
984
|
end
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
def instantiate_records(rows, &block)
|
989
|
+
return [].freeze if rows.empty?
|
990
|
+
if eager_loading?
|
991
|
+
records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
|
992
|
+
@_join_dependency = nil
|
993
|
+
records
|
860
994
|
else
|
861
|
-
|
995
|
+
klass._load_from_sql(rows, &block).freeze
|
862
996
|
end
|
863
997
|
end
|
864
998
|
|
865
|
-
def
|
866
|
-
|
999
|
+
def skip_query_cache_if_necessary(&block)
|
1000
|
+
if skip_query_cache_value
|
1001
|
+
uncached(&block)
|
1002
|
+
else
|
1003
|
+
yield
|
1004
|
+
end
|
867
1005
|
end
|
868
1006
|
|
869
1007
|
def references_eager_loaded_tables?
|
@@ -889,5 +1027,9 @@ module ActiveRecord
|
|
889
1027
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
890
1028
|
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
891
1029
|
end
|
1030
|
+
|
1031
|
+
def limited_count
|
1032
|
+
limit_value ? count : limit(2).count
|
1033
|
+
end
|
892
1034
|
end
|
893
1035
|
end
|