activerecord 6.0.5.1 → 6.1.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1163 -774
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +49 -26
- data/lib/active_record/associations/association_scope.rb +18 -20
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +32 -18
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +14 -8
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +118 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -8
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +16 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +265 -64
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +69 -34
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +38 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +24 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +72 -18
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +89 -14
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +61 -59
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +279 -101
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +104 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +61 -38
- data/lib/active_record/relation/query_methods.rb +324 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/relation.rb +100 -81
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -3
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +79 -31
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +24 -25
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
8
|
:extending, :unscope, :optimizer_hints, :annotate]
|
9
9
|
|
10
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
10
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
|
13
13
|
CLAUSE_METHODS = [:where, :having, :from]
|
@@ -28,7 +28,6 @@ module ActiveRecord
|
|
28
28
|
@klass = klass
|
29
29
|
@table = table
|
30
30
|
@values = values
|
31
|
-
@offsets = {}
|
32
31
|
@loaded = false
|
33
32
|
@predicate_builder = predicate_builder
|
34
33
|
@delegate_to_klass = false
|
@@ -40,8 +39,9 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def arel_attribute(name) # :nodoc:
|
43
|
-
|
42
|
+
table[name]
|
44
43
|
end
|
44
|
+
deprecate :arel_attribute
|
45
45
|
|
46
46
|
def bind_attribute(name, value) # :nodoc:
|
47
47
|
if reflection = klass._reflect_on_association(name)
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
|
50
50
|
end
|
51
51
|
|
52
|
-
attr =
|
52
|
+
attr = table[name]
|
53
53
|
bind = predicate_builder.build_bind_attribute(attr.name, value)
|
54
54
|
yield attr, bind
|
55
55
|
end
|
@@ -67,10 +67,9 @@ module ActiveRecord
|
|
67
67
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
68
|
# user.name # => Oscar
|
69
69
|
def new(attributes = nil, &block)
|
70
|
-
block =
|
71
|
-
scoping {
|
70
|
+
block = current_scope_restoring_block(&block)
|
71
|
+
scoping { _new(attributes, &block) }
|
72
72
|
end
|
73
|
-
|
74
73
|
alias build new
|
75
74
|
|
76
75
|
# Tries to create a new record with the same scoped attributes
|
@@ -96,8 +95,8 @@ module ActiveRecord
|
|
96
95
|
if attributes.is_a?(Array)
|
97
96
|
attributes.collect { |attr| create(attr, &block) }
|
98
97
|
else
|
99
|
-
block =
|
100
|
-
scoping {
|
98
|
+
block = current_scope_restoring_block(&block)
|
99
|
+
scoping { _create(attributes, &block) }
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
@@ -111,8 +110,8 @@ module ActiveRecord
|
|
111
110
|
if attributes.is_a?(Array)
|
112
111
|
attributes.collect { |attr| create!(attr, &block) }
|
113
112
|
else
|
114
|
-
block =
|
115
|
-
scoping {
|
113
|
+
block = current_scope_restoring_block(&block)
|
114
|
+
scoping { _create!(attributes, &block) }
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
@@ -308,7 +307,7 @@ module ActiveRecord
|
|
308
307
|
# last updated record.
|
309
308
|
#
|
310
309
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
311
|
-
def cache_key(timestamp_column =
|
310
|
+
def cache_key(timestamp_column = "updated_at")
|
312
311
|
@cache_keys ||= {}
|
313
312
|
@cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
|
314
313
|
end
|
@@ -317,7 +316,7 @@ module ActiveRecord
|
|
317
316
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
318
317
|
key = "#{klass.model_name.cache_key}/query-#{query_signature}"
|
319
318
|
|
320
|
-
if
|
319
|
+
if collection_cache_versioning
|
321
320
|
key
|
322
321
|
else
|
323
322
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
@@ -343,15 +342,17 @@ module ActiveRecord
|
|
343
342
|
end
|
344
343
|
|
345
344
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
|
+
timestamp_column = timestamp_column.to_s
|
346
|
+
|
346
347
|
if loaded? || distinct_value
|
347
348
|
size = records.size
|
348
349
|
if size > 0
|
349
|
-
timestamp =
|
350
|
+
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
350
351
|
end
|
351
352
|
else
|
352
353
|
collection = eager_loading? ? apply_join_dependency : self
|
353
354
|
|
354
|
-
column = connection.visitor.compile(
|
355
|
+
column = connection.visitor.compile(table[timestamp_column])
|
355
356
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
356
357
|
|
357
358
|
if collection.has_limit_or_offset?
|
@@ -365,14 +366,12 @@ module ActiveRecord
|
|
365
366
|
arel = query.arel
|
366
367
|
end
|
367
368
|
|
368
|
-
|
369
|
+
size, timestamp = connection.select_rows(arel, nil).first
|
369
370
|
|
370
|
-
if
|
371
|
+
if size
|
371
372
|
column_type = klass.type_for_attribute(timestamp_column)
|
372
|
-
timestamp = column_type.deserialize(
|
373
|
-
size = result["size"]
|
373
|
+
timestamp = column_type.deserialize(timestamp)
|
374
374
|
else
|
375
|
-
timestamp = nil
|
376
375
|
size = 0
|
377
376
|
end
|
378
377
|
end
|
@@ -407,9 +406,9 @@ module ActiveRecord
|
|
407
406
|
already_in_scope? ? yield : _scoping(self) { yield }
|
408
407
|
end
|
409
408
|
|
410
|
-
def _exec_scope(
|
409
|
+
def _exec_scope(*args, &block) # :nodoc:
|
411
410
|
@delegate_to_klass = true
|
412
|
-
_scoping(
|
411
|
+
_scoping(nil) { instance_exec(*args, &block) || self }
|
413
412
|
ensure
|
414
413
|
@delegate_to_klass = false
|
415
414
|
end
|
@@ -417,7 +416,7 @@ module ActiveRecord
|
|
417
416
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
418
417
|
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
|
419
418
|
# trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
|
420
|
-
# Active Record's normal type casting and serialization.
|
419
|
+
# Active Record's normal type casting and serialization. Returns the number of rows affected.
|
421
420
|
#
|
422
421
|
# Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
|
423
422
|
#
|
@@ -441,14 +440,12 @@ module ActiveRecord
|
|
441
440
|
def update_all(updates)
|
442
441
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
443
442
|
|
444
|
-
|
445
|
-
|
446
|
-
return relation.update_all(updates)
|
447
|
-
end
|
443
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
444
|
+
arel.source.left = table
|
448
445
|
|
449
446
|
stmt = Arel::UpdateManager.new
|
450
|
-
stmt.table(arel.
|
451
|
-
stmt.key =
|
447
|
+
stmt.table(arel.source)
|
448
|
+
stmt.key = table[primary_key]
|
452
449
|
stmt.take(arel.limit)
|
453
450
|
stmt.offset(arel.offset)
|
454
451
|
stmt.order(*arel.orders)
|
@@ -458,7 +455,7 @@ module ActiveRecord
|
|
458
455
|
if klass.locking_enabled? &&
|
459
456
|
!updates.key?(klass.locking_column) &&
|
460
457
|
!updates.key?(klass.locking_column.to_sym)
|
461
|
-
attr =
|
458
|
+
attr = table[klass.locking_column]
|
462
459
|
updates[attr.name] = _increment_attribute(attr)
|
463
460
|
end
|
464
461
|
stmt.set _substitute_values(updates)
|
@@ -466,7 +463,7 @@ module ActiveRecord
|
|
466
463
|
stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
467
464
|
end
|
468
465
|
|
469
|
-
|
466
|
+
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
470
467
|
end
|
471
468
|
|
472
469
|
def update(id = :all, attributes) # :nodoc:
|
@@ -477,12 +474,24 @@ module ActiveRecord
|
|
477
474
|
end
|
478
475
|
end
|
479
476
|
|
480
|
-
|
477
|
+
# Updates the counters of the records in the current relation.
|
478
|
+
#
|
479
|
+
# ==== Parameters
|
480
|
+
#
|
481
|
+
# * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
|
482
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
483
|
+
# * If attributes names are passed, they are updated along with update_at/on attributes.
|
484
|
+
#
|
485
|
+
# ==== Examples
|
486
|
+
#
|
487
|
+
# # For Posts by a given author increment the comment_count by 1.
|
488
|
+
# Post.where(author_id: author.id).update_counters(comment_count: 1)
|
489
|
+
def update_counters(counters)
|
481
490
|
touch = counters.delete(:touch)
|
482
491
|
|
483
492
|
updates = {}
|
484
493
|
counters.each do |counter_name, value|
|
485
|
-
attr =
|
494
|
+
attr = table[counter_name]
|
486
495
|
updates[attr.name] = _increment_attribute(attr, value)
|
487
496
|
end
|
488
497
|
|
@@ -571,23 +580,18 @@ module ActiveRecord
|
|
571
580
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
572
581
|
end
|
573
582
|
|
574
|
-
|
575
|
-
|
576
|
-
return relation.delete_all
|
577
|
-
end
|
583
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
584
|
+
arel.source.left = table
|
578
585
|
|
579
586
|
stmt = Arel::DeleteManager.new
|
580
|
-
stmt.from(arel.
|
581
|
-
stmt.key =
|
587
|
+
stmt.from(arel.source)
|
588
|
+
stmt.key = table[primary_key]
|
582
589
|
stmt.take(arel.limit)
|
583
590
|
stmt.offset(arel.offset)
|
584
591
|
stmt.order(*arel.orders)
|
585
592
|
stmt.wheres = arel.constraints
|
586
593
|
|
587
|
-
|
588
|
-
|
589
|
-
reset
|
590
|
-
affected
|
594
|
+
klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
|
591
595
|
end
|
592
596
|
|
593
597
|
# Finds and destroys all records matching the specified conditions.
|
@@ -623,7 +627,10 @@ module ActiveRecord
|
|
623
627
|
#
|
624
628
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
625
629
|
def load(&block)
|
626
|
-
|
630
|
+
unless loaded?
|
631
|
+
@records = exec_queries(&block)
|
632
|
+
@loaded = true
|
633
|
+
end
|
627
634
|
|
628
635
|
self
|
629
636
|
end
|
@@ -636,11 +643,10 @@ module ActiveRecord
|
|
636
643
|
|
637
644
|
def reset
|
638
645
|
@delegate_to_klass = false
|
639
|
-
@_deprecated_scope_source = nil
|
640
646
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
647
|
+
@offsets = @take = nil
|
648
|
+
@cache_keys = nil
|
641
649
|
@records = [].freeze
|
642
|
-
@offsets = {}
|
643
|
-
@take = nil
|
644
650
|
self
|
645
651
|
end
|
646
652
|
|
@@ -671,8 +677,7 @@ module ActiveRecord
|
|
671
677
|
end
|
672
678
|
|
673
679
|
def scope_for_create
|
674
|
-
hash =
|
675
|
-
hash.delete(klass.inheritance_column) if klass.finder_needs_type_condition?
|
680
|
+
hash = where_clause.to_h(klass.table_name, equality_only: true)
|
676
681
|
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
|
677
682
|
hash
|
678
683
|
end
|
@@ -718,7 +723,7 @@ module ActiveRecord
|
|
718
723
|
end
|
719
724
|
|
720
725
|
def inspect
|
721
|
-
subject = loaded? ? records :
|
726
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
722
727
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
723
728
|
|
724
729
|
entries[10] = "..." if entries.size == 11
|
@@ -735,25 +740,31 @@ module ActiveRecord
|
|
735
740
|
end
|
736
741
|
|
737
742
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
738
|
-
|
739
|
-
|
743
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
|
744
|
+
end
|
745
|
+
|
746
|
+
class StrictLoadingScope # :nodoc:
|
747
|
+
def self.empty_scope?
|
748
|
+
true
|
749
|
+
end
|
750
|
+
|
751
|
+
def self.strict_loading_value
|
752
|
+
true
|
753
|
+
end
|
740
754
|
end
|
741
755
|
|
742
756
|
def preload_associations(records) # :nodoc:
|
743
757
|
preload = preload_values
|
744
758
|
preload += includes_values unless eager_loading?
|
745
759
|
preloader = nil
|
760
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
746
761
|
preload.each do |associations|
|
747
762
|
preloader ||= build_preloader
|
748
|
-
preloader.preload records, associations
|
763
|
+
preloader.preload records, associations, scope
|
749
764
|
end
|
750
765
|
end
|
751
766
|
|
752
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
753
|
-
|
754
767
|
protected
|
755
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
756
|
-
|
757
768
|
def load_records(records)
|
758
769
|
@records = records.freeze
|
759
770
|
@loaded = true
|
@@ -765,23 +776,29 @@ module ActiveRecord
|
|
765
776
|
|
766
777
|
private
|
767
778
|
def already_in_scope?
|
768
|
-
@delegate_to_klass &&
|
769
|
-
scope = klass.current_scope(true)
|
770
|
-
scope && !scope._deprecated_scope_source
|
771
|
-
end
|
779
|
+
@delegate_to_klass && klass.current_scope(true)
|
772
780
|
end
|
773
781
|
|
774
|
-
def
|
775
|
-
|
776
|
-
end
|
777
|
-
|
778
|
-
def _deprecated_scope_block(name, &block)
|
782
|
+
def current_scope_restoring_block(&block)
|
783
|
+
current_scope = klass.current_scope(true)
|
779
784
|
-> record do
|
780
|
-
klass.current_scope =
|
785
|
+
klass.current_scope = current_scope
|
781
786
|
yield record if block_given?
|
782
787
|
end
|
783
788
|
end
|
784
789
|
|
790
|
+
def _new(attributes, &block)
|
791
|
+
klass.new(attributes, &block)
|
792
|
+
end
|
793
|
+
|
794
|
+
def _create(attributes, &block)
|
795
|
+
klass.create(attributes, &block)
|
796
|
+
end
|
797
|
+
|
798
|
+
def _create!(attributes, &block)
|
799
|
+
klass.create!(attributes, &block)
|
800
|
+
end
|
801
|
+
|
785
802
|
def _scoping(scope)
|
786
803
|
previous, klass.current_scope = klass.current_scope(true), scope
|
787
804
|
yield
|
@@ -791,7 +808,7 @@ module ActiveRecord
|
|
791
808
|
|
792
809
|
def _substitute_values(values)
|
793
810
|
values.map do |name, value|
|
794
|
-
attr =
|
811
|
+
attr = table[name]
|
795
812
|
unless Arel.arel_node?(value)
|
796
813
|
type = klass.type_for_attribute(attr.name)
|
797
814
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -809,27 +826,29 @@ module ActiveRecord
|
|
809
826
|
|
810
827
|
def exec_queries(&block)
|
811
828
|
skip_query_cache_if_necessary do
|
812
|
-
|
813
|
-
if
|
829
|
+
records =
|
830
|
+
if where_clause.contradiction?
|
831
|
+
[]
|
832
|
+
elsif eager_loading?
|
814
833
|
apply_join_dependency do |relation, join_dependency|
|
815
834
|
if relation.null_relation?
|
816
835
|
[]
|
817
836
|
else
|
818
837
|
relation = join_dependency.apply_column_aliases(relation)
|
819
838
|
rows = connection.select_all(relation.arel, "SQL")
|
820
|
-
join_dependency.instantiate(rows, &block)
|
839
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
821
840
|
end.freeze
|
822
841
|
end
|
823
842
|
else
|
824
843
|
klass.find_by_sql(arel, &block).freeze
|
825
844
|
end
|
826
845
|
|
827
|
-
preload_associations(
|
846
|
+
preload_associations(records) unless skip_preloading_value
|
828
847
|
|
829
|
-
|
848
|
+
records.each(&:readonly!) if readonly_value
|
849
|
+
records.each(&:strict_loading!) if strict_loading_value
|
830
850
|
|
831
|
-
|
832
|
-
@records
|
851
|
+
records
|
833
852
|
end
|
834
853
|
end
|
835
854
|
|
@@ -848,27 +867,27 @@ module ActiveRecord
|
|
848
867
|
end
|
849
868
|
|
850
869
|
def references_eager_loaded_tables?
|
851
|
-
joined_tables =
|
870
|
+
joined_tables = build_joins([]).flat_map do |join|
|
852
871
|
if join.is_a?(Arel::Nodes::StringJoin)
|
853
872
|
tables_in_string(join.left)
|
854
873
|
else
|
855
|
-
|
874
|
+
join.left.name
|
856
875
|
end
|
857
876
|
end
|
858
877
|
|
859
|
-
joined_tables
|
878
|
+
joined_tables << table.name
|
860
879
|
|
861
880
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
862
|
-
joined_tables
|
881
|
+
joined_tables.map!(&:downcase)
|
863
882
|
|
864
|
-
(references_values - joined_tables).
|
883
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
865
884
|
end
|
866
885
|
|
867
886
|
def tables_in_string(string)
|
868
887
|
return [] if string.blank?
|
869
888
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
870
889
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
871
|
-
string.scan(/
|
890
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
872
891
|
end
|
873
892
|
end
|
874
893
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -65,16 +65,10 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def to_hash
|
69
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
70
|
-
`ActiveRecord::Result#to_hash` has been renamed to `to_a`.
|
71
|
-
`to_hash` is deprecated and will be removed in Rails 6.1.
|
72
|
-
MSG
|
73
|
-
to_a
|
74
|
-
end
|
75
|
-
|
76
68
|
alias :map! :map
|
77
69
|
alias :collect! :map
|
70
|
+
deprecate "map!": :map
|
71
|
+
deprecate "collect!": :map
|
78
72
|
|
79
73
|
# Returns true if there are no records, otherwise false.
|
80
74
|
def empty?
|
@@ -92,31 +86,30 @@ module ActiveRecord
|
|
92
86
|
hash_rows[idx]
|
93
87
|
end
|
94
88
|
|
95
|
-
# Returns the first record from the rows collection.
|
96
|
-
# If the rows collection is empty, returns +nil+.
|
97
|
-
def first
|
98
|
-
return nil if @rows.empty?
|
99
|
-
Hash[@columns.zip(@rows.first)]
|
100
|
-
end
|
101
|
-
|
102
89
|
# Returns the last record from the rows collection.
|
103
|
-
|
104
|
-
|
105
|
-
return nil if @rows.empty?
|
106
|
-
Hash[@columns.zip(@rows.last)]
|
90
|
+
def last(n = nil)
|
91
|
+
n ? hash_rows.last(n) : hash_rows.last
|
107
92
|
end
|
108
93
|
|
109
94
|
def cast_values(type_overrides = {}) # :nodoc:
|
110
95
|
if columns.one?
|
111
96
|
# Separated to avoid allocating an array per row
|
112
97
|
|
113
|
-
type =
|
98
|
+
type = if type_overrides.is_a?(Array)
|
99
|
+
type_overrides.first
|
100
|
+
else
|
101
|
+
column_type(columns.first, type_overrides)
|
102
|
+
end
|
114
103
|
|
115
104
|
rows.map do |(value)|
|
116
105
|
type.deserialize(value)
|
117
106
|
end
|
118
107
|
else
|
119
|
-
types =
|
108
|
+
types = if type_overrides.is_a?(Array)
|
109
|
+
type_overrides
|
110
|
+
else
|
111
|
+
columns.map { |name| column_type(name, type_overrides) }
|
112
|
+
end
|
120
113
|
|
121
114
|
rows.map do |values|
|
122
115
|
Array.new(values.size) { |i| types[i].deserialize(values[i]) }
|
@@ -145,21 +138,36 @@ module ActiveRecord
|
|
145
138
|
# used as keys in ActiveRecord::Base's @attributes hash
|
146
139
|
columns = @columns.map(&:-@)
|
147
140
|
length = columns.length
|
141
|
+
template = nil
|
148
142
|
|
149
143
|
@rows.map { |row|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
144
|
+
if template
|
145
|
+
# We use transform_values to build subsequent rows from the
|
146
|
+
# hash of the first row. This is faster because we avoid any
|
147
|
+
# reallocs and in Ruby 2.7+ avoid hashing entirely.
|
148
|
+
index = -1
|
149
|
+
template.transform_values do
|
150
|
+
row[index += 1]
|
151
|
+
end
|
152
|
+
else
|
153
|
+
# In the past we used Hash[columns.zip(row)]
|
154
|
+
# though elegant, the verbose way is much more efficient
|
155
|
+
# both time and memory wise cause it avoids a big array allocation
|
156
|
+
# this method is called a lot and needs to be micro optimised
|
157
|
+
hash = {}
|
158
|
+
|
159
|
+
index = 0
|
160
|
+
while index < length
|
161
|
+
hash[columns[index]] = row[index]
|
162
|
+
index += 1
|
163
|
+
end
|
164
|
+
|
165
|
+
# It's possible to select the same column twice, in which case
|
166
|
+
# we can't use a template
|
167
|
+
template = hash if hash.length == length
|
168
|
+
|
169
|
+
hash
|
160
170
|
end
|
161
|
-
|
162
|
-
hash
|
163
171
|
}
|
164
172
|
end
|
165
173
|
end
|
@@ -14,9 +14,9 @@ module ActiveRecord
|
|
14
14
|
class RuntimeRegistry # :nodoc:
|
15
15
|
extend ActiveSupport::PerThreadRegistry
|
16
16
|
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :sql_runtime
|
18
18
|
|
19
|
-
[:
|
19
|
+
[:sql_runtime].each do |val|
|
20
20
|
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
21
21
|
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
22
22
|
end
|
@@ -67,7 +67,7 @@ module ActiveRecord
|
|
67
67
|
)
|
68
68
|
|
69
69
|
# Ensure we aren't dealing with a subclass of String that might
|
70
|
-
# override methods we use (
|
70
|
+
# override methods we use (e.g. Arel::Nodes::SqlLiteral).
|
71
71
|
if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
|
72
72
|
condition = [String.new(condition.first), *condition[1..-1]]
|
73
73
|
end
|
@@ -141,19 +141,7 @@ module ActiveRecord
|
|
141
141
|
(unexpected ||= []) << arg
|
142
142
|
end
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
if allow_unsafe_raw_sql == :deprecated
|
147
|
-
ActiveSupport::Deprecation.warn(
|
148
|
-
"Dangerous query method (method whose arguments are used as raw " \
|
149
|
-
"SQL) called with non-attribute argument(s): " \
|
150
|
-
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
151
|
-
"arguments will be disallowed in Rails 6.1. This method should " \
|
152
|
-
"not be called with user-provided values, such as request " \
|
153
|
-
"parameters or model attributes. Known-safe values can be passed " \
|
154
|
-
"by wrapping them in Arel.sql()."
|
155
|
-
)
|
156
|
-
else
|
144
|
+
if unexpected
|
157
145
|
raise(ActiveRecord::UnknownAttributeReference,
|
158
146
|
"Query method called with non-attribute argument(s): " +
|
159
147
|
unexpected.map(&:inspect).join(", ")
|
@@ -193,13 +181,14 @@ module ActiveRecord
|
|
193
181
|
|
194
182
|
def quote_bound_value(value, c = connection)
|
195
183
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
196
|
-
|
197
|
-
if
|
184
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
185
|
+
if values.empty?
|
198
186
|
c.quote(nil)
|
199
187
|
else
|
200
|
-
|
188
|
+
values.map! { |v| c.quote(v) }.join(",")
|
201
189
|
end
|
202
190
|
else
|
191
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
203
192
|
c.quote(value)
|
204
193
|
end
|
205
194
|
end
|
@@ -23,6 +23,12 @@ module ActiveRecord
|
|
23
23
|
# should not be dumped to db/schema.rb.
|
24
24
|
cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
|
25
25
|
|
26
|
+
##
|
27
|
+
# :singleton-method:
|
28
|
+
# Specify a custom regular expression matching check constraints which name
|
29
|
+
# should not be dumped to db/schema.rb.
|
30
|
+
cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
|
31
|
+
|
26
32
|
class << self
|
27
33
|
def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
|
28
34
|
connection.create_schema_dumper(generate_options(config)).dump(stream)
|
@@ -72,8 +78,8 @@ module ActiveRecord
|
|
72
78
|
# of editing this file, please use the migrations feature of Active Record to
|
73
79
|
# incrementally modify your database, and then regenerate this schema definition.
|
74
80
|
#
|
75
|
-
# This file is the source Rails uses to define your schema when running `rails
|
76
|
-
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
81
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
82
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
77
83
|
# be faster and is potentially less error prone than running all of your
|
78
84
|
# migrations from scratch. Old migrations may fail to apply correctly if those
|
79
85
|
# migrations use external dependencies or application code.
|
@@ -125,7 +131,10 @@ HEADER
|
|
125
131
|
tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
|
126
132
|
pkcol = columns.detect { |c| c.name == pk }
|
127
133
|
pkcolspec = column_spec_for_primary_key(pkcol)
|
128
|
-
|
134
|
+
unless pkcolspec.empty?
|
135
|
+
if pkcolspec != pkcolspec.slice(:id, :default)
|
136
|
+
pkcolspec = { id: { type: pkcolspec.delete(:id), **pkcolspec }.compact }
|
137
|
+
end
|
129
138
|
tbl.print ", #{format_colspec(pkcolspec)}"
|
130
139
|
end
|
131
140
|
when Array
|
@@ -156,6 +165,7 @@ HEADER
|
|
156
165
|
end
|
157
166
|
|
158
167
|
indexes_in_create(table, tbl)
|
168
|
+
check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
|
159
169
|
|
160
170
|
tbl.puts " end"
|
161
171
|
tbl.puts
|
@@ -209,6 +219,24 @@ HEADER
|
|
209
219
|
index_parts
|
210
220
|
end
|
211
221
|
|
222
|
+
def check_constraints_in_create(table, stream)
|
223
|
+
if (check_constraints = @connection.check_constraints(table)).any?
|
224
|
+
add_check_constraint_statements = check_constraints.map do |check_constraint|
|
225
|
+
parts = [
|
226
|
+
"t.check_constraint #{check_constraint.expression.inspect}"
|
227
|
+
]
|
228
|
+
|
229
|
+
if check_constraint.export_name_on_schema_dump?
|
230
|
+
parts << "name: #{check_constraint.name.inspect}"
|
231
|
+
end
|
232
|
+
|
233
|
+
" #{parts.join(', ')}"
|
234
|
+
end
|
235
|
+
|
236
|
+
stream.puts add_check_constraint_statements.sort.join("\n")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
212
240
|
def foreign_keys(table, stream)
|
213
241
|
if (foreign_keys = @connection.foreign_keys(table)).any?
|
214
242
|
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
@@ -240,7 +268,9 @@ HEADER
|
|
240
268
|
end
|
241
269
|
|
242
270
|
def format_colspec(colspec)
|
243
|
-
colspec.map
|
271
|
+
colspec.map do |key, value|
|
272
|
+
"#{key}: #{ value.is_a?(Hash) ? "{ #{format_colspec(value)} }" : value }"
|
273
|
+
end.join(", ")
|
244
274
|
end
|
245
275
|
|
246
276
|
def format_options(options)
|