activerecord 5.1.0 → 5.2.0.rc1
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 +410 -530
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +4 -2
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +20 -21
- data/lib/active_record/associations/association_scope.rb +49 -49
- data/lib/active_record/associations/belongs_to_association.rb +12 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +10 -6
- 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 +50 -41
- data/lib/active_record/associations/collection_proxy.rb +22 -39
- 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 +12 -18
- data/lib/active_record/associations/has_one_association.rb +5 -1
- data/lib/active_record/associations/has_one_through_association.rb +8 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -64
- 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/join_dependency.rb +27 -44
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +68 -76
- data/lib/active_record/attribute_assignment.rb +2 -0
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +24 -214
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- 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 +22 -19
- data/lib/active_record/attribute_methods.rb +48 -12
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +8 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -6
- 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 +14 -10
- 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 +175 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -24
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +58 -3
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +165 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +118 -180
- data/lib/active_record/connection_adapters/column.rb +4 -2
- 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 +11 -17
- 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 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -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 +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
- 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 -11
- 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 +4 -2
- 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/oid.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +269 -126
- 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 +64 -85
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- 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 +18 -0
- 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 +92 -95
- 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 +39 -60
- data/lib/active_record/counter_cache.rb +3 -2
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -13
- data/lib/active_record/errors.rb +42 -3
- 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 +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +9 -9
- 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 +8 -6
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +74 -22
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +181 -137
- data/lib/active_record/model_schema.rb +73 -58
- 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 +153 -18
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +61 -3
- 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 +47 -37
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +131 -204
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/calculations.rb +58 -20
- data/lib/active_record/relation/delegation.rb +10 -29
- data/lib/active_record/relation/finder_methods.rb +74 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +51 -20
- 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/predicate_builder.rb +53 -78
- data/lib/active_record/relation/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +101 -95
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +99 -202
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +38 -12
- data/lib/active_record/scoping.rb +12 -10
- 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 +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +37 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +5 -5
- 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/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 -0
- 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.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.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 +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- 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/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/migration.rb +2 -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
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +25 -37
- 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/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- 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 -33
@@ -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
|
@@ -30,14 +32,14 @@ module ActiveRecord
|
|
30
32
|
# end
|
31
33
|
#
|
32
34
|
# ==== Options
|
33
|
-
# * <tt>:batch_size</tt> - Specifies the size of the batch.
|
35
|
+
# * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
|
34
36
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
35
37
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
36
38
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
37
|
-
#
|
39
|
+
# an order is present in the relation.
|
38
40
|
#
|
39
41
|
# Limits are honored, and if present there is no requirement for the batch
|
40
|
-
# size
|
42
|
+
# size: it can be less than, equal to, or greater than the limit.
|
41
43
|
#
|
42
44
|
# The options +start+ and +finish+ are especially useful if you want
|
43
45
|
# multiple workers dealing with the same processing queue. You can make
|
@@ -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
|
@@ -89,14 +96,14 @@ module ActiveRecord
|
|
89
96
|
# To be yielded each record one by one, use #find_each instead.
|
90
97
|
#
|
91
98
|
# ==== Options
|
92
|
-
# * <tt>:batch_size</tt> - Specifies the size of the batch.
|
99
|
+
# * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
|
93
100
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
94
101
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
95
102
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
96
|
-
#
|
103
|
+
# an order is present in the relation.
|
97
104
|
#
|
98
105
|
# Limits are honored, and if present there is no requirement for the batch
|
99
|
-
# size
|
106
|
+
# size: it can be less than, equal to, or greater than the limit.
|
100
107
|
#
|
101
108
|
# The options +start+ and +finish+ are especially useful if you want
|
102
109
|
# multiple workers dealing with the same processing queue. You can make
|
@@ -140,9 +147,9 @@ module ActiveRecord
|
|
140
147
|
# If you do not provide a block to #in_batches, it will return a
|
141
148
|
# BatchEnumerator which is enumerable.
|
142
149
|
#
|
143
|
-
# Person.in_batches.
|
150
|
+
# Person.in_batches.each_with_index do |relation, batch_index|
|
144
151
|
# puts "Processing relation ##{batch_index}"
|
145
|
-
# relation.
|
152
|
+
# relation.delete_all
|
146
153
|
# end
|
147
154
|
#
|
148
155
|
# Examples of calling methods on the returned BatchEnumerator object:
|
@@ -152,12 +159,12 @@ module ActiveRecord
|
|
152
159
|
# Person.in_batches.each_record(&:party_all_night!)
|
153
160
|
#
|
154
161
|
# ==== Options
|
155
|
-
# * <tt>:of</tt> - Specifies the size of the batch.
|
156
|
-
# * <tt>:load</tt> - Specifies if the relation should be loaded.
|
162
|
+
# * <tt>:of</tt> - Specifies the size of the batch. Defaults to 1000.
|
163
|
+
# * <tt>:load</tt> - Specifies if the relation should be loaded. Defaults to false.
|
157
164
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
158
165
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
159
166
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
160
|
-
#
|
167
|
+
# an order is present in the relation.
|
161
168
|
#
|
162
169
|
# Limits are honored, and if present there is no requirement for the batch
|
163
170
|
# size, it can be less than, equal, or greater than the limit.
|
@@ -186,7 +193,7 @@ module ActiveRecord
|
|
186
193
|
#
|
187
194
|
# NOTE: It's not possible to set the order. That is automatically set to
|
188
195
|
# ascending on the primary key ("id ASC") to make the batch ordering
|
189
|
-
# consistent. Therefore the primary key must be orderable, e.g an integer
|
196
|
+
# consistent. Therefore the primary key must be orderable, e.g. an integer
|
190
197
|
# or a string.
|
191
198
|
#
|
192
199
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
@@ -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,8 +130,15 @@ module ActiveRecord
|
|
110
130
|
# end
|
111
131
|
def calculate(operation, column_name)
|
112
132
|
if has_include?(column_name)
|
113
|
-
relation =
|
114
|
-
|
133
|
+
relation = apply_join_dependency
|
134
|
+
|
135
|
+
if operation.to_s.downcase == "count" && !distinct_value
|
136
|
+
relation.distinct!
|
137
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
138
|
+
if (column_name == :all || column_name.nil?) && select_values.empty?
|
139
|
+
relation.order_values = []
|
140
|
+
end
|
141
|
+
end
|
115
142
|
|
116
143
|
relation.calculate(operation, column_name)
|
117
144
|
else
|
@@ -160,13 +187,15 @@ module ActiveRecord
|
|
160
187
|
end
|
161
188
|
|
162
189
|
if has_include?(column_names.first)
|
163
|
-
|
190
|
+
relation = apply_join_dependency
|
191
|
+
relation.pluck(*column_names)
|
164
192
|
else
|
193
|
+
enforce_raw_sql_whitelist(column_names)
|
165
194
|
relation = spawn
|
166
195
|
relation.select_values = column_names.map { |cn|
|
167
196
|
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
168
197
|
}
|
169
|
-
result = klass.connection.select_all(relation.arel, nil
|
198
|
+
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
170
199
|
result.cast_values(klass.attribute_types)
|
171
200
|
end
|
172
201
|
end
|
@@ -194,8 +223,13 @@ module ActiveRecord
|
|
194
223
|
|
195
224
|
if operation == "count"
|
196
225
|
column_name ||= select_for_count
|
197
|
-
|
198
|
-
|
226
|
+
if column_name == :all
|
227
|
+
if distinct && (group_values.any? || select_values.empty? && order_values.empty?)
|
228
|
+
column_name = primary_key
|
229
|
+
end
|
230
|
+
elsif column_name =~ /\s*DISTINCT[\s(]+/i
|
231
|
+
distinct = nil
|
232
|
+
end
|
199
233
|
end
|
200
234
|
|
201
235
|
if group_values.any?
|
@@ -208,7 +242,7 @@ module ActiveRecord
|
|
208
242
|
def aggregate_column(column_name)
|
209
243
|
return column_name if Arel::Expressions === column_name
|
210
244
|
|
211
|
-
if @klass.has_attribute?(column_name
|
245
|
+
if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
212
246
|
@klass.arel_attribute(column_name)
|
213
247
|
else
|
214
248
|
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
@@ -222,7 +256,7 @@ module ActiveRecord
|
|
222
256
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
223
257
|
column_alias = column_name
|
224
258
|
|
225
|
-
if operation == "count" && (
|
259
|
+
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
226
260
|
# Shortcut when limit is zero.
|
227
261
|
return 0 if limit_value == 0
|
228
262
|
|
@@ -234,6 +268,9 @@ module ActiveRecord
|
|
234
268
|
column = aggregate_column(column_name)
|
235
269
|
|
236
270
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
271
|
+
if operation == "sum" && distinct
|
272
|
+
select_value.distinct = true
|
273
|
+
end
|
237
274
|
|
238
275
|
column_alias = select_value.alias
|
239
276
|
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
@@ -242,7 +279,7 @@ module ActiveRecord
|
|
242
279
|
query_builder = relation.arel
|
243
280
|
end
|
244
281
|
|
245
|
-
result = @klass.connection.select_all(query_builder, nil
|
282
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
|
246
283
|
row = result.first
|
247
284
|
value = row && row.values.first
|
248
285
|
type = result.column_types.fetch(column_alias) do
|
@@ -293,7 +330,7 @@ module ActiveRecord
|
|
293
330
|
relation.group_values = group_fields
|
294
331
|
relation.select_values = select_values
|
295
332
|
|
296
|
-
calculated_data = @klass.connection.select_all(relation, nil
|
333
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
|
297
334
|
|
298
335
|
if association
|
299
336
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -361,16 +398,17 @@ module ActiveRecord
|
|
361
398
|
end
|
362
399
|
|
363
400
|
def build_count_subquery(relation, column_name, distinct)
|
364
|
-
|
365
|
-
|
401
|
+
if column_name == :all
|
402
|
+
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
403
|
+
else
|
404
|
+
column_alias = Arel.sql("count_column")
|
405
|
+
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
406
|
+
end
|
366
407
|
|
367
|
-
|
368
|
-
|
369
|
-
subquery = relation.arel.as(subquery_alias)
|
408
|
+
subquery = relation.arel.as(Arel.sql("subquery_for_count"))
|
409
|
+
select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
|
370
410
|
|
371
|
-
|
372
|
-
select_value = operation_over_aggregate_column(column_alias, "count", distinct)
|
373
|
-
sm.project(select_value).from(subquery)
|
411
|
+
Arel::SelectManager.new(subquery).project(select_value)
|
374
412
|
end
|
375
413
|
end
|
376
414
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Delegation # :nodoc:
|
3
5
|
module DelegateCache # :nodoc:
|
@@ -25,8 +27,6 @@ module ActiveRecord
|
|
25
27
|
|
26
28
|
def inherited(child_class)
|
27
29
|
child_class.initialize_relation_delegate_cache
|
28
|
-
delegate = child_class.relation_delegate_class(ActiveRecord::Associations::CollectionProxy)
|
29
|
-
delegate.include ActiveRecord::Associations::CollectionProxy::DelegateExtending
|
30
30
|
super
|
31
31
|
end
|
32
32
|
end
|
@@ -38,13 +38,12 @@ module ActiveRecord
|
|
38
38
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
39
39
|
# for each different klass, and the delegations are compiled into that subclass only.
|
40
40
|
|
41
|
-
delegate :to_xml, :encode_with, :length, :each, :uniq, :
|
42
|
-
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
41
|
+
delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
|
42
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
43
43
|
:to_sentence, :to_formatted_s, :as_json,
|
44
|
-
:shuffle, :split, :index, to: :records
|
44
|
+
:shuffle, :split, :slice, :index, :rindex, to: :records
|
45
45
|
|
46
|
-
delegate :
|
47
|
-
:connection, :columns_hash, to: :klass
|
46
|
+
delegate :primary_key, :connection, to: :klass
|
48
47
|
|
49
48
|
module ClassSpecificRelation # :nodoc:
|
50
49
|
extend ActiveSupport::Concern
|
@@ -75,13 +74,6 @@ module ActiveRecord
|
|
75
74
|
end
|
76
75
|
end
|
77
76
|
end
|
78
|
-
|
79
|
-
def delegate(method, opts = {})
|
80
|
-
@delegation_mutex.synchronize do
|
81
|
-
return if method_defined?(method)
|
82
|
-
super
|
83
|
-
end
|
84
|
-
end
|
85
77
|
end
|
86
78
|
|
87
79
|
private
|
@@ -91,7 +83,8 @@ module ActiveRecord
|
|
91
83
|
self.class.delegate_to_scoped_klass(method)
|
92
84
|
scoping { @klass.public_send(method, *args, &block) }
|
93
85
|
elsif arel.respond_to?(method)
|
94
|
-
|
86
|
+
ActiveSupport::Deprecation.warn \
|
87
|
+
"Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
|
95
88
|
arel.public_send(method, *args, &block)
|
96
89
|
else
|
97
90
|
super
|
@@ -111,21 +104,9 @@ module ActiveRecord
|
|
111
104
|
end
|
112
105
|
end
|
113
106
|
|
114
|
-
def respond_to_missing?(method, include_private = false)
|
115
|
-
super || @klass.respond_to?(method, include_private) ||
|
116
|
-
arel.respond_to?(method, include_private)
|
117
|
-
end
|
118
|
-
|
119
107
|
private
|
120
|
-
|
121
|
-
|
122
|
-
if @klass.respond_to?(method)
|
123
|
-
scoping { @klass.public_send(method, *args, &block) }
|
124
|
-
elsif arel.respond_to?(method)
|
125
|
-
arel.public_send(method, *args, &block)
|
126
|
-
else
|
127
|
-
super
|
128
|
-
end
|
108
|
+
def respond_to_missing?(method, _)
|
109
|
+
super || @klass.respond_to?(method) || arel.respond_to?(method)
|
129
110
|
end
|
130
111
|
end
|
131
112
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/filters"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -16,9 +18,10 @@ module ActiveRecord
|
|
16
18
|
# Person.find([1]) # returns an array for the object with ID = 1
|
17
19
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
18
20
|
#
|
19
|
-
# NOTE: The returned records
|
20
|
-
#
|
21
|
-
#
|
21
|
+
# NOTE: The returned records are in the same order as the ids you provide.
|
22
|
+
# If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
|
23
|
+
# method and provide an explicit ActiveRecord::QueryMethods#order option.
|
24
|
+
# But ActiveRecord::QueryMethods#where method doesn't raise ActiveRecord::RecordNotFound.
|
22
25
|
#
|
23
26
|
# ==== Find with lock
|
24
27
|
#
|
@@ -86,7 +89,7 @@ module ActiveRecord
|
|
86
89
|
where(arg, *args).take!
|
87
90
|
rescue ::RangeError
|
88
91
|
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
|
89
|
-
@klass.name)
|
92
|
+
@klass.name, @klass.primary_key)
|
90
93
|
end
|
91
94
|
|
92
95
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -145,10 +148,9 @@ module ActiveRecord
|
|
145
148
|
#
|
146
149
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
147
150
|
def last(limit = nil)
|
148
|
-
return find_last(limit) if loaded? ||
|
151
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
149
152
|
|
150
|
-
result = limit(limit)
|
151
|
-
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
153
|
+
result = ordered_relation.limit(limit)
|
152
154
|
result = result.reverse_order!
|
153
155
|
|
154
156
|
limit ? result.reverse : result.first
|
@@ -283,7 +285,7 @@ module ActiveRecord
|
|
283
285
|
# * Hash - Finds the record that matches these +find+-style conditions
|
284
286
|
# (such as <tt>{name: 'David'}</tt>).
|
285
287
|
# * +false+ - Returns always +false+.
|
286
|
-
# * No args - Returns +false+ if the
|
288
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
287
289
|
#
|
288
290
|
# For more information about specifying conditions as a hash or array,
|
289
291
|
# see the Conditions section in the introduction to ActiveRecord::Base.
|
@@ -299,6 +301,7 @@ module ActiveRecord
|
|
299
301
|
# Person.exists?(name: 'David')
|
300
302
|
# Person.exists?(false)
|
301
303
|
# Person.exists?
|
304
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
302
305
|
def exists?(conditions = :none)
|
303
306
|
if Base === conditions
|
304
307
|
raise ArgumentError, <<-MSG.squish
|
@@ -307,14 +310,16 @@ module ActiveRecord
|
|
307
310
|
MSG
|
308
311
|
end
|
309
312
|
|
310
|
-
return false if !conditions
|
313
|
+
return false if !conditions || limit_value == 0
|
311
314
|
|
312
|
-
|
313
|
-
|
315
|
+
if eager_loading?
|
316
|
+
relation = apply_join_dependency(eager_loading: false)
|
317
|
+
return relation.exists?(conditions)
|
318
|
+
end
|
314
319
|
|
315
|
-
relation = construct_relation_for_exists(
|
320
|
+
relation = construct_relation_for_exists(conditions)
|
316
321
|
|
317
|
-
connection.select_value(relation, "#{name} Exists"
|
322
|
+
skip_query_cache_if_necessary { connection.select_value(relation.arel, "#{name} Exists") } ? true : false
|
318
323
|
rescue ::RangeError
|
319
324
|
false
|
320
325
|
end
|
@@ -327,23 +332,23 @@ module ActiveRecord
|
|
327
332
|
# of results obtained should be provided in the +result_size+ argument and
|
328
333
|
# the expected number of results should be provided in the +expected_size+
|
329
334
|
# argument.
|
330
|
-
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key) # :nodoc:
|
331
|
-
conditions = arel.where_sql(@klass
|
335
|
+
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
336
|
+
conditions = arel.where_sql(@klass)
|
332
337
|
conditions = " [#{conditions}]" if conditions
|
333
338
|
name = @klass.name
|
334
339
|
|
335
340
|
if ids.nil?
|
336
|
-
error = "Couldn't find #{name}"
|
341
|
+
error = "Couldn't find #{name}".dup
|
337
342
|
error << " with#{conditions}" if conditions
|
338
|
-
raise RecordNotFound.new(error, name)
|
343
|
+
raise RecordNotFound.new(error, name, key)
|
339
344
|
elsif Array(ids).size == 1
|
340
345
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
341
346
|
raise RecordNotFound.new(error, name, key, ids)
|
342
347
|
else
|
343
|
-
error = "Couldn't find all #{name.pluralize} with '#{key}': "
|
344
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
345
|
-
|
346
|
-
raise RecordNotFound.new(error, name,
|
348
|
+
error = "Couldn't find all #{name.pluralize} with '#{key}': ".dup
|
349
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
350
|
+
error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
|
351
|
+
raise RecordNotFound.new(error, name, key, ids)
|
347
352
|
end
|
348
353
|
end
|
349
354
|
|
@@ -353,37 +358,8 @@ module ActiveRecord
|
|
353
358
|
offset_value || 0
|
354
359
|
end
|
355
360
|
|
356
|
-
def
|
357
|
-
|
358
|
-
# any joins already present in `self`, so pass them in
|
359
|
-
#
|
360
|
-
# failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
|
361
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
362
|
-
# SpecialCategorizations is constructed without knowledge of the
|
363
|
-
# preexisting join in joins_values to categorizations (by way of
|
364
|
-
# the `has_many :through` for categories).
|
365
|
-
#
|
366
|
-
join_dependency = construct_join_dependency(joins_values)
|
367
|
-
|
368
|
-
aliases = join_dependency.aliases
|
369
|
-
relation = select aliases.columns
|
370
|
-
relation = apply_join_dependency(relation, join_dependency)
|
371
|
-
|
372
|
-
if block_given?
|
373
|
-
yield relation
|
374
|
-
else
|
375
|
-
if ActiveRecord::NullRelation === relation
|
376
|
-
[]
|
377
|
-
else
|
378
|
-
arel = relation.arel
|
379
|
-
rows = connection.select_all(arel, "SQL", relation.bound_attributes)
|
380
|
-
join_dependency.instantiate(rows, aliases)
|
381
|
-
end
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
|
-
def construct_relation_for_exists(relation, conditions)
|
386
|
-
relation = relation.except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
361
|
+
def construct_relation_for_exists(conditions)
|
362
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
387
363
|
|
388
364
|
case conditions
|
389
365
|
when Array, Hash
|
@@ -395,37 +371,43 @@ module ActiveRecord
|
|
395
371
|
relation
|
396
372
|
end
|
397
373
|
|
398
|
-
def construct_join_dependency(
|
374
|
+
def construct_join_dependency(eager_loading: true)
|
399
375
|
including = eager_load_values + includes_values
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
apply_join_dependency(self, construct_join_dependency(joins_values))
|
376
|
+
joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) }
|
377
|
+
ActiveRecord::Associations::JoinDependency.new(
|
378
|
+
klass, table, including, alias_tracker(joins), eager_loading: eager_loading
|
379
|
+
)
|
405
380
|
end
|
406
381
|
|
407
|
-
def apply_join_dependency(
|
408
|
-
|
382
|
+
def apply_join_dependency(eager_loading: true)
|
383
|
+
join_dependency = construct_join_dependency(eager_loading: eager_loading)
|
384
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
409
385
|
|
410
|
-
if using_limitable_reflections?(join_dependency.reflections)
|
411
|
-
|
412
|
-
else
|
413
|
-
if relation.limit_value
|
386
|
+
if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
|
387
|
+
if has_limit_or_offset?
|
414
388
|
limited_ids = limited_ids_for(relation)
|
415
389
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
416
390
|
end
|
417
|
-
relation.
|
391
|
+
relation.limit_value = relation.offset_value = nil
|
392
|
+
end
|
393
|
+
|
394
|
+
if block_given?
|
395
|
+
relation._select!(join_dependency.aliases.columns)
|
396
|
+
yield relation, join_dependency
|
397
|
+
else
|
398
|
+
relation
|
418
399
|
end
|
419
400
|
end
|
420
401
|
|
421
402
|
def limited_ids_for(relation)
|
422
403
|
values = @klass.connection.columns_for_distinct(
|
423
|
-
|
404
|
+
connection.column_name_from_arel_node(arel_attribute(primary_key)),
|
405
|
+
relation.order_values
|
406
|
+
)
|
424
407
|
|
425
408
|
relation = relation.except(:select).select(values).distinct!
|
426
|
-
arel = relation.arel
|
427
409
|
|
428
|
-
id_rows = @klass.connection.select_all(arel, "SQL"
|
410
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
|
429
411
|
id_rows.map { |row| row[primary_key] }
|
430
412
|
end
|
431
413
|
|
@@ -441,9 +423,12 @@ module ActiveRecord
|
|
441
423
|
|
442
424
|
ids = ids.flatten.compact.uniq
|
443
425
|
|
426
|
+
model_name = @klass.name
|
427
|
+
|
444
428
|
case ids.size
|
445
429
|
when 0
|
446
|
-
|
430
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
431
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
447
432
|
when 1
|
448
433
|
result = find_one(ids.first)
|
449
434
|
expects_array ? [ result ] : result
|
@@ -451,7 +436,8 @@ module ActiveRecord
|
|
451
436
|
find_some(ids)
|
452
437
|
end
|
453
438
|
rescue ::RangeError
|
454
|
-
|
439
|
+
error_message = "Couldn't find #{model_name} with an out of range ID"
|
440
|
+
raise RecordNotFound.new(error_message, model_name, primary_key, ids)
|
455
441
|
end
|
456
442
|
|
457
443
|
def find_one(id)
|
@@ -533,13 +519,13 @@ module ActiveRecord
|
|
533
519
|
if loaded?
|
534
520
|
records[index, limit] || []
|
535
521
|
else
|
536
|
-
relation =
|
537
|
-
|
538
|
-
|
539
|
-
|
522
|
+
relation = ordered_relation
|
523
|
+
|
524
|
+
if limit_value
|
525
|
+
limit = [limit_value - index, limit].min
|
540
526
|
end
|
541
527
|
|
542
|
-
if
|
528
|
+
if limit > 0
|
543
529
|
relation = relation.offset(offset_index + index) unless index.zero?
|
544
530
|
relation.limit(limit).to_a
|
545
531
|
else
|
@@ -552,23 +538,26 @@ module ActiveRecord
|
|
552
538
|
if loaded?
|
553
539
|
records[-index]
|
554
540
|
else
|
555
|
-
relation =
|
556
|
-
|
541
|
+
relation = ordered_relation
|
542
|
+
|
543
|
+
if equal?(relation) || has_limit_or_offset?
|
544
|
+
relation.records[-index]
|
557
545
|
else
|
558
|
-
|
546
|
+
relation.last(index)[-index]
|
559
547
|
end
|
560
|
-
|
561
|
-
relation.to_a[-index]
|
562
|
-
# TODO: can be made more performant on large result sets by
|
563
|
-
# for instance, last(index)[-index] (which would require
|
564
|
-
# refactoring the last(n) finder method to make test suite pass),
|
565
|
-
# or by using a combination of reverse_order, limit, and offset,
|
566
|
-
# e.g., reverse_order.offset(index-1).first
|
567
548
|
end
|
568
549
|
end
|
569
550
|
|
570
551
|
def find_last(limit)
|
571
552
|
limit ? records.last(limit) : records.last
|
572
553
|
end
|
554
|
+
|
555
|
+
def ordered_relation
|
556
|
+
if order_values.empty? && primary_key
|
557
|
+
order(arel_attribute(primary_key).asc)
|
558
|
+
else
|
559
|
+
self
|
560
|
+
end
|
561
|
+
end
|
573
562
|
end
|
574
563
|
end
|