activerecord 7.0.8.7 → 7.1.0.beta1
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 +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- 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 +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- 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 +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- 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.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.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/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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
- metadata +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -57,6 +57,36 @@ module ActiveRecord
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
# Builds an object (or multiple objects) and returns either the built object or a list of built
|
61
|
+
# objects.
|
62
|
+
#
|
63
|
+
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
|
64
|
+
# attributes on the objects that are to be built.
|
65
|
+
#
|
66
|
+
# ==== Examples
|
67
|
+
# # Build a single new object
|
68
|
+
# User.build(first_name: 'Jamie')
|
69
|
+
#
|
70
|
+
# # Build an Array of new objects
|
71
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
|
72
|
+
#
|
73
|
+
# # Build a single object and pass it into a block to set other attributes.
|
74
|
+
# User.build(first_name: 'Jamie') do |u|
|
75
|
+
# u.is_admin = false
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# # Building an Array of new objects using a block, where the block is executed for each object:
|
79
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
|
80
|
+
# u.is_admin = false
|
81
|
+
# end
|
82
|
+
def build(attributes = nil, &block)
|
83
|
+
if attributes.is_a?(Array)
|
84
|
+
attributes.collect { |attr| build(attr, &block) }
|
85
|
+
else
|
86
|
+
new(attributes, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
60
90
|
# Inserts a single record into the database in a single SQL INSERT
|
61
91
|
# statement. It does not instantiate any models nor does it trigger
|
62
92
|
# Active Record callbacks or validations. Though passed values
|
@@ -92,7 +122,7 @@ module ActiveRecord
|
|
92
122
|
# clause entirely.
|
93
123
|
#
|
94
124
|
# You can also pass an SQL string if you need more control on the return values
|
95
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
125
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
96
126
|
#
|
97
127
|
# [:unique_by]
|
98
128
|
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
@@ -102,7 +132,7 @@ module ActiveRecord
|
|
102
132
|
#
|
103
133
|
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
104
134
|
# row has an existing id, or is not unique by another unique index,
|
105
|
-
#
|
135
|
+
# ActiveRecord::RecordNotUnique is raised.
|
106
136
|
#
|
107
137
|
# Unique indexes can be identified by columns or name:
|
108
138
|
#
|
@@ -164,7 +194,7 @@ module ActiveRecord
|
|
164
194
|
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
165
195
|
# the attributes for a single row and must have the same keys.
|
166
196
|
#
|
167
|
-
# Raises
|
197
|
+
# Raises ActiveRecord::RecordNotUnique if any rows violate a
|
168
198
|
# unique index on the table. In that case, no rows are inserted.
|
169
199
|
#
|
170
200
|
# To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
|
@@ -182,7 +212,7 @@ module ActiveRecord
|
|
182
212
|
# clause entirely.
|
183
213
|
#
|
184
214
|
# You can also pass an SQL string if you need more control on the return values
|
185
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
215
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
186
216
|
#
|
187
217
|
# [:record_timestamps]
|
188
218
|
# By default, automatic setting of timestamp columns is controlled by
|
@@ -219,8 +249,8 @@ module ActiveRecord
|
|
219
249
|
# go through Active Record's type casting and serialization.
|
220
250
|
#
|
221
251
|
# See #upsert_all for documentation.
|
222
|
-
def upsert(attributes,
|
223
|
-
upsert_all([ attributes ],
|
252
|
+
def upsert(attributes, **kwargs)
|
253
|
+
upsert_all([ attributes ], **kwargs)
|
224
254
|
end
|
225
255
|
|
226
256
|
# Updates or inserts (upserts) multiple records into the database in a
|
@@ -248,7 +278,7 @@ module ActiveRecord
|
|
248
278
|
# clause entirely.
|
249
279
|
#
|
250
280
|
# You can also pass an SQL string if you need more control on the return values
|
251
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
281
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
252
282
|
#
|
253
283
|
# [:unique_by]
|
254
284
|
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
@@ -258,7 +288,7 @@ module ActiveRecord
|
|
258
288
|
#
|
259
289
|
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
260
290
|
# row has an existing id, or is not unique by another unique index,
|
261
|
-
#
|
291
|
+
# ActiveRecord::RecordNotUnique is raised.
|
262
292
|
#
|
263
293
|
# Unique indexes can be identified by columns or name:
|
264
294
|
#
|
@@ -425,6 +455,62 @@ module ActiveRecord
|
|
425
455
|
end
|
426
456
|
end
|
427
457
|
|
458
|
+
# Accepts a list of attribute names to be used in the WHERE clause
|
459
|
+
# of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for `#first` and `#last` finder methods.
|
460
|
+
#
|
461
|
+
# class Developer < ActiveRecord::Base
|
462
|
+
# query_constraints :company_id, :id
|
463
|
+
# end
|
464
|
+
#
|
465
|
+
# developer = Developer.first
|
466
|
+
# # SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
|
467
|
+
# developer.inspect # => #<Developer id: 1, company_id: 1, ...>
|
468
|
+
#
|
469
|
+
# developer.update!(name: "Nikita")
|
470
|
+
# # UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
471
|
+
#
|
472
|
+
# It is possible to update attribute used in the query_by clause:
|
473
|
+
# developer.update!(company_id: 2)
|
474
|
+
# # UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
475
|
+
#
|
476
|
+
# developer.name = "Bob"
|
477
|
+
# developer.save!
|
478
|
+
# # UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
479
|
+
#
|
480
|
+
# developer.destroy!
|
481
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
482
|
+
#
|
483
|
+
# developer.delete
|
484
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
485
|
+
#
|
486
|
+
# developer.reload
|
487
|
+
# # SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1
|
488
|
+
def query_constraints(*columns_list)
|
489
|
+
raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty?
|
490
|
+
|
491
|
+
@query_constraints_list = columns_list.map(&:to_s)
|
492
|
+
@has_query_constraints = @query_constraints_list
|
493
|
+
end
|
494
|
+
|
495
|
+
def has_query_constraints? # :nodoc:
|
496
|
+
@has_query_constraints
|
497
|
+
end
|
498
|
+
|
499
|
+
def query_constraints_list # :nodoc:
|
500
|
+
@query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
|
501
|
+
primary_key if primary_key.is_a?(Array)
|
502
|
+
else
|
503
|
+
base_class.query_constraints_list
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# Returns an array of column names to be used in queries. The source of column
|
508
|
+
# names is derived from +query_constraints_list+ or +primary_key+. This method
|
509
|
+
# is for internal use when the primary key is to be treated as an array.
|
510
|
+
def composite_query_constraints_list # :nodoc:
|
511
|
+
@composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
|
512
|
+
end
|
513
|
+
|
428
514
|
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
429
515
|
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
430
516
|
# less efficient than #delete but allows cleanup methods and other actions to be run.
|
@@ -445,7 +531,13 @@ module ActiveRecord
|
|
445
531
|
# todos = [1,2,3]
|
446
532
|
# Todo.destroy(todos)
|
447
533
|
def destroy(id)
|
448
|
-
if
|
534
|
+
multiple_ids = if composite_primary_key?
|
535
|
+
id.first.is_a?(Array)
|
536
|
+
else
|
537
|
+
id.is_a?(Array)
|
538
|
+
end
|
539
|
+
|
540
|
+
if multiple_ids
|
449
541
|
find(id).each(&:destroy)
|
450
542
|
else
|
451
543
|
find(id).destroy
|
@@ -474,7 +566,7 @@ module ActiveRecord
|
|
474
566
|
delete_by(primary_key => id_or_array)
|
475
567
|
end
|
476
568
|
|
477
|
-
def _insert_record(values) # :nodoc:
|
569
|
+
def _insert_record(values, returning) # :nodoc:
|
478
570
|
primary_key = self.primary_key
|
479
571
|
primary_key_value = nil
|
480
572
|
|
@@ -493,7 +585,10 @@ module ActiveRecord
|
|
493
585
|
im.insert(values.transform_keys { |name| arel_table[name] })
|
494
586
|
end
|
495
587
|
|
496
|
-
connection.insert(
|
588
|
+
connection.insert(
|
589
|
+
im, "#{self} Create", primary_key || false, primary_key_value,
|
590
|
+
returning: returning
|
591
|
+
)
|
497
592
|
end
|
498
593
|
|
499
594
|
def _update_record(values, constraints) # :nodoc:
|
@@ -530,6 +625,14 @@ module ActiveRecord
|
|
530
625
|
end
|
531
626
|
|
532
627
|
private
|
628
|
+
def inherited(subclass)
|
629
|
+
super
|
630
|
+
subclass.class_eval do
|
631
|
+
@_query_constraints_list = nil
|
632
|
+
@has_query_constraints = false
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
533
636
|
# Given a class, an attributes hash, +instantiate_instance_of+ returns a
|
534
637
|
# new instance of the class. Accepts only keys as strings.
|
535
638
|
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
@@ -677,11 +780,7 @@ module ActiveRecord
|
|
677
780
|
def destroy
|
678
781
|
_raise_readonly_record_error if readonly?
|
679
782
|
destroy_associations
|
680
|
-
@_trigger_destroy_callback
|
681
|
-
destroy_row > 0
|
682
|
-
else
|
683
|
-
true
|
684
|
-
end
|
783
|
+
@_trigger_destroy_callback ||= persisted? && destroy_row > 0
|
685
784
|
@destroyed = true
|
686
785
|
@previously_new_record = false
|
687
786
|
freeze
|
@@ -709,11 +808,14 @@ module ActiveRecord
|
|
709
808
|
# Note: The new instance will share a link to the same attributes as the original class.
|
710
809
|
# Therefore the STI column value will still be the same.
|
711
810
|
# Any change to the attributes on either instance will affect both instances.
|
811
|
+
# This includes any attribute initialization done by the new instance.
|
812
|
+
#
|
712
813
|
# If you want to change the STI column as well, use #becomes! instead.
|
713
814
|
def becomes(klass)
|
714
815
|
became = klass.allocate
|
715
816
|
|
716
817
|
became.send(:initialize) do |becoming|
|
818
|
+
@attributes.reverse_merge!(becoming.instance_variable_get(:@attributes))
|
717
819
|
becoming.instance_variable_set(:@attributes, @attributes)
|
718
820
|
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
719
821
|
becoming.instance_variable_set(:@new_record, new_record?)
|
@@ -748,7 +850,7 @@ module ActiveRecord
|
|
748
850
|
# * updated_at/updated_on column is updated if that column is available.
|
749
851
|
# * Updates all the attributes that are dirty in this object.
|
750
852
|
#
|
751
|
-
# This method raises an ActiveRecord::ActiveRecordError
|
853
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
752
854
|
# attribute is marked as readonly.
|
753
855
|
#
|
754
856
|
# Also see #update_column.
|
@@ -760,6 +862,28 @@ module ActiveRecord
|
|
760
862
|
save(validate: false)
|
761
863
|
end
|
762
864
|
|
865
|
+
# Updates a single attribute and saves the record.
|
866
|
+
# This is especially useful for boolean flags on existing records. Also note that
|
867
|
+
#
|
868
|
+
# * Validation is skipped.
|
869
|
+
# * \Callbacks are invoked.
|
870
|
+
# * updated_at/updated_on column is updated if that column is available.
|
871
|
+
# * Updates all the attributes that are dirty in this object.
|
872
|
+
#
|
873
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
874
|
+
# attribute is marked as readonly.
|
875
|
+
#
|
876
|
+
# If any of the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
|
877
|
+
# and #update_attribute! raises ActiveRecord::RecordNotSaved. See
|
878
|
+
# ActiveRecord::Callbacks for further details.
|
879
|
+
def update_attribute!(name, value)
|
880
|
+
name = name.to_s
|
881
|
+
verify_readonly_attribute(name)
|
882
|
+
public_send("#{name}=", value)
|
883
|
+
|
884
|
+
save!(validate: false)
|
885
|
+
end
|
886
|
+
|
763
887
|
# Updates the attributes of the model from the passed-in hash and saves the
|
764
888
|
# record, all wrapped in a transaction. If the object is invalid, the saving
|
765
889
|
# will fail and false will be returned.
|
@@ -946,7 +1070,7 @@ module ActiveRecord
|
|
946
1070
|
self.class.connection.clear_query_cache
|
947
1071
|
|
948
1072
|
fresh_object = if apply_scoping?(options)
|
949
|
-
_find_record(options)
|
1073
|
+
_find_record((options || {}).merge(all_queries: true))
|
950
1074
|
else
|
951
1075
|
self.class.unscoped { _find_record(options) }
|
952
1076
|
end
|
@@ -997,10 +1121,12 @@ module ActiveRecord
|
|
997
1121
|
_raise_readonly_record_error if readonly?
|
998
1122
|
|
999
1123
|
attribute_names = timestamp_attributes_for_update_in_model
|
1000
|
-
attribute_names
|
1124
|
+
attribute_names = (attribute_names | names).map! do |name|
|
1001
1125
|
name = name.to_s
|
1002
|
-
self.class.attribute_aliases[name] || name
|
1003
|
-
|
1126
|
+
name = self.class.attribute_aliases[name] || name
|
1127
|
+
verify_readonly_attribute(name)
|
1128
|
+
name
|
1129
|
+
end
|
1004
1130
|
|
1005
1131
|
unless attribute_names.empty?
|
1006
1132
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -1011,6 +1137,12 @@ module ActiveRecord
|
|
1011
1137
|
end
|
1012
1138
|
|
1013
1139
|
private
|
1140
|
+
def init_internals
|
1141
|
+
super
|
1142
|
+
@_trigger_destroy_callback = @_trigger_update_callback = nil
|
1143
|
+
@previously_new_record = false
|
1144
|
+
end
|
1145
|
+
|
1014
1146
|
def strict_loaded_associations
|
1015
1147
|
@association_cache.find_all do |_, assoc|
|
1016
1148
|
assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
|
@@ -1018,10 +1150,23 @@ module ActiveRecord
|
|
1018
1150
|
end
|
1019
1151
|
|
1020
1152
|
def _find_record(options)
|
1153
|
+
all_queries = options ? options[:all_queries] : nil
|
1154
|
+
base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
|
1155
|
+
|
1021
1156
|
if options && options[:lock]
|
1022
|
-
|
1157
|
+
base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
|
1158
|
+
else
|
1159
|
+
base.find_by!(_in_memory_query_constraints_hash)
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
def _in_memory_query_constraints_hash
|
1164
|
+
if self.class.query_constraints_list.nil?
|
1165
|
+
{ @primary_key => id }
|
1023
1166
|
else
|
1024
|
-
self.class.
|
1167
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1168
|
+
attribute(column_name)
|
1169
|
+
end
|
1025
1170
|
end
|
1026
1171
|
end
|
1027
1172
|
|
@@ -1031,7 +1176,13 @@ module ActiveRecord
|
|
1031
1176
|
end
|
1032
1177
|
|
1033
1178
|
def _query_constraints_hash
|
1034
|
-
|
1179
|
+
if self.class.query_constraints_list.nil?
|
1180
|
+
{ @primary_key => id_in_database }
|
1181
|
+
else
|
1182
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1183
|
+
attribute_in_database(column_name)
|
1184
|
+
end
|
1185
|
+
end
|
1035
1186
|
end
|
1036
1187
|
|
1037
1188
|
# A hook to be overridden by association modules.
|
@@ -1095,11 +1246,16 @@ module ActiveRecord
|
|
1095
1246
|
def _create_record(attribute_names = self.attribute_names)
|
1096
1247
|
attribute_names = attributes_for_create(attribute_names)
|
1097
1248
|
|
1098
|
-
|
1099
|
-
|
1249
|
+
returning_columns = self.class._returning_columns_for_insert
|
1250
|
+
|
1251
|
+
returning_values = self.class._insert_record(
|
1252
|
+
attributes_with_values(attribute_names),
|
1253
|
+
returning_columns
|
1100
1254
|
)
|
1101
1255
|
|
1102
|
-
|
1256
|
+
returning_columns.zip(returning_values).each do |column, value|
|
1257
|
+
_write_attribute(column, value) if !_read_attribute(column)
|
1258
|
+
end if returning_values
|
1103
1259
|
|
1104
1260
|
@new_record = false
|
1105
1261
|
@previously_new_record = true
|
@@ -1131,11 +1287,5 @@ module ActiveRecord
|
|
1131
1287
|
persisted?, new_record?, or destroyed? before touching.
|
1132
1288
|
MSG
|
1133
1289
|
end
|
1134
|
-
|
1135
|
-
# The name of the method used to touch a +belongs_to+ association when the
|
1136
|
-
# +:touch+ option is used.
|
1137
|
-
def belongs_to_touch_method
|
1138
|
-
:touch
|
1139
|
-
end
|
1140
1290
|
end
|
1141
1291
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Promise < BasicObject
|
5
|
+
undef_method :==, :!, :!=
|
6
|
+
|
7
|
+
def initialize(future_result, block) # :nodoc:
|
8
|
+
@future_result = future_result
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns whether the associated query is still being executed or not.
|
13
|
+
def pending?
|
14
|
+
@future_result.pending?
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the query result.
|
18
|
+
# If the query wasn't completed yet, accessing +#value+ will block until the query completes.
|
19
|
+
# If the query failed, +#value+ will raise the corresponding error.
|
20
|
+
def value
|
21
|
+
return @value if defined? @value
|
22
|
+
|
23
|
+
result = @future_result.result
|
24
|
+
@value = if @block
|
25
|
+
@block.call(result)
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a new +ActiveRecord::Promise+ that will apply the passed block
|
32
|
+
# when the value is accessed:
|
33
|
+
#
|
34
|
+
# Post.async_pluck(:title).then { |title| title.upcase }.value
|
35
|
+
# # => "POST TITLE"
|
36
|
+
def then(&block)
|
37
|
+
Promise.new(@future_result, @block ? @block >> block : block)
|
38
|
+
end
|
39
|
+
|
40
|
+
[:class, :respond_to?, :is_a?].each do |method|
|
41
|
+
define_method(method, ::Object.instance_method(method))
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect # :nodoc:
|
45
|
+
"#<ActiveRecord::Promise status=#{status}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def pretty_print(q) # :nodoc:
|
49
|
+
q.text(inspect)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def status
|
54
|
+
if @future_result.pending?
|
55
|
+
:pending
|
56
|
+
elsif @future_result.canceled?
|
57
|
+
:canceled
|
58
|
+
else
|
59
|
+
:complete
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Complete < self # :nodoc:
|
64
|
+
attr_reader :value
|
65
|
+
|
66
|
+
def initialize(value)
|
67
|
+
@value = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def then
|
71
|
+
Complete.new(yield @value)
|
72
|
+
end
|
73
|
+
|
74
|
+
def pending?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def status
|
80
|
+
:complete
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -26,32 +26,14 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.run
|
29
|
-
|
30
|
-
|
31
|
-
if ActiveRecord.legacy_connection_handling
|
32
|
-
ActiveRecord::Base.connection_handlers.each do |key, handler|
|
33
|
-
pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
34
|
-
end
|
35
|
-
else
|
36
|
-
pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
37
|
-
end
|
38
|
-
|
39
|
-
pools
|
29
|
+
ActiveRecord::Base.connection_handler.each_connection_pool.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
|
40
30
|
end
|
41
31
|
|
42
32
|
def self.complete(pools)
|
43
33
|
pools.each { |pool| pool.disable_query_cache! }
|
44
34
|
|
45
|
-
|
46
|
-
|
47
|
-
handler.connection_pool_list.each do |pool|
|
48
|
-
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
49
|
-
end
|
50
|
-
end
|
51
|
-
else
|
52
|
-
ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
|
53
|
-
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
54
|
-
end
|
35
|
+
ActiveRecord::Base.connection_handler.each_connection_pool do |pool|
|
36
|
+
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
55
37
|
end
|
56
38
|
end
|
57
39
|
|