activerecord 6.0.6 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- 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 +19 -13
- 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 +29 -14
- 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 +13 -5
- 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 +114 -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 +32 -7
- 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 +2 -24
- 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 +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- 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 +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- 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 +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- 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 +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- 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 +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -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/money.rb +2 -2
- 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 +4 -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 +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -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 +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -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 +124 -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 +27 -10
- 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 +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -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 +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- 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 +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- 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 +100 -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 +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- 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 +104 -57
- data/lib/active_record/relation.rb +90 -64
- 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/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 +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -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 +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- 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 +72 -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 +28 -30
- 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
|
#
|
@@ -448,7 +447,7 @@ module ActiveRecord
|
|
448
447
|
|
449
448
|
stmt = Arel::UpdateManager.new
|
450
449
|
stmt.table(arel.join_sources.empty? ? table : arel.source)
|
451
|
-
stmt.key =
|
450
|
+
stmt.key = table[primary_key]
|
452
451
|
stmt.take(arel.limit)
|
453
452
|
stmt.offset(arel.offset)
|
454
453
|
stmt.order(*arel.orders)
|
@@ -458,7 +457,7 @@ module ActiveRecord
|
|
458
457
|
if klass.locking_enabled? &&
|
459
458
|
!updates.key?(klass.locking_column) &&
|
460
459
|
!updates.key?(klass.locking_column.to_sym)
|
461
|
-
attr =
|
460
|
+
attr = table[klass.locking_column]
|
462
461
|
updates[attr.name] = _increment_attribute(attr)
|
463
462
|
end
|
464
463
|
stmt.set _substitute_values(updates)
|
@@ -477,12 +476,24 @@ module ActiveRecord
|
|
477
476
|
end
|
478
477
|
end
|
479
478
|
|
480
|
-
|
479
|
+
# Updates the counters of the records in the current relation.
|
480
|
+
#
|
481
|
+
# ==== Parameters
|
482
|
+
#
|
483
|
+
# * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
|
484
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
485
|
+
# * If attributes names are passed, they are updated along with update_at/on attributes.
|
486
|
+
#
|
487
|
+
# ==== Examples
|
488
|
+
#
|
489
|
+
# # For Posts by a given author increment the comment_count by 1.
|
490
|
+
# Post.where(author_id: author.id).update_counters(comment_count: 1)
|
491
|
+
def update_counters(counters)
|
481
492
|
touch = counters.delete(:touch)
|
482
493
|
|
483
494
|
updates = {}
|
484
495
|
counters.each do |counter_name, value|
|
485
|
-
attr =
|
496
|
+
attr = table[counter_name]
|
486
497
|
updates[attr.name] = _increment_attribute(attr, value)
|
487
498
|
end
|
488
499
|
|
@@ -578,7 +589,7 @@ module ActiveRecord
|
|
578
589
|
|
579
590
|
stmt = Arel::DeleteManager.new
|
580
591
|
stmt.from(arel.join_sources.empty? ? table : arel.source)
|
581
|
-
stmt.key =
|
592
|
+
stmt.key = table[primary_key]
|
582
593
|
stmt.take(arel.limit)
|
583
594
|
stmt.offset(arel.offset)
|
584
595
|
stmt.order(*arel.orders)
|
@@ -623,7 +634,10 @@ module ActiveRecord
|
|
623
634
|
#
|
624
635
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
625
636
|
def load(&block)
|
626
|
-
|
637
|
+
unless loaded?
|
638
|
+
@records = exec_queries(&block)
|
639
|
+
@loaded = true
|
640
|
+
end
|
627
641
|
|
628
642
|
self
|
629
643
|
end
|
@@ -636,11 +650,9 @@ module ActiveRecord
|
|
636
650
|
|
637
651
|
def reset
|
638
652
|
@delegate_to_klass = false
|
639
|
-
@_deprecated_scope_source = nil
|
640
653
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
654
|
+
@offsets = @take = nil
|
641
655
|
@records = [].freeze
|
642
|
-
@offsets = {}
|
643
|
-
@take = nil
|
644
656
|
self
|
645
657
|
end
|
646
658
|
|
@@ -718,7 +730,7 @@ module ActiveRecord
|
|
718
730
|
end
|
719
731
|
|
720
732
|
def inspect
|
721
|
-
subject = loaded? ? records :
|
733
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
722
734
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
723
735
|
|
724
736
|
entries[10] = "..." if entries.size == 11
|
@@ -735,25 +747,31 @@ module ActiveRecord
|
|
735
747
|
end
|
736
748
|
|
737
749
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
738
|
-
|
739
|
-
|
750
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
|
751
|
+
end
|
752
|
+
|
753
|
+
class StrictLoadingScope # :nodoc:
|
754
|
+
def self.empty_scope?
|
755
|
+
true
|
756
|
+
end
|
757
|
+
|
758
|
+
def self.strict_loading_value
|
759
|
+
true
|
760
|
+
end
|
740
761
|
end
|
741
762
|
|
742
763
|
def preload_associations(records) # :nodoc:
|
743
764
|
preload = preload_values
|
744
765
|
preload += includes_values unless eager_loading?
|
745
766
|
preloader = nil
|
767
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
746
768
|
preload.each do |associations|
|
747
769
|
preloader ||= build_preloader
|
748
|
-
preloader.preload records, associations
|
770
|
+
preloader.preload records, associations, scope
|
749
771
|
end
|
750
772
|
end
|
751
773
|
|
752
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
753
|
-
|
754
774
|
protected
|
755
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
756
|
-
|
757
775
|
def load_records(records)
|
758
776
|
@records = records.freeze
|
759
777
|
@loaded = true
|
@@ -765,23 +783,29 @@ module ActiveRecord
|
|
765
783
|
|
766
784
|
private
|
767
785
|
def already_in_scope?
|
768
|
-
@delegate_to_klass &&
|
769
|
-
scope = klass.current_scope(true)
|
770
|
-
scope && !scope._deprecated_scope_source
|
771
|
-
end
|
772
|
-
end
|
773
|
-
|
774
|
-
def _deprecated_spawn(name)
|
775
|
-
spawn.tap { |scope| scope._deprecated_scope_source = name }
|
786
|
+
@delegate_to_klass && klass.current_scope(true)
|
776
787
|
end
|
777
788
|
|
778
|
-
def
|
789
|
+
def current_scope_restoring_block(&block)
|
790
|
+
current_scope = klass.current_scope(true)
|
779
791
|
-> record do
|
780
|
-
klass.current_scope =
|
792
|
+
klass.current_scope = current_scope
|
781
793
|
yield record if block_given?
|
782
794
|
end
|
783
795
|
end
|
784
796
|
|
797
|
+
def _new(attributes, &block)
|
798
|
+
klass.new(attributes, &block)
|
799
|
+
end
|
800
|
+
|
801
|
+
def _create(attributes, &block)
|
802
|
+
klass.create(attributes, &block)
|
803
|
+
end
|
804
|
+
|
805
|
+
def _create!(attributes, &block)
|
806
|
+
klass.create!(attributes, &block)
|
807
|
+
end
|
808
|
+
|
785
809
|
def _scoping(scope)
|
786
810
|
previous, klass.current_scope = klass.current_scope(true), scope
|
787
811
|
yield
|
@@ -791,7 +815,7 @@ module ActiveRecord
|
|
791
815
|
|
792
816
|
def _substitute_values(values)
|
793
817
|
values.map do |name, value|
|
794
|
-
attr =
|
818
|
+
attr = table[name]
|
795
819
|
unless Arel.arel_node?(value)
|
796
820
|
type = klass.type_for_attribute(attr.name)
|
797
821
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -809,27 +833,29 @@ module ActiveRecord
|
|
809
833
|
|
810
834
|
def exec_queries(&block)
|
811
835
|
skip_query_cache_if_necessary do
|
812
|
-
|
813
|
-
if
|
836
|
+
records =
|
837
|
+
if where_clause.contradiction?
|
838
|
+
[]
|
839
|
+
elsif eager_loading?
|
814
840
|
apply_join_dependency do |relation, join_dependency|
|
815
841
|
if relation.null_relation?
|
816
842
|
[]
|
817
843
|
else
|
818
844
|
relation = join_dependency.apply_column_aliases(relation)
|
819
845
|
rows = connection.select_all(relation.arel, "SQL")
|
820
|
-
join_dependency.instantiate(rows, &block)
|
846
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
821
847
|
end.freeze
|
822
848
|
end
|
823
849
|
else
|
824
850
|
klass.find_by_sql(arel, &block).freeze
|
825
851
|
end
|
826
852
|
|
827
|
-
preload_associations(
|
853
|
+
preload_associations(records) unless skip_preloading_value
|
828
854
|
|
829
|
-
|
855
|
+
records.each(&:readonly!) if readonly_value
|
856
|
+
records.each(&:strict_loading!) if strict_loading_value
|
830
857
|
|
831
|
-
|
832
|
-
@records
|
858
|
+
records
|
833
859
|
end
|
834
860
|
end
|
835
861
|
|
@@ -848,27 +874,27 @@ module ActiveRecord
|
|
848
874
|
end
|
849
875
|
|
850
876
|
def references_eager_loaded_tables?
|
851
|
-
joined_tables =
|
877
|
+
joined_tables = build_joins([]).flat_map do |join|
|
852
878
|
if join.is_a?(Arel::Nodes::StringJoin)
|
853
879
|
tables_in_string(join.left)
|
854
880
|
else
|
855
|
-
|
881
|
+
join.left.name
|
856
882
|
end
|
857
883
|
end
|
858
884
|
|
859
|
-
joined_tables
|
885
|
+
joined_tables << table.name
|
860
886
|
|
861
887
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
862
|
-
joined_tables
|
888
|
+
joined_tables.map!(&:downcase)
|
863
889
|
|
864
|
-
(references_values - joined_tables).
|
890
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
865
891
|
end
|
866
892
|
|
867
893
|
def tables_in_string(string)
|
868
894
|
return [] if string.blank?
|
869
895
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
870
896
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
871
|
-
string.scan(/
|
897
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
872
898
|
end
|
873
899
|
end
|
874
900
|
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)
|
@@ -22,16 +22,10 @@ module ActiveRecord
|
|
22
22
|
"#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
|
23
23
|
end
|
24
24
|
|
25
|
-
def table_exists?
|
26
|
-
connection.table_exists?(table_name)
|
27
|
-
end
|
28
|
-
|
29
25
|
def create_table
|
30
|
-
unless table_exists?
|
31
|
-
version_options = connection.internal_string_options_for_primary_key
|
32
|
-
|
26
|
+
unless connection.table_exists?(table_name)
|
33
27
|
connection.create_table(table_name, id: false) do |t|
|
34
|
-
t.string :version, **
|
28
|
+
t.string :version, **connection.internal_string_options_for_primary_key
|
35
29
|
end
|
36
30
|
end
|
37
31
|
end
|