activerecord 4.2.9 → 6.1.4.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 +964 -1382
- data/MIT-LICENSE +4 -2
- data/README.rdoc +15 -14
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +40 -15
- data/lib/active_record/associations/alias_tracker.rb +40 -43
- data/lib/active_record/associations/association.rb +162 -69
- data/lib/active_record/associations/association_scope.rb +105 -130
- data/lib/active_record/associations/belongs_to_association.rb +83 -65
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +57 -43
- data/lib/active_record/associations/builder/belongs_to.rb +74 -57
- data/lib/active_record/associations/builder/collection_association.rb +15 -37
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
- data/lib/active_record/associations/builder/has_many.rb +13 -5
- data/lib/active_record/associations/builder/has_one.rb +44 -6
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +148 -287
- data/lib/active_record/associations/collection_proxy.rb +252 -150
- data/lib/active_record/associations/foreign_association.rb +23 -1
- data/lib/active_record/associations/has_many_association.rb +56 -98
- data/lib/active_record/associations/has_many_through_association.rb +68 -89
- data/lib/active_record/associations/has_one_association.rb +73 -47
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/join_dependency.rb +174 -169
- data/lib/active_record/associations/preloader/association.rb +108 -115
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +97 -94
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +39 -19
- data/lib/active_record/associations.rb +1845 -1598
- data/lib/active_record/attribute_assignment.rb +59 -185
- data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
- data/lib/active_record/attribute_methods/dirty.rb +168 -148
- data/lib/active_record/attribute_methods/primary_key.rb +93 -83
- data/lib/active_record/attribute_methods/query.rb +8 -10
- data/lib/active_record/attribute_methods/read.rb +19 -79
- data/lib/active_record/attribute_methods/serialization.rb +49 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
- data/lib/active_record/attribute_methods/write.rb +24 -55
- data/lib/active_record/attribute_methods.rb +149 -154
- data/lib/active_record/attributes.rb +234 -78
- data/lib/active_record/autosave_association.rb +133 -60
- data/lib/active_record/base.rb +46 -46
- data/lib/active_record/callbacks.rb +234 -79
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
- data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
- data/lib/active_record/connection_adapters/column.rb +67 -40
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
- data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
- 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 +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +314 -41
- data/lib/active_record/core.rb +458 -241
- data/lib/active_record/counter_cache.rb +70 -49
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +211 -92
- data/lib/active_record/errors.rb +224 -54
- data/lib/active_record/explain.rb +27 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +33 -14
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +275 -500
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +175 -110
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +121 -29
- data/lib/active_record/internal_metadata.rb +62 -0
- data/lib/active_record/legacy_yaml_adapter.rb +27 -5
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +98 -92
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +93 -31
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +185 -90
- data/lib/active_record/migration/compatibility.rb +295 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +673 -325
- data/lib/active_record/model_schema.rb +418 -113
- data/lib/active_record/nested_attributes.rb +263 -224
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +572 -136
- data/lib/active_record/query_cache.rb +29 -23
- data/lib/active_record/querying.rb +50 -31
- data/lib/active_record/railtie.rb +170 -51
- data/lib/active_record/railties/console_sandbox.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +523 -199
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +454 -291
- data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
- data/lib/active_record/relation/batches.rb +217 -59
- data/lib/active_record/relation/calculations.rb +324 -249
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +316 -242
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +95 -103
- data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +136 -122
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +757 -413
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -20
- data/lib/active_record/relation/where_clause.rb +239 -0
- data/lib/active_record/relation.rb +554 -343
- data/lib/active_record/result.rb +91 -47
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +134 -122
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +141 -92
- data/lib/active_record/schema_migration.rb +24 -23
- data/lib/active_record/scoping/default.rb +96 -83
- data/lib/active_record/scoping/named.rb +78 -36
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +48 -0
- data/lib/active_record/serialization.rb +8 -6
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +89 -36
- data/lib/active_record/store.rb +128 -43
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +81 -0
- data/lib/active_record/tasks/database_tasks.rb +364 -130
- data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
- data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +86 -43
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +182 -163
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +27 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +21 -16
- data/lib/active_record/type/type_map.rb +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +84 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +12 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +63 -56
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -29
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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 +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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 +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
- data/lib/rails/generators/active_record/migration.rb +35 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- 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 +172 -65
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- 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 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_decorators.rb +0 -66
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,13 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/filters"
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module FinderMethods
|
6
|
-
ONE_AS_ONE =
|
7
|
+
ONE_AS_ONE = "1 AS one"
|
7
8
|
|
8
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]).
|
9
|
-
# If
|
10
|
-
# 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+.
|
11
12
|
#
|
12
13
|
# Person.find(1) # returns the object for ID = 1
|
13
14
|
# Person.find("1") # returns the object for ID = 1
|
@@ -17,11 +18,10 @@ module ActiveRecord
|
|
17
18
|
# Person.find([1]) # returns an array for the object with ID = 1
|
18
19
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
19
20
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# option if you want the results are sorted.
|
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.
|
25
25
|
#
|
26
26
|
# ==== Find with lock
|
27
27
|
#
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
# person.save!
|
38
38
|
# end
|
39
39
|
#
|
40
|
-
# ==== Variations of
|
40
|
+
# ==== Variations of #find
|
41
41
|
#
|
42
42
|
# Person.where(name: 'Spartacus', rating: 4)
|
43
43
|
# # returns a chainable list (which can be empty).
|
@@ -45,13 +45,13 @@ module ActiveRecord
|
|
45
45
|
# Person.find_by(name: 'Spartacus', rating: 4)
|
46
46
|
# # returns the first item or nil.
|
47
47
|
#
|
48
|
-
# Person.
|
48
|
+
# Person.find_or_initialize_by(name: 'Spartacus', rating: 4)
|
49
49
|
# # returns the first item or returns a new instance (requires you call .save to persist against the database).
|
50
50
|
#
|
51
|
-
# Person.
|
52
|
-
# # returns the first item or creates it and returns it
|
51
|
+
# Person.find_or_create_by(name: 'Spartacus', rating: 4)
|
52
|
+
# # returns the first item or creates it and returns it.
|
53
53
|
#
|
54
|
-
# ==== Alternatives for
|
54
|
+
# ==== Alternatives for #find
|
55
55
|
#
|
56
56
|
# Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
|
57
57
|
# # returns a boolean indicating if any record with the given conditions exist.
|
@@ -60,16 +60,13 @@ module ActiveRecord
|
|
60
60
|
# # returns a chainable list of instances with only the mentioned fields.
|
61
61
|
#
|
62
62
|
# Person.where(name: 'Spartacus', rating: 4).ids
|
63
|
-
# # returns an Array of ids
|
63
|
+
# # returns an Array of ids.
|
64
64
|
#
|
65
65
|
# Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
|
66
|
-
# # returns an Array of the required fields
|
66
|
+
# # returns an Array of the required fields.
|
67
67
|
def find(*args)
|
68
|
-
if block_given?
|
69
|
-
|
70
|
-
else
|
71
|
-
find_with_ids(*args)
|
72
|
-
end
|
68
|
+
return super if block_given?
|
69
|
+
find_with_ids(*args)
|
73
70
|
end
|
74
71
|
|
75
72
|
# Finds the first record matching the specified conditions. There
|
@@ -80,18 +77,14 @@ module ActiveRecord
|
|
80
77
|
#
|
81
78
|
# Post.find_by name: 'Spartacus', rating: 4
|
82
79
|
# Post.find_by "published_at < ?", 2.weeks.ago
|
83
|
-
def find_by(*args)
|
84
|
-
where(*args).take
|
85
|
-
rescue RangeError
|
86
|
-
nil
|
80
|
+
def find_by(arg, *args)
|
81
|
+
where(arg, *args).take
|
87
82
|
end
|
88
83
|
|
89
|
-
# Like
|
90
|
-
# an
|
91
|
-
def find_by!(*args)
|
92
|
-
where(*args).take!
|
93
|
-
rescue RangeError
|
94
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
|
84
|
+
# Like #find_by, except that if no record is found, raises
|
85
|
+
# an ActiveRecord::RecordNotFound error.
|
86
|
+
def find_by!(arg, *args)
|
87
|
+
where(arg, *args).take!
|
95
88
|
end
|
96
89
|
|
97
90
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -102,13 +95,13 @@ module ActiveRecord
|
|
102
95
|
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
|
103
96
|
# Person.where(["name LIKE '%?'", name]).take
|
104
97
|
def take(limit = nil)
|
105
|
-
limit ?
|
98
|
+
limit ? find_take_with_limit(limit) : find_take
|
106
99
|
end
|
107
100
|
|
108
|
-
# Same as
|
109
|
-
# is found. Note that
|
101
|
+
# Same as #take but raises ActiveRecord::RecordNotFound if no record
|
102
|
+
# is found. Note that #take! accepts no arguments.
|
110
103
|
def take!
|
111
|
-
take
|
104
|
+
take || raise_record_not_found_exception!
|
112
105
|
end
|
113
106
|
|
114
107
|
# Find the first record (or first N records if a parameter is supplied).
|
@@ -121,17 +114,19 @@ module ActiveRecord
|
|
121
114
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
122
115
|
#
|
123
116
|
def first(limit = nil)
|
117
|
+
check_reorder_deprecation unless loaded?
|
118
|
+
|
124
119
|
if limit
|
125
|
-
find_nth_with_limit(
|
120
|
+
find_nth_with_limit(0, limit)
|
126
121
|
else
|
127
|
-
find_nth
|
122
|
+
find_nth 0
|
128
123
|
end
|
129
124
|
end
|
130
125
|
|
131
|
-
# Same as
|
132
|
-
# is found. Note that
|
126
|
+
# Same as #first but raises ActiveRecord::RecordNotFound if no record
|
127
|
+
# is found. Note that #first! accepts no arguments.
|
133
128
|
def first!
|
134
|
-
|
129
|
+
first || raise_record_not_found_exception!
|
135
130
|
end
|
136
131
|
|
137
132
|
# Find the last record (or last N records if a parameter is supplied).
|
@@ -150,21 +145,18 @@ module ActiveRecord
|
|
150
145
|
#
|
151
146
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
152
147
|
def last(limit = nil)
|
153
|
-
if
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
else
|
160
|
-
find_last
|
161
|
-
end
|
148
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
149
|
+
|
150
|
+
result = ordered_relation.limit(limit)
|
151
|
+
result = result.reverse_order!
|
152
|
+
|
153
|
+
limit ? result.reverse : result.first
|
162
154
|
end
|
163
155
|
|
164
|
-
# Same as
|
165
|
-
# is found. Note that
|
156
|
+
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
157
|
+
# is found. Note that #last! accepts no arguments.
|
166
158
|
def last!
|
167
|
-
last
|
159
|
+
last || raise_record_not_found_exception!
|
168
160
|
end
|
169
161
|
|
170
162
|
# Find the second record.
|
@@ -174,13 +166,13 @@ module ActiveRecord
|
|
174
166
|
# Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
|
175
167
|
# Person.where(["user_name = :u", { u: user_name }]).second
|
176
168
|
def second
|
177
|
-
find_nth
|
169
|
+
find_nth 1
|
178
170
|
end
|
179
171
|
|
180
|
-
# Same as
|
172
|
+
# Same as #second but raises ActiveRecord::RecordNotFound if no record
|
181
173
|
# is found.
|
182
174
|
def second!
|
183
|
-
|
175
|
+
second || raise_record_not_found_exception!
|
184
176
|
end
|
185
177
|
|
186
178
|
# Find the third record.
|
@@ -190,13 +182,13 @@ module ActiveRecord
|
|
190
182
|
# Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
|
191
183
|
# Person.where(["user_name = :u", { u: user_name }]).third
|
192
184
|
def third
|
193
|
-
find_nth
|
185
|
+
find_nth 2
|
194
186
|
end
|
195
187
|
|
196
|
-
# Same as
|
188
|
+
# Same as #third but raises ActiveRecord::RecordNotFound if no record
|
197
189
|
# is found.
|
198
190
|
def third!
|
199
|
-
|
191
|
+
third || raise_record_not_found_exception!
|
200
192
|
end
|
201
193
|
|
202
194
|
# Find the fourth record.
|
@@ -206,13 +198,13 @@ module ActiveRecord
|
|
206
198
|
# Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
|
207
199
|
# Person.where(["user_name = :u", { u: user_name }]).fourth
|
208
200
|
def fourth
|
209
|
-
find_nth
|
201
|
+
find_nth 3
|
210
202
|
end
|
211
203
|
|
212
|
-
# Same as
|
204
|
+
# Same as #fourth but raises ActiveRecord::RecordNotFound if no record
|
213
205
|
# is found.
|
214
206
|
def fourth!
|
215
|
-
|
207
|
+
fourth || raise_record_not_found_exception!
|
216
208
|
end
|
217
209
|
|
218
210
|
# Find the fifth record.
|
@@ -222,13 +214,13 @@ module ActiveRecord
|
|
222
214
|
# Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
|
223
215
|
# Person.where(["user_name = :u", { u: user_name }]).fifth
|
224
216
|
def fifth
|
225
|
-
find_nth
|
217
|
+
find_nth 4
|
226
218
|
end
|
227
219
|
|
228
|
-
# Same as
|
220
|
+
# Same as #fifth but raises ActiveRecord::RecordNotFound if no record
|
229
221
|
# is found.
|
230
222
|
def fifth!
|
231
|
-
|
223
|
+
fifth || raise_record_not_found_exception!
|
232
224
|
end
|
233
225
|
|
234
226
|
# Find the forty-second record. Also known as accessing "the reddit".
|
@@ -238,30 +230,62 @@ module ActiveRecord
|
|
238
230
|
# Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
|
239
231
|
# Person.where(["user_name = :u", { u: user_name }]).forty_two
|
240
232
|
def forty_two
|
241
|
-
find_nth
|
233
|
+
find_nth 41
|
242
234
|
end
|
243
235
|
|
244
|
-
# Same as
|
236
|
+
# Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
|
245
237
|
# is found.
|
246
238
|
def forty_two!
|
247
|
-
|
239
|
+
forty_two || raise_record_not_found_exception!
|
240
|
+
end
|
241
|
+
|
242
|
+
# Find the third-to-last record.
|
243
|
+
# If no order is defined it will order by primary key.
|
244
|
+
#
|
245
|
+
# Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
|
246
|
+
# Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
|
247
|
+
# Person.where(["user_name = :u", { u: user_name }]).third_to_last
|
248
|
+
def third_to_last
|
249
|
+
find_nth_from_last 3
|
250
|
+
end
|
251
|
+
|
252
|
+
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
253
|
+
# is found.
|
254
|
+
def third_to_last!
|
255
|
+
third_to_last || raise_record_not_found_exception!
|
256
|
+
end
|
257
|
+
|
258
|
+
# Find the second-to-last record.
|
259
|
+
# If no order is defined it will order by primary key.
|
260
|
+
#
|
261
|
+
# Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
|
262
|
+
# Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
|
263
|
+
# Person.where(["user_name = :u", { u: user_name }]).second_to_last
|
264
|
+
def second_to_last
|
265
|
+
find_nth_from_last 2
|
248
266
|
end
|
249
267
|
|
250
|
-
#
|
251
|
-
#
|
268
|
+
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
269
|
+
# is found.
|
270
|
+
def second_to_last!
|
271
|
+
second_to_last || raise_record_not_found_exception!
|
272
|
+
end
|
273
|
+
|
274
|
+
# Returns true if a record exists in the table that matches the +id+ or
|
275
|
+
# conditions given, or false otherwise. The argument can take six forms:
|
252
276
|
#
|
253
277
|
# * Integer - Finds the record with this primary key.
|
254
278
|
# * String - Finds the record with a primary key corresponding to this
|
255
279
|
# string (such as <tt>'5'</tt>).
|
256
|
-
# * Array - Finds the record that matches these +
|
280
|
+
# * Array - Finds the record that matches these +where+-style conditions
|
257
281
|
# (such as <tt>['name LIKE ?', "%#{query}%"]</tt>).
|
258
|
-
# * Hash - Finds the record that matches these +
|
282
|
+
# * Hash - Finds the record that matches these +where+-style conditions
|
259
283
|
# (such as <tt>{name: 'David'}</tt>).
|
260
284
|
# * +false+ - Returns always +false+.
|
261
|
-
# * No args - Returns +false+ if the
|
285
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
262
286
|
#
|
263
287
|
# For more information about specifying conditions as a hash or array,
|
264
|
-
# see the Conditions section in the introduction to
|
288
|
+
# see the Conditions section in the introduction to ActiveRecord::Base.
|
265
289
|
#
|
266
290
|
# Note: You can't pass in a condition as a string (like <tt>name =
|
267
291
|
# 'Jamie'</tt>), since it would be sanitized and then queried against
|
@@ -274,243 +298,293 @@ module ActiveRecord
|
|
274
298
|
# Person.exists?(name: 'David')
|
275
299
|
# Person.exists?(false)
|
276
300
|
# Person.exists?
|
301
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
277
302
|
def exists?(conditions = :none)
|
278
303
|
if Base === conditions
|
279
|
-
|
280
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
304
|
+
raise ArgumentError, <<-MSG.squish
|
281
305
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
282
|
-
Please pass the id of the object by calling `.id
|
306
|
+
Please pass the id of the object by calling `.id`.
|
283
307
|
MSG
|
284
308
|
end
|
285
309
|
|
286
|
-
return false if !conditions
|
310
|
+
return false if !conditions || limit_value == 0
|
287
311
|
|
288
|
-
|
289
|
-
|
312
|
+
if eager_loading?
|
313
|
+
relation = apply_join_dependency(eager_loading: false)
|
314
|
+
return relation.exists?(conditions)
|
315
|
+
end
|
290
316
|
|
291
|
-
relation =
|
317
|
+
relation = construct_relation_for_exists(conditions)
|
318
|
+
return false if relation.where_clause.contradiction?
|
292
319
|
|
293
|
-
|
294
|
-
|
295
|
-
|
320
|
+
skip_query_cache_if_necessary { connection.select_rows(relation.arel, "#{name} Exists?").size == 1 }
|
321
|
+
end
|
322
|
+
|
323
|
+
# Returns true if the relation contains the given record or false otherwise.
|
324
|
+
#
|
325
|
+
# No query is performed if the relation is loaded; the given record is
|
326
|
+
# compared to the records in memory. If the relation is unloaded, an
|
327
|
+
# efficient existence query is performed, as in #exists?.
|
328
|
+
def include?(record)
|
329
|
+
if loaded? || offset_value || limit_value || having_clause.any?
|
330
|
+
records.include?(record)
|
296
331
|
else
|
297
|
-
|
298
|
-
relation = relation.where(primary_key => conditions)
|
299
|
-
end
|
332
|
+
record.is_a?(klass) && exists?(record.id)
|
300
333
|
end
|
301
|
-
|
302
|
-
connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false
|
303
334
|
end
|
304
335
|
|
336
|
+
alias :member? :include?
|
337
|
+
|
305
338
|
# This method is called whenever no records are found with either a single
|
306
|
-
# id or multiple ids and raises
|
339
|
+
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
307
340
|
#
|
308
341
|
# The error message is different depending on whether a single id or
|
309
342
|
# multiple ids are provided. If multiple ids are provided, then the number
|
310
343
|
# of results obtained should be provided in the +result_size+ argument and
|
311
344
|
# the expected number of results should be provided in the +expected_size+
|
312
345
|
# argument.
|
313
|
-
def raise_record_not_found_exception!(ids, result_size, expected_size)
|
314
|
-
conditions = arel.where_sql
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
346
|
+
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
347
|
+
conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
|
348
|
+
|
349
|
+
name = @klass.name
|
350
|
+
|
351
|
+
if ids.nil?
|
352
|
+
error = +"Couldn't find #{name}"
|
353
|
+
error << " with#{conditions}" if conditions
|
354
|
+
raise RecordNotFound.new(error, name, key)
|
355
|
+
elsif Array.wrap(ids).size == 1
|
356
|
+
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
357
|
+
raise RecordNotFound.new(error, name, key, ids)
|
319
358
|
else
|
320
|
-
error = "Couldn't find all #{
|
321
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
359
|
+
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
360
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
361
|
+
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
|
362
|
+
raise RecordNotFound.new(error, name, key, ids)
|
322
363
|
end
|
323
|
-
|
324
|
-
raise RecordNotFound, error
|
325
364
|
end
|
326
365
|
|
327
366
|
private
|
367
|
+
def check_reorder_deprecation
|
368
|
+
if !order_values.empty? && order_values.all?(&:blank?)
|
369
|
+
blank_value = order_values.first
|
370
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
|
+
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
+
takes non-deterministic result in Rails 6.2.
|
373
|
+
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
|
+
MSG
|
375
|
+
end
|
376
|
+
end
|
328
377
|
|
329
|
-
|
330
|
-
|
331
|
-
end
|
378
|
+
def construct_relation_for_exists(conditions)
|
379
|
+
conditions = sanitize_forbidden_attributes(conditions)
|
332
380
|
|
333
|
-
|
334
|
-
|
335
|
-
# any joins already present in `self`, so pass them in
|
336
|
-
#
|
337
|
-
# failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
|
338
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
339
|
-
# SpecialCategorizations is constructed without knowledge of the
|
340
|
-
# preexisting join in joins_values to categorizations (by way of
|
341
|
-
# the `has_many :through` for categories).
|
342
|
-
#
|
343
|
-
join_dependency = construct_join_dependency(joins_values)
|
344
|
-
|
345
|
-
aliases = join_dependency.aliases
|
346
|
-
relation = select aliases.columns
|
347
|
-
relation = apply_join_dependency(relation, join_dependency)
|
348
|
-
|
349
|
-
if block_given?
|
350
|
-
yield relation
|
351
|
-
else
|
352
|
-
if ActiveRecord::NullRelation === relation
|
353
|
-
[]
|
381
|
+
if distinct_value && offset_value
|
382
|
+
relation = except(:order).limit!(1)
|
354
383
|
else
|
355
|
-
|
356
|
-
rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
|
357
|
-
join_dependency.instantiate(rows, aliases)
|
384
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
358
385
|
end
|
359
|
-
end
|
360
|
-
end
|
361
386
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
387
|
+
case conditions
|
388
|
+
when Array, Hash
|
389
|
+
relation.where!(conditions) unless conditions.empty?
|
390
|
+
else
|
391
|
+
relation.where!(primary_key => conditions) unless conditions == :none
|
392
|
+
end
|
366
393
|
|
367
|
-
|
368
|
-
from = arel.froms.first
|
369
|
-
if Arel::Table === from
|
370
|
-
apply_join_dependency(self, construct_join_dependency(joins_values))
|
371
|
-
else
|
372
|
-
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
|
373
|
-
# There are no tests that test this branch, but presumably it's
|
374
|
-
# possible for `from` to be a list?
|
375
|
-
apply_join_dependency(self, construct_join_dependency(from))
|
394
|
+
relation
|
376
395
|
end
|
377
|
-
end
|
378
396
|
|
379
|
-
|
380
|
-
|
381
|
-
|
397
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
398
|
+
join_dependency = construct_join_dependency(
|
399
|
+
eager_load_values | includes_values, Arel::Nodes::OuterJoin
|
400
|
+
)
|
401
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
|
+
|
403
|
+
if eager_loading && !(
|
404
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
405
|
+
using_limitable_reflections?(
|
406
|
+
construct_join_dependency(
|
407
|
+
select_association_list(joins_values).concat(
|
408
|
+
select_association_list(left_outer_joins_values)
|
409
|
+
), nil
|
410
|
+
).reflections
|
411
|
+
)
|
412
|
+
)
|
413
|
+
if has_limit_or_offset?
|
414
|
+
limited_ids = limited_ids_for(relation)
|
415
|
+
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
416
|
+
end
|
417
|
+
relation.limit_value = relation.offset_value = nil
|
418
|
+
end
|
382
419
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
limited_ids = limited_ids_for(relation)
|
388
|
-
limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
|
420
|
+
if block_given?
|
421
|
+
yield relation, join_dependency
|
422
|
+
else
|
423
|
+
relation
|
389
424
|
end
|
390
|
-
relation.except(:limit, :offset)
|
391
425
|
end
|
392
|
-
end
|
393
426
|
|
394
|
-
|
395
|
-
|
396
|
-
|
427
|
+
def limited_ids_for(relation)
|
428
|
+
values = @klass.connection.columns_for_distinct(
|
429
|
+
connection.visitor.compile(table[primary_key]),
|
430
|
+
relation.order_values
|
431
|
+
)
|
397
432
|
|
398
|
-
|
399
|
-
arel = relation.arel
|
433
|
+
relation = relation.except(:select).select(values).distinct!
|
400
434
|
|
401
|
-
|
402
|
-
|
403
|
-
|
435
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
+
id_rows.map(&:last)
|
437
|
+
end
|
404
438
|
|
405
|
-
|
406
|
-
|
407
|
-
|
439
|
+
def using_limitable_reflections?(reflections)
|
440
|
+
reflections.none?(&:collection?)
|
441
|
+
end
|
408
442
|
|
409
|
-
|
443
|
+
def find_with_ids(*ids)
|
444
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
410
445
|
|
411
|
-
|
412
|
-
|
446
|
+
expects_array = ids.first.kind_of?(Array)
|
447
|
+
return [] if expects_array && ids.first.empty?
|
413
448
|
|
414
|
-
|
415
|
-
return ids.first if expects_array && ids.first.empty?
|
449
|
+
ids = ids.flatten.compact.uniq
|
416
450
|
|
417
|
-
|
451
|
+
model_name = @klass.name
|
418
452
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
453
|
+
case ids.size
|
454
|
+
when 0
|
455
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
456
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
457
|
+
when 1
|
458
|
+
result = find_one(ids.first)
|
459
|
+
expects_array ? [ result ] : result
|
460
|
+
else
|
461
|
+
find_some(ids)
|
462
|
+
end
|
427
463
|
end
|
428
|
-
rescue RangeError
|
429
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
430
|
-
end
|
431
464
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
465
|
+
def find_one(id)
|
466
|
+
if ActiveRecord::Base === id
|
467
|
+
raise ArgumentError, <<-MSG.squish
|
468
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
469
|
+
Please pass the id of the object by calling `.id`.
|
470
|
+
MSG
|
471
|
+
end
|
472
|
+
|
473
|
+
relation = where(primary_key => id)
|
474
|
+
record = relation.take
|
475
|
+
|
476
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
477
|
+
|
478
|
+
record
|
439
479
|
end
|
440
480
|
|
441
|
-
|
442
|
-
|
481
|
+
def find_some(ids)
|
482
|
+
return find_some_ordered(ids) unless order_values.present?
|
443
483
|
|
444
|
-
|
484
|
+
result = where(primary_key => ids).to_a
|
445
485
|
|
446
|
-
|
447
|
-
|
486
|
+
expected_size =
|
487
|
+
if limit_value && ids.size > limit_value
|
488
|
+
limit_value
|
489
|
+
else
|
490
|
+
ids.size
|
491
|
+
end
|
448
492
|
|
449
|
-
|
450
|
-
|
493
|
+
# 11 ids with limit 3, offset 9 should give 2 results.
|
494
|
+
if offset_value && (ids.size - offset_value < expected_size)
|
495
|
+
expected_size = ids.size - offset_value
|
496
|
+
end
|
451
497
|
|
452
|
-
|
453
|
-
|
454
|
-
limit_value
|
498
|
+
if result.size == expected_size
|
499
|
+
result
|
455
500
|
else
|
456
|
-
ids.size
|
501
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
457
502
|
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def find_some_ordered(ids)
|
506
|
+
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
507
|
+
|
508
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
458
509
|
|
459
|
-
|
460
|
-
|
461
|
-
|
510
|
+
if result.size == ids.size
|
511
|
+
pk_type = @klass.type_for_attribute(primary_key)
|
512
|
+
|
513
|
+
records_by_id = result.index_by(&:id)
|
514
|
+
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
515
|
+
else
|
516
|
+
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
|
+
end
|
462
518
|
end
|
463
519
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
520
|
+
def find_take
|
521
|
+
if loaded?
|
522
|
+
records.first
|
523
|
+
else
|
524
|
+
@take ||= limit(1).records.first
|
525
|
+
end
|
468
526
|
end
|
469
|
-
end
|
470
527
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
528
|
+
def find_take_with_limit(limit)
|
529
|
+
if loaded?
|
530
|
+
records.take(limit)
|
531
|
+
else
|
532
|
+
limit(limit).to_a
|
533
|
+
end
|
476
534
|
end
|
477
|
-
end
|
478
535
|
|
479
|
-
|
480
|
-
|
481
|
-
@
|
482
|
-
else
|
483
|
-
offset += index
|
484
|
-
@offsets[offset] ||= find_nth_with_limit(offset, 1).first
|
536
|
+
def find_nth(index)
|
537
|
+
@offsets ||= {}
|
538
|
+
@offsets[index] ||= find_nth_with_limit(index, 1).first
|
485
539
|
end
|
486
|
-
end
|
487
540
|
|
488
|
-
|
489
|
-
|
490
|
-
|
541
|
+
def find_nth_with_limit(index, limit)
|
542
|
+
if loaded?
|
543
|
+
records[index, limit] || []
|
544
|
+
else
|
545
|
+
relation = ordered_relation
|
491
546
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
else
|
496
|
-
self
|
497
|
-
end
|
547
|
+
if limit_value
|
548
|
+
limit = [limit_value - index, limit].min
|
549
|
+
end
|
498
550
|
|
499
|
-
|
500
|
-
|
501
|
-
|
551
|
+
if limit > 0
|
552
|
+
relation = relation.offset((offset_value || 0) + index) unless index.zero?
|
553
|
+
relation.limit(limit).to_a
|
554
|
+
else
|
555
|
+
[]
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
502
559
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
560
|
+
def find_nth_from_last(index)
|
561
|
+
if loaded?
|
562
|
+
records[-index]
|
563
|
+
else
|
564
|
+
relation = ordered_relation
|
565
|
+
|
566
|
+
if equal?(relation) || has_limit_or_offset?
|
567
|
+
relation.records[-index]
|
510
568
|
else
|
511
|
-
|
569
|
+
relation.last(index)[-index]
|
512
570
|
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def find_last(limit)
|
575
|
+
limit ? records.last(limit) : records.last
|
576
|
+
end
|
577
|
+
|
578
|
+
def ordered_relation
|
579
|
+
if order_values.empty? && (implicit_order_column || primary_key)
|
580
|
+
if implicit_order_column && primary_key && implicit_order_column != primary_key
|
581
|
+
order(table[implicit_order_column].asc, table[primary_key].asc)
|
582
|
+
else
|
583
|
+
order(table[implicit_order_column || primary_key].asc)
|
584
|
+
end
|
585
|
+
else
|
586
|
+
self
|
587
|
+
end
|
513
588
|
end
|
514
|
-
end
|
515
589
|
end
|
516
590
|
end
|