activerecord 5.1.7 → 5.2.0.beta1
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 +5 -5
- data/CHANGELOG.md +221 -900
- data/README.rdoc +3 -3
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record.rb +10 -3
- data/lib/active_record/aggregations.rb +2 -0
- data/lib/active_record/association_relation.rb +2 -0
- data/lib/active_record/associations.rb +13 -42
- data/lib/active_record/associations/alias_tracker.rb +17 -17
- data/lib/active_record/associations/association.rb +11 -22
- data/lib/active_record/associations/association_scope.rb +32 -44
- data/lib/active_record/associations/belongs_to_association.rb +6 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
- data/lib/active_record/associations/builder/association.rb +2 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -12
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +41 -33
- data/lib/active_record/associations/collection_proxy.rb +11 -14
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +4 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -2
- data/lib/active_record/associations/has_one_association.rb +3 -1
- data/lib/active_record/associations/has_one_through_association.rb +3 -1
- data/lib/active_record/associations/join_dependency.rb +22 -40
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +42 -58
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +3 -1
- data/lib/active_record/attribute_assignment.rb +2 -0
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +47 -7
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +25 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +8 -2
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +5 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +6 -8
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +120 -28
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -2
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +103 -63
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -6
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +47 -82
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +19 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -89
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +27 -57
- data/lib/active_record/counter_cache.rb +15 -12
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +15 -13
- data/lib/active_record/errors.rb +54 -21
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +40 -24
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +6 -5
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +31 -20
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +2 -0
- data/lib/active_record/migration.rb +47 -21
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +20 -2
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +29 -38
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +184 -40
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +54 -1
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +41 -28
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +100 -182
- data/lib/active_record/relation.rb +61 -193
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +40 -23
- data/lib/active_record/relation/delegation.rb +10 -27
- data/lib/active_record/relation/finder_methods.rb +53 -49
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +22 -19
- data/lib/active_record/relation/predicate_builder.rb +42 -79
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +80 -69
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -0
- data/lib/active_record/relation/where_clause.rb +50 -67
- data/lib/active_record/relation/where_clause_factory.rb +4 -46
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +15 -9
- data/lib/active_record/schema.rb +3 -1
- data/lib/active_record/schema_dumper.rb +24 -23
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +15 -7
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +2 -0
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +3 -1
- data/lib/active_record/tasks/database_tasks.rb +23 -12
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +5 -12
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +9 -7
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -4
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +2 -0
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +25 -38
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -126
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record \Relation
|
3
5
|
class Relation
|
4
6
|
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
5
|
-
:order, :joins, :
|
7
|
+
:order, :joins, :left_outer_joins, :references,
|
6
8
|
:extending, :unscope]
|
7
9
|
|
8
10
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
9
|
-
:reverse_order, :distinct, :create_with]
|
11
|
+
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
10
12
|
CLAUSE_METHODS = [:where, :having, :from]
|
11
13
|
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
|
12
14
|
|
@@ -18,6 +20,7 @@ module ActiveRecord
|
|
18
20
|
attr_reader :table, :klass, :loaded, :predicate_builder
|
19
21
|
alias :model :klass
|
20
22
|
alias :loaded? :loaded
|
23
|
+
alias :locked? :lock_value
|
21
24
|
|
22
25
|
def initialize(klass, table, predicate_builder, values = {})
|
23
26
|
@klass = klass
|
@@ -33,74 +36,6 @@ module ActiveRecord
|
|
33
36
|
reset
|
34
37
|
end
|
35
38
|
|
36
|
-
def insert(values) # :nodoc:
|
37
|
-
primary_key_value = nil
|
38
|
-
|
39
|
-
if primary_key && Hash === values
|
40
|
-
primary_key_value = values[values.keys.find { |k|
|
41
|
-
k.name == primary_key
|
42
|
-
}]
|
43
|
-
|
44
|
-
if !primary_key_value && klass.prefetch_primary_key?
|
45
|
-
primary_key_value = klass.next_sequence_value
|
46
|
-
values[arel_attribute(klass.primary_key)] = primary_key_value
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
im = arel.create_insert
|
51
|
-
im.into @table
|
52
|
-
|
53
|
-
substitutes, binds = substitute_values values
|
54
|
-
|
55
|
-
if values.empty? # empty insert
|
56
|
-
im.values = Arel.sql(connection.empty_insert_statement_value)
|
57
|
-
else
|
58
|
-
im.insert substitutes
|
59
|
-
end
|
60
|
-
|
61
|
-
@klass.connection.insert(
|
62
|
-
im,
|
63
|
-
"SQL",
|
64
|
-
primary_key || false,
|
65
|
-
primary_key_value,
|
66
|
-
nil,
|
67
|
-
binds)
|
68
|
-
end
|
69
|
-
|
70
|
-
def _update_record(values, constraints) # :nodoc:
|
71
|
-
substitutes, binds = substitute_values values
|
72
|
-
|
73
|
-
scope = @klass.unscoped
|
74
|
-
|
75
|
-
if @klass.finder_needs_type_condition?
|
76
|
-
scope.unscope!(where: @klass.inheritance_column)
|
77
|
-
end
|
78
|
-
|
79
|
-
relation = scope.where(constraints)
|
80
|
-
bvs = binds + relation.bound_attributes
|
81
|
-
um = relation
|
82
|
-
.arel
|
83
|
-
.compile_update(substitutes, @klass.primary_key)
|
84
|
-
|
85
|
-
@klass.connection.update(
|
86
|
-
um,
|
87
|
-
"SQL",
|
88
|
-
bvs,
|
89
|
-
)
|
90
|
-
end
|
91
|
-
|
92
|
-
def substitute_values(values) # :nodoc:
|
93
|
-
binds = []
|
94
|
-
substitutes = []
|
95
|
-
|
96
|
-
values.each do |arel_attr, value|
|
97
|
-
binds.push QueryAttribute.new(arel_attr.name, value, klass.type_for_attribute(arel_attr.name))
|
98
|
-
substitutes.push [arel_attr, Arel::Nodes::BindParam.new]
|
99
|
-
end
|
100
|
-
|
101
|
-
[substitutes, binds]
|
102
|
-
end
|
103
|
-
|
104
39
|
def arel_attribute(name) # :nodoc:
|
105
40
|
klass.arel_attribute(name, table)
|
106
41
|
end
|
@@ -247,9 +182,10 @@ module ActiveRecord
|
|
247
182
|
end
|
248
183
|
|
249
184
|
# Converts relation objects to Array.
|
250
|
-
def
|
185
|
+
def to_ary
|
251
186
|
records.dup
|
252
187
|
end
|
188
|
+
alias to_a to_ary
|
253
189
|
|
254
190
|
def records # :nodoc:
|
255
191
|
load
|
@@ -363,6 +299,11 @@ module ActiveRecord
|
|
363
299
|
def update_all(updates)
|
364
300
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
365
301
|
|
302
|
+
if eager_loading?
|
303
|
+
relation = apply_join_dependency
|
304
|
+
return relation.update_all(updates)
|
305
|
+
end
|
306
|
+
|
366
307
|
stmt = Arel::UpdateManager.new
|
367
308
|
|
368
309
|
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
|
@@ -377,51 +318,7 @@ module ActiveRecord
|
|
377
318
|
stmt.wheres = arel.constraints
|
378
319
|
end
|
379
320
|
|
380
|
-
@klass.connection.update stmt, "
|
381
|
-
end
|
382
|
-
|
383
|
-
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
|
384
|
-
# The resulting object is returned whether the object was saved successfully to the database or not.
|
385
|
-
#
|
386
|
-
# ==== Parameters
|
387
|
-
#
|
388
|
-
# * +id+ - This should be the id or an array of ids to be updated.
|
389
|
-
# * +attributes+ - This should be a hash of attributes or an array of hashes.
|
390
|
-
#
|
391
|
-
# ==== Examples
|
392
|
-
#
|
393
|
-
# # Updates one record
|
394
|
-
# Person.update(15, user_name: 'Samuel', group: 'expert')
|
395
|
-
#
|
396
|
-
# # Updates multiple records
|
397
|
-
# people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
|
398
|
-
# Person.update(people.keys, people.values)
|
399
|
-
#
|
400
|
-
# # Updates multiple records from the result of a relation
|
401
|
-
# people = Person.where(group: 'expert')
|
402
|
-
# people.update(group: 'masters')
|
403
|
-
#
|
404
|
-
# Note: Updating a large number of records will run an
|
405
|
-
# UPDATE query for each record, which may cause a performance
|
406
|
-
# issue. So if it is not needed to run callbacks for each update, it is
|
407
|
-
# preferred to use #update_all for updating all records using
|
408
|
-
# a single query.
|
409
|
-
def update(id = :all, attributes)
|
410
|
-
if id.is_a?(Array)
|
411
|
-
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
|
412
|
-
elsif id == :all
|
413
|
-
records.each { |record| record.update(attributes) }
|
414
|
-
else
|
415
|
-
if ActiveRecord::Base === id
|
416
|
-
raise ArgumentError, <<-MSG.squish
|
417
|
-
You are passing an instance of ActiveRecord::Base to `update`.
|
418
|
-
Please pass the id of the object by calling `.id`.
|
419
|
-
MSG
|
420
|
-
end
|
421
|
-
object = find(id)
|
422
|
-
object.update(attributes)
|
423
|
-
object
|
424
|
-
end
|
321
|
+
@klass.connection.update stmt, "#{@klass} Update All"
|
425
322
|
end
|
426
323
|
|
427
324
|
# Destroys the records by instantiating each
|
@@ -444,33 +341,6 @@ module ActiveRecord
|
|
444
341
|
records.each(&:destroy).tap { reset }
|
445
342
|
end
|
446
343
|
|
447
|
-
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
448
|
-
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
449
|
-
# less efficient than #delete but allows cleanup methods and other actions to be run.
|
450
|
-
#
|
451
|
-
# This essentially finds the object (or multiple objects) with the given id, creates a new object
|
452
|
-
# from the attributes, and then calls destroy on it.
|
453
|
-
#
|
454
|
-
# ==== Parameters
|
455
|
-
#
|
456
|
-
# * +id+ - Can be either an Integer or an Array of Integers.
|
457
|
-
#
|
458
|
-
# ==== Examples
|
459
|
-
#
|
460
|
-
# # Destroy a single object
|
461
|
-
# Todo.destroy(1)
|
462
|
-
#
|
463
|
-
# # Destroy multiple objects
|
464
|
-
# todos = [1,2,3]
|
465
|
-
# Todo.destroy(todos)
|
466
|
-
def destroy(id)
|
467
|
-
if id.is_a?(Array)
|
468
|
-
id.map { |one_id| destroy(one_id) }
|
469
|
-
else
|
470
|
-
find(id).destroy
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
344
|
# Deletes the records without instantiating the records
|
475
345
|
# first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
|
476
346
|
# method nor invoking callbacks.
|
@@ -498,6 +368,11 @@ module ActiveRecord
|
|
498
368
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
499
369
|
end
|
500
370
|
|
371
|
+
if eager_loading?
|
372
|
+
relation = apply_join_dependency
|
373
|
+
return relation.delete_all
|
374
|
+
end
|
375
|
+
|
501
376
|
stmt = Arel::DeleteManager.new
|
502
377
|
stmt.from(table)
|
503
378
|
|
@@ -507,35 +382,12 @@ module ActiveRecord
|
|
507
382
|
stmt.wheres = arel.constraints
|
508
383
|
end
|
509
384
|
|
510
|
-
affected = @klass.connection.delete(stmt, "
|
385
|
+
affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
|
511
386
|
|
512
387
|
reset
|
513
388
|
affected
|
514
389
|
end
|
515
390
|
|
516
|
-
# Deletes the row with a primary key matching the +id+ argument, using a
|
517
|
-
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
|
518
|
-
# Record objects are not instantiated, so the object's callbacks are not
|
519
|
-
# executed, including any <tt>:dependent</tt> association options.
|
520
|
-
#
|
521
|
-
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
|
522
|
-
#
|
523
|
-
# Note: Although it is often much faster than the alternative,
|
524
|
-
# #destroy, skipping callbacks might bypass business logic in
|
525
|
-
# your application that ensures referential integrity or performs other
|
526
|
-
# essential jobs.
|
527
|
-
#
|
528
|
-
# ==== Examples
|
529
|
-
#
|
530
|
-
# # Delete a single row
|
531
|
-
# Todo.delete(1)
|
532
|
-
#
|
533
|
-
# # Delete multiple rows
|
534
|
-
# Todo.delete([2,3,4])
|
535
|
-
def delete(id_or_array)
|
536
|
-
where(primary_key => id_or_array).delete_all
|
537
|
-
end
|
538
|
-
|
539
391
|
# Causes the records to be loaded from the database if they have not
|
540
392
|
# been loaded already. You can use this if for some reason you need
|
541
393
|
# to explicitly load some records before actually using them. The
|
@@ -555,8 +407,7 @@ module ActiveRecord
|
|
555
407
|
end
|
556
408
|
|
557
409
|
def reset
|
558
|
-
@
|
559
|
-
@should_eager_load = @join_dependency = nil
|
410
|
+
@to_sql = @arel = @loaded = @should_eager_load = nil
|
560
411
|
@records = [].freeze
|
561
412
|
@offsets = {}
|
562
413
|
self
|
@@ -576,7 +427,7 @@ module ActiveRecord
|
|
576
427
|
|
577
428
|
conn = klass.connection
|
578
429
|
conn.unprepared_statement {
|
579
|
-
conn.to_sql(relation.arel
|
430
|
+
conn.to_sql(relation.arel)
|
580
431
|
}
|
581
432
|
end
|
582
433
|
end
|
@@ -585,12 +436,12 @@ module ActiveRecord
|
|
585
436
|
#
|
586
437
|
# User.where(name: 'Oscar').where_values_hash
|
587
438
|
# # => {name: "Oscar"}
|
588
|
-
def where_values_hash(relation_table_name = table_name)
|
439
|
+
def where_values_hash(relation_table_name = klass.table_name)
|
589
440
|
where_clause.to_h(relation_table_name)
|
590
441
|
end
|
591
442
|
|
592
443
|
def scope_for_create
|
593
|
-
|
444
|
+
where_values_hash.merge!(create_with_value.stringify_keys)
|
594
445
|
end
|
595
446
|
|
596
447
|
# Returns true if relation needs eager loading.
|
@@ -650,6 +501,11 @@ module ActiveRecord
|
|
650
501
|
limit_value || offset_value
|
651
502
|
end
|
652
503
|
|
504
|
+
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
505
|
+
joins += [aliases] if aliases
|
506
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
|
507
|
+
end
|
508
|
+
|
653
509
|
protected
|
654
510
|
|
655
511
|
def load_records(records)
|
@@ -664,32 +520,44 @@ module ActiveRecord
|
|
664
520
|
end
|
665
521
|
|
666
522
|
def exec_queries(&block)
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
523
|
+
skip_query_cache_if_necessary do
|
524
|
+
@records =
|
525
|
+
if eager_loading?
|
526
|
+
find_with_associations do |relation, join_dependency|
|
527
|
+
if ActiveRecord::NullRelation === relation
|
528
|
+
[]
|
529
|
+
else
|
530
|
+
rows = connection.select_all(relation.arel, "SQL")
|
531
|
+
join_dependency.instantiate(rows, &block)
|
532
|
+
end.freeze
|
533
|
+
end
|
534
|
+
else
|
535
|
+
klass.find_by_sql(arel, &block).freeze
|
676
536
|
end
|
677
|
-
|
678
|
-
|
537
|
+
|
538
|
+
preload = preload_values
|
539
|
+
preload += includes_values unless eager_loading?
|
540
|
+
preloader = nil
|
541
|
+
preload.each do |associations|
|
542
|
+
preloader ||= build_preloader
|
543
|
+
preloader.preload @records, associations
|
679
544
|
end
|
680
545
|
|
681
|
-
|
682
|
-
preload += includes_values unless eager_loading?
|
683
|
-
preloader = nil
|
684
|
-
preload.each do |associations|
|
685
|
-
preloader ||= build_preloader
|
686
|
-
preloader.preload @records, associations
|
687
|
-
end
|
546
|
+
@records.each(&:readonly!) if readonly_value
|
688
547
|
|
689
|
-
|
548
|
+
@loaded = true
|
549
|
+
@records
|
550
|
+
end
|
551
|
+
end
|
690
552
|
|
691
|
-
|
692
|
-
|
553
|
+
def skip_query_cache_if_necessary
|
554
|
+
if skip_query_cache_value
|
555
|
+
uncached do
|
556
|
+
yield
|
557
|
+
end
|
558
|
+
else
|
559
|
+
yield
|
560
|
+
end
|
693
561
|
end
|
694
562
|
|
695
563
|
def build_preloader
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/relation/batches/batch_enumerator"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -45,7 +47,12 @@ module ActiveRecord
|
|
45
47
|
# handle from 10000 and beyond by setting the +:start+ and +:finish+
|
46
48
|
# option on each worker.
|
47
49
|
#
|
48
|
-
# #
|
50
|
+
# # In worker 1, let's process until 9999 records.
|
51
|
+
# Person.find_each(finish: 9_999) do |person|
|
52
|
+
# person.party_all_night!
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# # In worker 2, let's process from record 10_000 and onwards.
|
49
56
|
# Person.find_each(start: 10_000) do |person|
|
50
57
|
# person.party_all_night!
|
51
58
|
# end
|
@@ -209,6 +216,7 @@ module ActiveRecord
|
|
209
216
|
|
210
217
|
relation = relation.reorder(batch_order).limit(batch_limit)
|
211
218
|
relation = apply_limits(relation, start, finish)
|
219
|
+
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
212
220
|
batch_relation = relation
|
213
221
|
|
214
222
|
loop do
|
@@ -243,20 +251,27 @@ module ActiveRecord
|
|
243
251
|
end
|
244
252
|
end
|
245
253
|
|
246
|
-
|
254
|
+
attr = Relation::QueryAttribute.new(primary_key, primary_key_offset, klass.type_for_attribute(primary_key))
|
255
|
+
batch_relation = relation.where(arel_attribute(primary_key).gt(Arel::Nodes::BindParam.new(attr)))
|
247
256
|
end
|
248
257
|
end
|
249
258
|
|
250
259
|
private
|
251
260
|
|
252
261
|
def apply_limits(relation, start, finish)
|
253
|
-
|
254
|
-
|
262
|
+
if start
|
263
|
+
attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
|
264
|
+
relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
|
265
|
+
end
|
266
|
+
if finish
|
267
|
+
attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
|
268
|
+
relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
|
269
|
+
end
|
255
270
|
relation
|
256
271
|
end
|
257
272
|
|
258
273
|
def batch_order
|
259
|
-
|
274
|
+
arel_attribute(primary_key).asc
|
260
275
|
end
|
261
276
|
|
262
277
|
def act_on_ignored_order(error_on_ignore)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Calculations
|
3
5
|
# Count the records.
|
@@ -37,7 +39,16 @@ module ActiveRecord
|
|
37
39
|
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
38
40
|
# between databases. In invalid cases, an error from the database is thrown.
|
39
41
|
def count(column_name = nil)
|
40
|
-
|
42
|
+
if block_given?
|
43
|
+
unless column_name.nil?
|
44
|
+
ActiveSupport::Deprecation.warn \
|
45
|
+
"When `count' is called with a block, it ignores other arguments. " \
|
46
|
+
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
47
|
+
end
|
48
|
+
|
49
|
+
return super()
|
50
|
+
end
|
51
|
+
|
41
52
|
calculate(:count, column_name)
|
42
53
|
end
|
43
54
|
|
@@ -73,7 +84,16 @@ module ActiveRecord
|
|
73
84
|
#
|
74
85
|
# Person.sum(:age) # => 4562
|
75
86
|
def sum(column_name = nil)
|
76
|
-
|
87
|
+
if block_given?
|
88
|
+
unless column_name.nil?
|
89
|
+
ActiveSupport::Deprecation.warn \
|
90
|
+
"When `sum' is called with a block, it ignores other arguments. " \
|
91
|
+
"This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
|
92
|
+
end
|
93
|
+
|
94
|
+
return super()
|
95
|
+
end
|
96
|
+
|
77
97
|
calculate(:sum, column_name)
|
78
98
|
end
|
79
99
|
|
@@ -110,15 +130,8 @@ module ActiveRecord
|
|
110
130
|
# end
|
111
131
|
def calculate(operation, column_name)
|
112
132
|
if has_include?(column_name)
|
113
|
-
relation =
|
114
|
-
|
115
|
-
if operation.to_s.downcase == "count"
|
116
|
-
relation.distinct!
|
117
|
-
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
118
|
-
if (column_name == :all || column_name.nil?) && select_values.empty?
|
119
|
-
relation.order_values = []
|
120
|
-
end
|
121
|
-
end
|
133
|
+
relation = apply_join_dependency
|
134
|
+
relation.distinct! if operation.to_s.downcase == "count"
|
122
135
|
|
123
136
|
relation.calculate(operation, column_name)
|
124
137
|
else
|
@@ -167,13 +180,15 @@ module ActiveRecord
|
|
167
180
|
end
|
168
181
|
|
169
182
|
if has_include?(column_names.first)
|
170
|
-
|
183
|
+
relation = apply_join_dependency
|
184
|
+
relation.pluck(*column_names)
|
171
185
|
else
|
186
|
+
enforce_raw_sql_whitelist(column_names)
|
172
187
|
relation = spawn
|
173
188
|
relation.select_values = column_names.map { |cn|
|
174
189
|
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
175
190
|
}
|
176
|
-
result = klass.connection.select_all(relation.arel, nil
|
191
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
177
192
|
result.cast_values(klass.attribute_types)
|
178
193
|
end
|
179
194
|
end
|
@@ -202,7 +217,7 @@ module ActiveRecord
|
|
202
217
|
if operation == "count"
|
203
218
|
column_name ||= select_for_count
|
204
219
|
if column_name == :all
|
205
|
-
if distinct && (group_values.any? ||
|
220
|
+
if distinct && (group_values.any? || !(has_limit_or_offset? && order_values.any?))
|
206
221
|
column_name = primary_key
|
207
222
|
end
|
208
223
|
elsif column_name =~ /\s*DISTINCT[\s(]+/i
|
@@ -234,7 +249,7 @@ module ActiveRecord
|
|
234
249
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
235
250
|
column_alias = column_name
|
236
251
|
|
237
|
-
if operation == "count" &&
|
252
|
+
if operation == "count" && has_limit_or_offset?
|
238
253
|
# Shortcut when limit is zero.
|
239
254
|
return 0 if limit_value == 0
|
240
255
|
|
@@ -257,7 +272,7 @@ module ActiveRecord
|
|
257
272
|
query_builder = relation.arel
|
258
273
|
end
|
259
274
|
|
260
|
-
result = @klass.connection.select_all(query_builder, nil
|
275
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
261
276
|
row = result.first
|
262
277
|
value = row && row.values.first
|
263
278
|
type = result.column_types.fetch(column_alias) do
|
@@ -308,7 +323,7 @@ module ActiveRecord
|
|
308
323
|
relation.group_values = group_fields
|
309
324
|
relation.select_values = select_values
|
310
325
|
|
311
|
-
calculated_data = @klass.connection.select_all(relation, nil
|
326
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
312
327
|
|
313
328
|
if association
|
314
329
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -376,12 +391,14 @@ module ActiveRecord
|
|
376
391
|
end
|
377
392
|
|
378
393
|
def build_count_subquery(relation, column_name, distinct)
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
394
|
+
relation.select_values = [
|
395
|
+
if column_name == :all
|
396
|
+
distinct ? table[Arel.star] : Arel.sql(FinderMethods::ONE_AS_ONE)
|
397
|
+
else
|
398
|
+
column_alias = Arel.sql("count_column")
|
399
|
+
aggregate_column(column_name).as(column_alias)
|
400
|
+
end
|
401
|
+
]
|
385
402
|
|
386
403
|
subquery = relation.arel.as(Arel.sql("subquery_for_count"))
|
387
404
|
select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
|