activerecord 5.0.6 → 6.0.1
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 +638 -2023
- data/MIT-LICENSE +3 -1
- data/README.rdoc +8 -6
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/aggregations.rb +249 -246
- data/lib/active_record/association_relation.rb +24 -13
- data/lib/active_record/associations/alias_tracker.rb +24 -33
- data/lib/active_record/associations/association.rb +119 -56
- data/lib/active_record/associations/association_scope.rb +94 -94
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +80 -252
- data/lib/active_record/associations/collection_proxy.rb +158 -121
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -29
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -176
- data/lib/active_record/associations/preloader/association.rb +84 -125
- data/lib/active_record/associations/preloader/through_association.rb +82 -75
- data/lib/active_record/associations/preloader.rb +90 -102
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +26 -14
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -60
- data/lib/active_record/attribute_decorators.rb +38 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +86 -91
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +21 -49
- data/lib/active_record/attribute_methods/serialization.rb +30 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
- data/lib/active_record/attribute_methods/write.rb +35 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/autosave_association.rb +53 -32
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +63 -33
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- 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 +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
- 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 +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
- 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 +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
- data/lib/active_record/connection_handling.rb +159 -40
- data/lib/active_record/core.rb +202 -162
- data/lib/active_record/counter_cache.rb +57 -28
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -86
- data/lib/active_record/enum.rb +60 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -3
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +195 -502
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +151 -97
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +15 -18
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +78 -87
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +143 -97
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +367 -300
- data/lib/active_record/model_schema.rb +145 -139
- data/lib/active_record/nested_attributes.rb +214 -201
- data/lib/active_record/no_touching.rb +10 -1
- data/lib/active_record/null_relation.rb +13 -34
- data/lib/active_record/persistence.rb +442 -72
- data/lib/active_record/query_cache.rb +15 -14
- data/lib/active_record/querying.rb +36 -23
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +309 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +211 -249
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +99 -52
- data/lib/active_record/relation/calculations.rb +211 -172
- data/lib/active_record/relation/delegation.rb +67 -65
- data/lib/active_record/relation/finder_methods.rb +208 -247
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +78 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -104
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +458 -329
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -95
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +429 -318
- data/lib/active_record/result.rb +69 -39
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +15 -5
- data/lib/active_record/scoping/default.rb +93 -95
- data/lib/active_record/scoping/named.rb +45 -25
- data/lib/active_record/scoping.rb +20 -19
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +4 -1
- data/lib/active_record/table_metadata.rb +26 -20
- data/lib/active_record/tasks/database_tasks.rb +276 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
- data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +70 -35
- data/lib/active_record/touch_later.rb +7 -4
- data/lib/active_record/transactions.rb +133 -149
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -45
- 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 +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- 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 +16 -8
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +2 -1
- data/lib/active_record/type/type_map.rb +13 -15
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +23 -17
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -1
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -4
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +58 -0
- 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 +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +133 -50
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- 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 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -130
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- 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/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,12 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/filters"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module FinderMethods
|
5
|
-
ONE_AS_ONE =
|
7
|
+
ONE_AS_ONE = "1 AS one"
|
6
8
|
|
7
9
|
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
8
|
-
# If one or more records
|
9
|
-
# is an integer, find by id coerces its arguments using +to_i+.
|
10
|
+
# If one or more records cannot be found for the requested ids, then ActiveRecord::RecordNotFound will be raised.
|
11
|
+
# If the primary key is an integer, find by id coerces its arguments by using +to_i+.
|
10
12
|
#
|
11
13
|
# Person.find(1) # returns the object for ID = 1
|
12
14
|
# Person.find("1") # returns the object for ID = 1
|
@@ -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
|
#
|
@@ -76,17 +79,12 @@ module ActiveRecord
|
|
76
79
|
# Post.find_by "published_at < ?", 2.weeks.ago
|
77
80
|
def find_by(arg, *args)
|
78
81
|
where(arg, *args).take
|
79
|
-
rescue RangeError
|
80
|
-
nil
|
81
82
|
end
|
82
83
|
|
83
84
|
# Like #find_by, except that if no record is found, raises
|
84
85
|
# an ActiveRecord::RecordNotFound error.
|
85
86
|
def find_by!(arg, *args)
|
86
87
|
where(arg, *args).take!
|
87
|
-
rescue RangeError
|
88
|
-
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
|
89
|
-
@klass.name)
|
90
88
|
end
|
91
89
|
|
92
90
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -97,13 +95,13 @@ module ActiveRecord
|
|
97
95
|
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
|
98
96
|
# Person.where(["name LIKE '%?'", name]).take
|
99
97
|
def take(limit = nil)
|
100
|
-
limit ?
|
98
|
+
limit ? find_take_with_limit(limit) : find_take
|
101
99
|
end
|
102
100
|
|
103
101
|
# Same as #take but raises ActiveRecord::RecordNotFound if no record
|
104
102
|
# is found. Note that #take! accepts no arguments.
|
105
103
|
def take!
|
106
|
-
take
|
104
|
+
take || raise_record_not_found_exception!
|
107
105
|
end
|
108
106
|
|
109
107
|
# Find the first record (or first N records if a parameter is supplied).
|
@@ -117,7 +115,7 @@ module ActiveRecord
|
|
117
115
|
#
|
118
116
|
def first(limit = nil)
|
119
117
|
if limit
|
120
|
-
|
118
|
+
find_nth_with_limit(0, limit)
|
121
119
|
else
|
122
120
|
find_nth 0
|
123
121
|
end
|
@@ -126,7 +124,7 @@ module ActiveRecord
|
|
126
124
|
# Same as #first but raises ActiveRecord::RecordNotFound if no record
|
127
125
|
# is found. Note that #first! accepts no arguments.
|
128
126
|
def first!
|
129
|
-
|
127
|
+
first || raise_record_not_found_exception!
|
130
128
|
end
|
131
129
|
|
132
130
|
# Find the last record (or last N records if a parameter is supplied).
|
@@ -145,27 +143,18 @@ module ActiveRecord
|
|
145
143
|
#
|
146
144
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
147
145
|
def last(limit = nil)
|
148
|
-
return find_last(limit) if loaded? ||
|
146
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
149
147
|
|
150
|
-
result = limit(limit
|
151
|
-
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
148
|
+
result = ordered_relation.limit(limit)
|
152
149
|
result = result.reverse_order!
|
153
150
|
|
154
151
|
limit ? result.reverse : result.first
|
155
|
-
rescue ActiveRecord::IrreversibleOrderError
|
156
|
-
ActiveSupport::Deprecation.warn(<<-WARNING.squish)
|
157
|
-
Finding a last element by loading the relation when SQL ORDER
|
158
|
-
can not be reversed is deprecated.
|
159
|
-
Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
|
160
|
-
Please call `to_a.last` if you still want to load the relation.
|
161
|
-
WARNING
|
162
|
-
find_last(limit)
|
163
152
|
end
|
164
153
|
|
165
154
|
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
166
155
|
# is found. Note that #last! accepts no arguments.
|
167
156
|
def last!
|
168
|
-
last
|
157
|
+
last || raise_record_not_found_exception!
|
169
158
|
end
|
170
159
|
|
171
160
|
# Find the second record.
|
@@ -181,7 +170,7 @@ module ActiveRecord
|
|
181
170
|
# Same as #second but raises ActiveRecord::RecordNotFound if no record
|
182
171
|
# is found.
|
183
172
|
def second!
|
184
|
-
|
173
|
+
second || raise_record_not_found_exception!
|
185
174
|
end
|
186
175
|
|
187
176
|
# Find the third record.
|
@@ -197,7 +186,7 @@ module ActiveRecord
|
|
197
186
|
# Same as #third but raises ActiveRecord::RecordNotFound if no record
|
198
187
|
# is found.
|
199
188
|
def third!
|
200
|
-
|
189
|
+
third || raise_record_not_found_exception!
|
201
190
|
end
|
202
191
|
|
203
192
|
# Find the fourth record.
|
@@ -213,7 +202,7 @@ module ActiveRecord
|
|
213
202
|
# Same as #fourth but raises ActiveRecord::RecordNotFound if no record
|
214
203
|
# is found.
|
215
204
|
def fourth!
|
216
|
-
|
205
|
+
fourth || raise_record_not_found_exception!
|
217
206
|
end
|
218
207
|
|
219
208
|
# Find the fifth record.
|
@@ -229,7 +218,7 @@ module ActiveRecord
|
|
229
218
|
# Same as #fifth but raises ActiveRecord::RecordNotFound if no record
|
230
219
|
# is found.
|
231
220
|
def fifth!
|
232
|
-
|
221
|
+
fifth || raise_record_not_found_exception!
|
233
222
|
end
|
234
223
|
|
235
224
|
# Find the forty-second record. Also known as accessing "the reddit".
|
@@ -245,7 +234,7 @@ module ActiveRecord
|
|
245
234
|
# Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
|
246
235
|
# is found.
|
247
236
|
def forty_two!
|
248
|
-
|
237
|
+
forty_two || raise_record_not_found_exception!
|
249
238
|
end
|
250
239
|
|
251
240
|
# Find the third-to-last record.
|
@@ -261,7 +250,7 @@ module ActiveRecord
|
|
261
250
|
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
262
251
|
# is found.
|
263
252
|
def third_to_last!
|
264
|
-
|
253
|
+
third_to_last || raise_record_not_found_exception!
|
265
254
|
end
|
266
255
|
|
267
256
|
# Find the second-to-last record.
|
@@ -277,7 +266,7 @@ module ActiveRecord
|
|
277
266
|
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
278
267
|
# is found.
|
279
268
|
def second_to_last!
|
280
|
-
|
269
|
+
second_to_last || raise_record_not_found_exception!
|
281
270
|
end
|
282
271
|
|
283
272
|
# Returns true if a record exists in the table that matches the +id+ or
|
@@ -291,7 +280,7 @@ module ActiveRecord
|
|
291
280
|
# * Hash - Finds the record that matches these +find+-style conditions
|
292
281
|
# (such as <tt>{name: 'David'}</tt>).
|
293
282
|
# * +false+ - Returns always +false+.
|
294
|
-
# * No args - Returns +false+ if the
|
283
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
295
284
|
#
|
296
285
|
# For more information about specifying conditions as a hash or array,
|
297
286
|
# see the Conditions section in the introduction to ActiveRecord::Base.
|
@@ -307,32 +296,25 @@ module ActiveRecord
|
|
307
296
|
# Person.exists?(name: 'David')
|
308
297
|
# Person.exists?(false)
|
309
298
|
# Person.exists?
|
299
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
310
300
|
def exists?(conditions = :none)
|
311
301
|
if Base === conditions
|
312
|
-
|
313
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
302
|
+
raise ArgumentError, <<-MSG.squish
|
314
303
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
315
304
|
Please pass the id of the object by calling `.id`.
|
316
305
|
MSG
|
317
306
|
end
|
318
307
|
|
319
|
-
return false if !conditions
|
320
|
-
|
321
|
-
relation = apply_join_dependency(self, construct_join_dependency)
|
322
|
-
return false if ActiveRecord::NullRelation === relation
|
323
|
-
|
324
|
-
relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)
|
308
|
+
return false if !conditions || limit_value == 0
|
325
309
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
else
|
330
|
-
unless conditions == :none
|
331
|
-
relation = relation.where(primary_key => conditions)
|
332
|
-
end
|
310
|
+
if eager_loading?
|
311
|
+
relation = apply_join_dependency(eager_loading: false)
|
312
|
+
return relation.exists?(conditions)
|
333
313
|
end
|
334
314
|
|
335
|
-
|
315
|
+
relation = construct_relation_for_exists(conditions)
|
316
|
+
|
317
|
+
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
|
336
318
|
end
|
337
319
|
|
338
320
|
# This method is called whenever no records are found with either a single
|
@@ -343,258 +325,237 @@ module ActiveRecord
|
|
343
325
|
# of results obtained should be provided in the +result_size+ argument and
|
344
326
|
# the expected number of results should be provided in the +expected_size+
|
345
327
|
# argument.
|
346
|
-
def raise_record_not_found_exception!(ids, result_size, expected_size, key = primary_key)
|
347
|
-
conditions = arel.where_sql(@klass
|
328
|
+
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
329
|
+
conditions = arel.where_sql(@klass)
|
348
330
|
conditions = " [#{conditions}]" if conditions
|
349
331
|
name = @klass.name
|
350
332
|
|
351
|
-
if
|
333
|
+
if ids.nil?
|
334
|
+
error = +"Couldn't find #{name}"
|
335
|
+
error << " with#{conditions}" if conditions
|
336
|
+
raise RecordNotFound.new(error, name, key)
|
337
|
+
elsif Array(ids).size == 1
|
352
338
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
353
339
|
raise RecordNotFound.new(error, name, key, ids)
|
354
340
|
else
|
355
|
-
error = "Couldn't find all #{name.pluralize} with '#{key}': "
|
356
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
357
|
-
|
358
|
-
raise RecordNotFound,
|
341
|
+
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
342
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
343
|
+
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
|
344
|
+
raise RecordNotFound.new(error, name, key, ids)
|
359
345
|
end
|
360
346
|
end
|
361
347
|
|
362
348
|
private
|
363
349
|
|
364
|
-
|
365
|
-
|
366
|
-
|
350
|
+
def offset_index
|
351
|
+
offset_value || 0
|
352
|
+
end
|
367
353
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
374
|
-
# SpecialCategorizations is constructed without knowledge of the
|
375
|
-
# preexisting join in joins_values to categorizations (by way of
|
376
|
-
# the `has_many :through` for categories).
|
377
|
-
#
|
378
|
-
join_dependency = construct_join_dependency(joins_values)
|
379
|
-
|
380
|
-
aliases = join_dependency.aliases
|
381
|
-
relation = select aliases.columns
|
382
|
-
relation = apply_join_dependency(relation, join_dependency)
|
383
|
-
|
384
|
-
if block_given?
|
385
|
-
yield relation
|
386
|
-
else
|
387
|
-
if ActiveRecord::NullRelation === relation
|
388
|
-
[]
|
354
|
+
def construct_relation_for_exists(conditions)
|
355
|
+
conditions = sanitize_forbidden_attributes(conditions)
|
356
|
+
|
357
|
+
if distinct_value && offset_value
|
358
|
+
relation = except(:order).limit!(1)
|
389
359
|
else
|
390
|
-
|
391
|
-
rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
|
392
|
-
join_dependency.instantiate(rows, aliases)
|
360
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
393
361
|
end
|
394
|
-
end
|
395
|
-
end
|
396
362
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
363
|
+
case conditions
|
364
|
+
when Array, Hash
|
365
|
+
relation.where!(conditions) unless conditions.empty?
|
366
|
+
else
|
367
|
+
relation.where!(primary_key => conditions) unless conditions == :none
|
368
|
+
end
|
401
369
|
|
402
|
-
|
403
|
-
from = arel.froms.first
|
404
|
-
if Arel::Table === from
|
405
|
-
apply_join_dependency(self, construct_join_dependency(joins_values))
|
406
|
-
else
|
407
|
-
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
|
408
|
-
# There are no tests that test this branch, but presumably it's
|
409
|
-
# possible for `from` to be a list?
|
410
|
-
apply_join_dependency(self, construct_join_dependency(from))
|
370
|
+
relation
|
411
371
|
end
|
412
|
-
end
|
413
372
|
|
414
|
-
|
415
|
-
|
416
|
-
|
373
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
374
|
+
join_dependency = construct_join_dependency(
|
375
|
+
eager_load_values + includes_values, Arel::Nodes::OuterJoin
|
376
|
+
)
|
377
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
378
|
+
|
379
|
+
if eager_loading && !(
|
380
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
381
|
+
using_limitable_reflections?(
|
382
|
+
construct_join_dependency(
|
383
|
+
select_association_list(joins_values).concat(
|
384
|
+
select_association_list(left_outer_joins_values)
|
385
|
+
), nil
|
386
|
+
).reflections
|
387
|
+
)
|
388
|
+
)
|
389
|
+
if has_limit_or_offset?
|
390
|
+
limited_ids = limited_ids_for(relation)
|
391
|
+
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
392
|
+
end
|
393
|
+
relation.limit_value = relation.offset_value = nil
|
394
|
+
end
|
417
395
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
limited_ids = limited_ids_for(relation)
|
423
|
-
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
396
|
+
if block_given?
|
397
|
+
yield relation, join_dependency
|
398
|
+
else
|
399
|
+
relation
|
424
400
|
end
|
425
|
-
relation.except(:limit, :offset)
|
426
401
|
end
|
427
|
-
end
|
428
402
|
|
429
|
-
|
430
|
-
|
431
|
-
|
403
|
+
def limited_ids_for(relation)
|
404
|
+
values = @klass.connection.columns_for_distinct(
|
405
|
+
connection.visitor.compile(arel_attribute(primary_key)),
|
406
|
+
relation.order_values
|
407
|
+
)
|
432
408
|
|
433
|
-
|
434
|
-
arel = relation.arel
|
409
|
+
relation = relation.except(:select).select(values).distinct!
|
435
410
|
|
436
|
-
|
437
|
-
|
438
|
-
|
411
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
|
412
|
+
id_rows.map { |row| row[primary_key] }
|
413
|
+
end
|
439
414
|
|
440
|
-
|
441
|
-
|
442
|
-
|
415
|
+
def using_limitable_reflections?(reflections)
|
416
|
+
reflections.none?(&:collection?)
|
417
|
+
end
|
443
418
|
|
444
|
-
|
419
|
+
def find_with_ids(*ids)
|
420
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
445
421
|
|
446
|
-
|
447
|
-
|
422
|
+
expects_array = ids.first.kind_of?(Array)
|
423
|
+
return [] if expects_array && ids.first.empty?
|
448
424
|
|
449
|
-
|
450
|
-
return ids.first if expects_array && ids.first.empty?
|
425
|
+
ids = ids.flatten.compact.uniq
|
451
426
|
|
452
|
-
|
427
|
+
model_name = @klass.name
|
453
428
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
429
|
+
case ids.size
|
430
|
+
when 0
|
431
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
432
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
433
|
+
when 1
|
434
|
+
result = find_one(ids.first)
|
435
|
+
expects_array ? [ result ] : result
|
436
|
+
else
|
437
|
+
find_some(ids)
|
438
|
+
end
|
462
439
|
end
|
463
|
-
rescue RangeError
|
464
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
465
|
-
end
|
466
440
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
end
|
441
|
+
def find_one(id)
|
442
|
+
if ActiveRecord::Base === id
|
443
|
+
raise ArgumentError, <<-MSG.squish
|
444
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
445
|
+
Please pass the id of the object by calling `.id`.
|
446
|
+
MSG
|
447
|
+
end
|
475
448
|
|
476
|
-
|
477
|
-
|
449
|
+
relation = where(primary_key => id)
|
450
|
+
record = relation.take
|
478
451
|
|
479
|
-
|
452
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
480
453
|
|
481
|
-
|
482
|
-
|
454
|
+
record
|
455
|
+
end
|
483
456
|
|
484
|
-
|
485
|
-
|
457
|
+
def find_some(ids)
|
458
|
+
return find_some_ordered(ids) unless order_values.present?
|
486
459
|
|
487
|
-
|
460
|
+
result = where(primary_key => ids).to_a
|
488
461
|
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
462
|
+
expected_size =
|
463
|
+
if limit_value && ids.size > limit_value
|
464
|
+
limit_value
|
465
|
+
else
|
466
|
+
ids.size
|
467
|
+
end
|
495
468
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
469
|
+
# 11 ids with limit 3, offset 9 should give 2 results.
|
470
|
+
if offset_value && (ids.size - offset_value < expected_size)
|
471
|
+
expected_size = ids.size - offset_value
|
472
|
+
end
|
500
473
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
474
|
+
if result.size == expected_size
|
475
|
+
result
|
476
|
+
else
|
477
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
478
|
+
end
|
505
479
|
end
|
506
|
-
end
|
507
480
|
|
508
|
-
|
509
|
-
|
481
|
+
def find_some_ordered(ids)
|
482
|
+
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
510
483
|
|
511
|
-
|
484
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
512
485
|
|
513
|
-
|
514
|
-
|
486
|
+
if result.size == ids.size
|
487
|
+
pk_type = @klass.type_for_attribute(primary_key)
|
515
488
|
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
489
|
+
records_by_id = result.index_by(&:id)
|
490
|
+
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
491
|
+
else
|
492
|
+
raise_record_not_found_exception!(ids, result.size, ids.size)
|
493
|
+
end
|
520
494
|
end
|
521
|
-
end
|
522
495
|
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
496
|
+
def find_take
|
497
|
+
if loaded?
|
498
|
+
records.first
|
499
|
+
else
|
500
|
+
@take ||= limit(1).records.first
|
501
|
+
end
|
528
502
|
end
|
529
|
-
end
|
530
503
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
Passing an offset argument to find_nth is deprecated,
|
538
|
-
please use Relation#offset instead.
|
539
|
-
MSG
|
504
|
+
def find_take_with_limit(limit)
|
505
|
+
if loaded?
|
506
|
+
records.take(limit)
|
507
|
+
else
|
508
|
+
limit(limit).to_a
|
509
|
+
end
|
540
510
|
end
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
offset ||= offset_index
|
545
|
-
@offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
|
511
|
+
|
512
|
+
def find_nth(index)
|
513
|
+
@offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
|
546
514
|
end
|
547
|
-
end
|
548
515
|
|
549
|
-
|
550
|
-
|
551
|
-
|
516
|
+
def find_nth_with_limit(index, limit)
|
517
|
+
if loaded?
|
518
|
+
records[index, limit] || []
|
519
|
+
else
|
520
|
+
relation = ordered_relation
|
521
|
+
|
522
|
+
if limit_value
|
523
|
+
limit = [limit_value - index, limit].min
|
524
|
+
end
|
525
|
+
|
526
|
+
if limit > 0
|
527
|
+
relation = relation.offset(offset_index + index) unless index.zero?
|
528
|
+
relation.limit(limit).to_a
|
529
|
+
else
|
530
|
+
[]
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
552
534
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
else
|
559
|
-
self
|
560
|
-
end
|
561
|
-
|
562
|
-
relation = relation.offset(index) unless index.zero?
|
563
|
-
relation.limit(limit).to_a
|
564
|
-
end
|
535
|
+
def find_nth_from_last(index)
|
536
|
+
if loaded?
|
537
|
+
records[-index]
|
538
|
+
else
|
539
|
+
relation = ordered_relation
|
565
540
|
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
else
|
573
|
-
self
|
574
|
-
end
|
575
|
-
|
576
|
-
relation.to_a[-index]
|
577
|
-
# TODO: can be made more performant on large result sets by
|
578
|
-
# for instance, last(index)[-index] (which would require
|
579
|
-
# refactoring the last(n) finder method to make test suite pass),
|
580
|
-
# or by using a combination of reverse_order, limit, and offset,
|
581
|
-
# e.g., reverse_order.offset(index-1).first
|
541
|
+
if equal?(relation) || has_limit_or_offset?
|
542
|
+
relation.records[-index]
|
543
|
+
else
|
544
|
+
relation.last(index)[-index]
|
545
|
+
end
|
546
|
+
end
|
582
547
|
end
|
583
|
-
end
|
584
|
-
|
585
|
-
private
|
586
548
|
|
587
|
-
|
588
|
-
|
589
|
-
records[index, limit]
|
590
|
-
else
|
591
|
-
index += offset
|
592
|
-
find_nth_with_limit(index, limit)
|
549
|
+
def find_last(limit)
|
550
|
+
limit ? records.last(limit) : records.last
|
593
551
|
end
|
594
|
-
end
|
595
552
|
|
596
|
-
|
597
|
-
|
598
|
-
|
553
|
+
def ordered_relation
|
554
|
+
if order_values.empty? && (implicit_order_column || primary_key)
|
555
|
+
order(arel_attribute(implicit_order_column || primary_key).asc)
|
556
|
+
else
|
557
|
+
self
|
558
|
+
end
|
559
|
+
end
|
599
560
|
end
|
600
561
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class Relation
|
3
5
|
class FromClause # :nodoc:
|
@@ -8,14 +10,6 @@ module ActiveRecord
|
|
8
10
|
@name = name
|
9
11
|
end
|
10
12
|
|
11
|
-
def binds
|
12
|
-
if value.is_a?(Relation)
|
13
|
-
value.bound_attributes
|
14
|
-
else
|
15
|
-
[]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
13
|
def merge(other)
|
20
14
|
self
|
21
15
|
end
|